snowy-yang
|
838d635bc5
|
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,未被写入。
|
2026-09-26 11:52:06 +08:00 |
|
snowy-yang
|
8446166120
|
refactor!: uv 管理环境 + 彻底删除技术债(Flask 与 requests 全部移除)
## uv 环境管理
- pyproject.toml 声明 dependencies + [dependency-groups].dev,uv.lock 精确锁定
- 删除 requirements.txt / requirements-fastapi.txt / requirements-dev.txt
- .python-version = 3.12;Dockerfile 改用 uv sync --frozen(可复现构建)
- 新增 jinja2(首页渲染)
## 删除 Flask 技术债
- 从 main.py 用 ast 精确剥离 56 个 Flask 节点(路由/中间件/错误处理/启动),
框架无关的服务层落为 services/runtime.py(MusicAPIService、下载/打包 worker、
任务监控、缓存清扫),零 Flask 依赖
- 删除 main.py(4527 行)与 auth_routes.py(1050 行)
- auth_system.py 移除会话/请求上下文层(login_session/current_user/login_required/
admin_required/_client_ip 等),保留数据与业务层
- 新增 core/net.py(IP 解析)、web/auth_state.py(登录锁定/2FA 票据/发码限流)
- FastAPI 侧改直接依赖 services.runtime,不再 import main
- web/app.py 去掉 Flask fallback;入口默认根路径模式(API_PREFIX 可选)
## 删除 requests 技术债
- 新增 core/sync_http.py:requests 风格的同步门面(底层 aiohttp 连接池,
流式读取经有界队列背压),含 Session/headers/(connect,read) 元组超时兼容
- core/utils、auth_system、podcast_api、music_downloader、services 全部切换
- 实测真实下载 5.2MB 音频完整成功
## 质量门禁归零
- ruff:0 错误(B904 全部修复,不再忽略)
- pyright:0 错误(类型收窄修复)
- pytest:140/140(含 golden 契约回归、root 模式 66 项路径覆盖)
- 真实 uvicorn 启动:/health、/、/static、受保护端鉴权全部正确
新增 tests/golden/responses.json:删除 Flask 前捕获的 32 例响应快照,
FastAPI 逐字段复现——删除巨石后行为回归仍有硬证据。
|
2026-09-26 11:10:17 +08:00 |
|
snowy-yang
|
9df0028195
|
feat(routes): 迁移下载/批量打包/播客下载(账本事务)+ 修密钥绑定缺陷
迁移端点:
- POST /api/v1/download(单曲:file 后台任务 / json 同步交付+结算)
- POST /api/v1/download/batch_zip(按去重歌曲数计费)
- POST /api/v1/podcast/download、/podcast/download/batch_zip
- 新增 web/billing.py(预扣+开账同事务 / 只退 open 行 / rename 承接)
与 web/tasks_registry.py(任务登记/容量闸/账本撞名重试,与 main 同口径)
- worker 仍复用 main 既有实现(无 flask 依赖),账本与交付语义不变
修复我引入的真实缺陷:
- download 参数校验分支(ID/音质/格式非法)漏退款 → 预扣泄漏。改为统一 _fail() 退款
- web/routers/{auth,register}.py 在导入期绑定 deps.secret_key,导致 patch web.deps.secret_key
无效、且测试顺序相关。改为调用期 deps.secret_key() 解析
测试:tests/test_download_billing.py 7 项沙箱用例如实断言账本守恒
(预扣必退、无 open 行残留、次数不足不建任务);
全套 pytest 69/69(顺序无关);ruff All checks passed;pyright 0 errors;奇偶 36/36。
|
2026-09-26 10:13:16 +08:00 |
|