Astral 的三件套在 2026 年已经不只是"更快的替代品":uv 管包与项目、Ruff 管 lint 与格式化、ty 管类型检查,覆盖了 pip、virtualenv、pip-tools、pipx、pyenv、flake8、Black、isort、mypy、Pyright 的位置。ty 在 2025-12-16 发布公告后仍是 Beta;Astral 在 2026-03-19 宣布已达成协议加入 OpenAI 的 Codex 团队。
Trail of Bits 把这套迁移规则写成了一个可被 Claude Code / Codex 加载的 Skill:plugins/modern-python/skills/modern-python/SKILL.md,底层来自其内部模板 cookiecutter-python。下面是这套规则里的实际配置、迁移路径,以及它明确点名的反模式。
工具映射:谁替代谁
| 工具 | 用途 | 替代 |
|---|---|---|
| uv | 包/依赖管理 | pip, virtualenv, pip-tools, pipx, pyenv |
| ruff | lint + 格式化 | flake8, black, isort, pyupgrade, pydocstyle |
| ty | 类型检查 | mypy, pyright |
| pytest | 测试与覆盖率 | unittest |
| prek | pre-commit 钩子(Rust 原生,更快,无需 Python 运行时) | pre-commit |
安全工具另有:shellcheck、detect-secrets、actionlint、zizmor、pip-audit、Dependabot。
反模式:写了就会被工具链绕开
| Avoid | Use Instead |
|---|---|
[tool.ty] 里的 python-version | [tool.ty.environment] 下的 python-version |
uv pip install | uv add / uv sync |
手工编辑 pyproject.toml 加依赖 | `uv add |
/uv remove | |
| ` | |
| hatchling 作为 build backend | uv_build(更简单,多数项目够用) |
| Poetry | uv |
requirements.txt | 脚本用 PEP 723,项目用 pyproject.toml |
| mypy / pyright | ty |
用 [project.optional-dependencies] 放开发工具 | [dependency-groups](PEP 735) |
手工 source .venv/bin/activate | uv run |
| pre-commit | prek |
三条原则贯穿上面所有条目:依赖只通过 uv add / uv remove 管理;不要手工激活或管理虚拟环境,所有命令走 uv run;开发/测试/文档依赖放进 [dependency-groups],不要放进给用户安装的 extras。
决策树
- 单文件带依赖脚本 → PEP 723 内联元数据
- 不分发的多文件项目 → 最小 uv 配置
- 可复用包 → 完整项目配置
- 已有仓库 → 迁移指南
最小项目
uv init myproject && cd myproject
uv add requests rich
uv add --group dev pytest ruff ty
uv run python src/myproject/main.py
uv run pytest
uv run ruff check .
完整项目配置
[project]
name = "myproject"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = []
[dependency-groups]
dev = [
{ include-group = "lint" },
{ include-group = "test" },
{ include-group = "audit" },
]
lint = ["ruff", "ty"]
test = ["pytest", "pytest-cov"]
audit = ["pip-audit"]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["ALL"]
ignore = ["D", "COM812", "ISC001"]
[tool.pytest]
addopts = ["--cov=myproject", "--cov-fail-under=80"]
[tool.ty.terminal]
error-on-warning = true
[tool.ty.environment]
python-version = "3.11"
[tool.ty.rules]
possibly-unresolved-reference = "error"
unused-ignore-comment = "warn"
requires-python = ">=3.11" 与 ruff 的 target-version = "py311" 必须配套,只改一个会在工具链里留下不一致的版本视图。
配套 Makefile:
lint:
uv run ruff format --check && uv run ruff check && uv run ty check src/
test:
uv run pytest
迁移路径
从 requirements.txt + pip
脚本转 PEP 723;项目先 uv init --bare,再用 uv add 逐个加依赖,然后删掉 requirements.txt、requirements-dev.txt、venv/.venv,把 uv.lock 纳入版本控制。
从 setup.py / setup.cfg
uv init --bare → uv add 搬 install_requires → uv add --group dev 放开发依赖 → 把 name/version/description 等元数据拷到 [project] → 删 setup.py、setup.cfg、MANIFEST.in。
从 flake8 + black + isort
uv remove 掉它们,删 .flake8、[tool.black]、[tool.isort] 配置,uv add --group dev ruff,跑 uv run ruff check --fix . 与 uv run ruff format .。
从 mypy / pyright
uv remove,删 mypy.ini/pyrightconfig.json/[tool.mypy]/[tool.pyright],uv add --group dev ty,跑 uv run ty check src/。
uv 常用命令
uv init / uv init --package / uv add / uv add --group dev / uv remove / uv sync / uv sync --all-groups / uv run / uv run --with / uv build / uv publish。--with 用于一次性临时依赖,例如:
uv run --with requests python -c "..."
边界
ty 仍是 beta,官方建议有经验的用户在生产试用。对类型检查敏感的仓库,迁移前先在分支上跑 uv run ty check src/,确认误报是否可接受;规则与诊断在小版本之间仍可能变化。最低 Python 版本为 3.11。想直接生成预配置好的骨架:
uvx cookiecutter gh:trailofbits/cookiecutter-python
项目信息
- uv:github.com/astral-sh/uv ,文档 docs.astral.sh/uv
- ruff:github.com/astral-sh/ruff
- ty:github.com/astral-sh/ty ,文档 docs.astral.sh/ty(约 19.7k stars,MIT,Beta)
- modern-python Skill:github.com/trailofbits/skills(路径
plugins/modern-python/skills/modern-python/SKILL.md,CC-BY-SA-4.0) - 模板:github.com/trailofbits/cookiecutter-python