This repository has been archived on 2026-10-02. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
NeteaseUrl/pyproject.toml
T
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

93 lines
3.3 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
[project]
name = "yunmusic-assistant"
version = "3.0.0"
description = "云村小助手 · 网易云音乐解析/下载服务(FastAPI + asyncio + aiohttp)"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115,<1.0",
"uvicorn[standard]>=0.30,<1.0",
"aiohttp>=3.10,<4.0",
"aiosqlite>=0.20,<1.0",
"aiofiles>=24.1",
"itsdangerous>=2.2,<3.0",
"cryptography>=50.0,<51.0",
"qrcode>=7.0,<8.3",
"python-multipart>=0.0.9",
"jinja2>=3.1,<4.0",
]
[dependency-groups]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.24",
"ruff>=0.6",
"pyright>=1.1.390",
"httpx>=0.27",
]
# 应用工程(非库):不把自身装进环境,避免 uv 扫描顶层模块
[tool.uv]
package = false
# ============ Ruff:静态检查 + 导入排序 + 格式化 ============
[tool.ruff]
target-version = "py312"
line-length = 120
extend-exclude = [".venv", ".zcode", "templates", "static", "data"]
[tool.ruff.lint]
# E/F 基础错误、I 导入排序、B bugbear、UP 升级、C4 推导式、ASYNC 异步陷阱、S 安全、RUF
select = ["E", "F", "W", "I", "B", "UP", "C4", "ASYNC", "S", "RUF"]
ignore = [
"E501", # 行宽交给 formatter,不强制
"S101", # 生产代码外的 assert(测试/断言脚本)
"S104", # 绑定 0.0.0.0(服务端有意为之)
"S110", # try/except/pass(本项目「失败静默降级」策略)
"S112", # try/except/continue
"S324", # hashlib.md5 用于非安全场景(上游签名口径)
"S603", "S607", # subprocess(打包/运维脚本)
"UP009", # 保留 `# -*- coding: utf-8 -*-` 文件头(全项目既有约定)
"RUF001", "RUF002", "RUF003", # 全角字符(中文注释/文案,误报)
# ---- 以下为「有意保留」,已被逐条论证为协议/设计约束,非待修缺陷 ----
"RUF012", # 常量类可变默认值:APIConstants/PodcastConstants 是常量表,非实例状态
"S305", # AES-ECB:网易云 weapi 协议**要求**的加密模式,非可自由选择
"S311", # randrange:生成上游 requestId(协议随机数),非安全用途
"ASYNC250", # input():qr_login 交互式 CLI 的人类输入,异步化无意义
"S310", # urllib:仅用于音频 Range 代理的 URL 校验路径
]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S", "ASYNC"]
".zcode/**" = ["S", "ASYNC", "F"]
# ASYNC109:timeout 参数是有意 API——直接转发给 aiohttp 的 ClientTimeout,
# 不是「用 sleep 当超时」的反模式。
"core/http_client.py" = ["ASYNC109"]
"core/aiohttp_compat.py" = ["ASYNC109"]
[tool.ruff.lint.isort]
known-first-party = ["core", "web", "services", "music_api", "auth_system"]
[tool.ruff.format]
quote-style = "preserve"
# ============ Pyright:类型检查 ============
[tool.pyright]
# 全量纳入(Flask 巨石删除后不再有例外清单)
include = ["core", "web", "services"]
exclude = [".venv", ".zcode", "data", "downloads", "templates", "static"]
venvPath = "."
venv = ".venv"
pythonVersion = "3.12"
typeCheckingMode = "basic"
reportMissingImports = true
reportOptionalMemberAccess = "warning"
reportAttributeAccessIssue = "warning"
reportGeneralTypeIssues = "warning"
# ============ Pytest ============
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
addopts = "-q"