Archived
fix: 修复重构遗留缺陷,补齐 pyright 检查盲区
上一次重构(8446166)声称「pyright 0 错误」,但 pyproject 里 pyright 的 include 只覆盖 core/web/services —— 根目录 6 个应用模块与整个 tests/ 从未被检查,而 requests→sync_http 迁移的遗留恰好全部藏在那里。补齐 include 后立刻暴露 7 errors + 9 warnings,其中数处在运行时静默失效。 修复: - services/runtime.py:删除 _podcast_billing_count/_billing_ids_count 两个 无调用方的死函数。它们仍调用 api_service._safe_get_request_data(),而该方法 在剥离 Flask 时已被删除,异常又被 except 吞掉 —— 一旦被调用,播客/歌单计费 恒为 1 次且不报任何错。路由层已各自实现同口径版本,故整体删除。 - web/routers/admin_site.py:备份上传的类型判定必须用 starlette 的 UploadFile。 fastapi.UploadFile 是它的子类,而 request.form() 返回基类实例,用错会让 isinstance 恒为 False,把每一次真实上传都判成「请选择数据库文件」。 已补 4 例真实 multipart 回归测试,并用变异测试确认能抓住该缺陷。 - auth_system.py:修正 create_user(实返 sqlite3.Row|None)与 list_cards (实返 (cards,total) 元组)与实现不符的返回注解;注解一改正,立刻暴露出被它 掩盖的 register.py 中 int(user['id']) 未做 None 检查的 500 崩溃路径,已补守卫。 - music_downloader.py:修正注解引用的 core.sync_http.Response(正确名应为 SyncResponse);封面缓存淘汰不再读类型为 Optional 的 deque.maxlen,改用命名常量。 - services/runtime.py:zip worker 的 result.music_info 可能为 None,原样使用会 炸掉整批任务,改为按单曲失败处理。 - music_api.py:三处 isinstance 三元表达式收敛为 _as_dict() 帮助函数。 - web/main.py:文档串移除已删除的 Flask 兜底描述,补充 data/ 相对 CWD 解析的提醒。 验证:ruff check 通过;pyright 0 errors / 0 warnings(filesAnalyzed=67); pytest 144 passed;真实 uvicorn 启动冒烟通过(/health、/、静态资源 200, 未鉴权管理端点 403)。生产库仅做只读 integrity_check,未被写入。
This commit is contained in:
1 parent
8446166120
commit
838d635bc5
14 files changed
+152
-78
No files matched your search
+6
-59
@@ -723,39 +723,6 @@ _QUIET_LOG_PATHS = {'/api/queue', '/api/batch_progress', '/api/task/heartbeat',
|
||||
'/audio_stream', '/api/fe_error'}
|
||||
|
||||
|
||||
def _podcast_billing_count() -> int:
|
||||
"""播客打包计费:指定单集列表按数量扣;整台电台提交时先扣 1 次,
|
||||
worker 解析完实际单集数后补扣差额(一首单集 = 1 次)
|
||||
F22:与路由完全同口径——ids 模式先做与路由一致的 limit 截断,避免多扣"""
|
||||
try:
|
||||
data = api_service._safe_get_request_data()
|
||||
if data.get('radio_id'):
|
||||
return 1
|
||||
try:
|
||||
limit = int(data.get('limit', 200) or 200)
|
||||
except (TypeError, ValueError):
|
||||
limit = 200
|
||||
limit = max(1, min(limit, 500))
|
||||
raw = data.get('ids')
|
||||
if isinstance(raw, str):
|
||||
raw_list = raw.split(',')
|
||||
else:
|
||||
raw_list = list(raw or [])
|
||||
# 与路由完全同口径(提取→去重):URL 形式与纯数字形式的同一单集不再重复计费
|
||||
ids, seen = [], set()
|
||||
for x in raw_list:
|
||||
try:
|
||||
mid = api_service._extract_music_id(x)
|
||||
except Exception:
|
||||
mid = str(x).strip()
|
||||
if mid and mid not in seen:
|
||||
seen.add(mid)
|
||||
ids.append(mid)
|
||||
return max(1, min(len(ids), limit))
|
||||
except Exception:
|
||||
return 1
|
||||
|
||||
|
||||
def _podcast_safe_name(s: str, fallback: str = 'unknown') -> str:
|
||||
"""文件名安全化(去除非法字符)"""
|
||||
s = ''.join(c for c in str(s or '') if c not in r'<>:"/\|?*' and ord(c) >= 32).strip()
|
||||
@@ -910,32 +877,6 @@ def _user_client() -> QRLoginClient:
|
||||
return QRLoginClient(USER_COOKIE_FILE)
|
||||
|
||||
|
||||
def _billing_ids_count() -> int:
|
||||
"""按次计费:解析请求中的 ids 数量(一首歌 = 1 次;100 首歌单打包 = 100 次)
|
||||
F23:与路由的清洗规则完全一致(提取→去重),预扣数=实际执行数,重复 ID 不多扣"""
|
||||
try:
|
||||
data = api_service._safe_get_request_data()
|
||||
raw = data.get('ids')
|
||||
if isinstance(raw, str):
|
||||
raw_list = raw.split(',')
|
||||
else:
|
||||
raw_list = list(raw or [])
|
||||
ids, seen = [], set()
|
||||
for x in raw_list:
|
||||
try:
|
||||
mid = api_service._extract_music_id(x)
|
||||
except Exception:
|
||||
mid = str(x).strip()
|
||||
if mid and mid not in seen:
|
||||
seen.add(mid)
|
||||
ids.append(mid)
|
||||
# 与路由同口径:单任务上限 500(超出部分路由会 400 拒绝并退款,
|
||||
# 预扣数先封顶可让"请分批提交"提示优先于"次数不足")
|
||||
return max(1, min(len(ids), 500))
|
||||
except Exception:
|
||||
return 1
|
||||
|
||||
|
||||
def _settle_batch_billing(task_id: str, ok_count: int, final_status: str = 'settled') -> int:
|
||||
"""批量任务结算(F25/F26:走持久账本,按实际预扣-实际交付幂等退款;
|
||||
重复调用/重启后调用都只会退一次)"""
|
||||
@@ -1114,6 +1055,12 @@ def _batch_zip_worker(task_id: str) -> None:
|
||||
_update_progress()
|
||||
continue
|
||||
mi = result.music_info
|
||||
if mi is None:
|
||||
# 与上面 fp.exists() 同口径:成功但缺元信息(上游详情缺失)
|
||||
# 按单曲失败计,不让 mi.name 抛 AttributeError 把整批转 error
|
||||
failed.append(str(mid))
|
||||
_update_progress()
|
||||
continue
|
||||
base = _build_download_base(filename_format, {'name': mi.name, 'artist_string': mi.artists})
|
||||
# 同名去重:歌单里同一首歌出现两次/同名不同版本时,
|
||||
# 追加序号避免 ZIP 内重名互相覆盖(用户被扣 2 次只拿到 1 首)
|
||||
|
||||
Reference in new issue
Block a user