编程 把 pip+black+mypy 换成 uv+ruff+ty:Trail of Bits 的 modern-python Skill 点名了 10 条反模式

2026-09-25 00:04:26

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
rufflint + 格式化flake8, black, isort, pyupgrade, pydocstyle
ty类型检查mypy, pyright
pytest测试与覆盖率unittest
prekpre-commit 钩子(Rust 原生,更快,无需 Python 运行时)pre-commit

安全工具另有:shellcheck、detect-secrets、actionlint、zizmor、pip-audit、Dependabot。

反模式:写了就会被工具链绕开

AvoidUse Instead
[tool.ty] 里的 python-version[tool.ty.environment] 下的 python-version
uv pip installuv add / uv sync
手工编辑 pyproject.toml 加依赖`uv add
/uv remove
`
hatchling 作为 build backenduv_build(更简单,多数项目够用)
Poetryuv
requirements.txt脚本用 PEP 723,项目用 pyproject.toml
mypy / pyrightty
用 [project.optional-dependencies] 放开发工具[dependency-groups](PEP 735)
手工 source .venv/bin/activateuv run
pre-commitprek

三条原则贯穿上面所有条目:依赖只通过 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

项目信息

推荐文章

程序员茄子在线接单