使用 modern-python Skill 为 Python 项目配置 uv、ruff 与 ty

前言

Python 项目里常见的一套工具链是这样的:pip 装依赖,virtualenv 管环境,flake8 做检查,black 做格式化,isort 排 import,mypy 做类型检查,pre-commit 再把这些钩到 Git 上。配置往往散落在 requirements.txtsetup.py.flake8mypy.ini 里,Agent 写代码时还经常随手执行 pip install,或者手动 source .venv/bin/activate

Astral 这一侧已经把包管理、检查、格式化收成了 uvruff,类型检查也有同门的 ty。问题是:人可以按文档慢慢迁,Agent 默认仍可能沿用旧命令。Trail of Bits 把内部模板 cookiecutter-python 里的选择,写成了 Agent Skill modern-python,用来约束新项目怎么建、旧项目怎么迁、单文件脚本怎么声明依赖。

这是什么

modern-python 是 Trail of Bits 在 trailofbits/skills 市场里发布的一条 Skill,插件作者署名为 William Tan。官方描述是:用 uvruffty 配置 Python 项目;在创建项目、写带依赖的独立脚本,或从 pip / Poetry / mypy / black 迁移时使用。

它基于通用的 SKILL.md 格式,因此在 Claude Code、Codex CLI、Cursor 这类支持 Agent Skill 的工具里都可以加载。仓库把它归在 Development 一类,和安全审计类 Skill 放在同一个 marketplace 里。实践规范来自 Trail of Bits 自己的 cookiecutter 模板,不是另一套平行标准。

Skill 明确写了不适用的情况:用户要求保留旧工具链时不要强行替换;需要 Python 3.11 以下时不要用这套工具;Python 不是主语言的混合仓库也不要套上去。

核心工具

Skill 把推荐工具和被替换的旧工具列成了一张表,交叉对照 GitHub 上的 SKILL.md 与官方文档后,内容一致:

工具 作用 替换对象
uv 包与依赖管理 pip、virtualenv、pip-tools、pipx、pyenv
ruff 检查和格式化 flake8、black、isort、pyupgrade、pydocstyle
ty 类型检查 mypy、pyright
pytest 测试与覆盖率 unittest
prek Git hooks pre-commit

ty 来自 Astral(与 uvruff 同一团队)。Astral 官方文档把它定位为用 Rust 写的类型检查器,当前仍处于 beta,Skill 仍推荐用它替代 mypy / pyright。实际落地时要把这点算进风险:规则和诊断在小版本之间仍可能变。

prekj178/prek,Rust 实现、单二进制、兼容已有的 .pre-commit-config.yaml。Skill 把它写成比 pre-commit 更快、且不依赖 Python 运行时的替代。

除开发工具外,Skill 还附带一组安全相关能力,主要跑在 pre-commit 或 CI 里:

工具 作用 运行时机
shellcheck Shell 脚本检查 pre-commit
detect-secrets 密钥检测 pre-commit
actionlint GitHub Actions 语法校验 pre-commit、CI
zizmor Workflow 安全审计 pre-commit、CI
pip-audit 依赖漏洞扫描 CI、手工
Dependabot 依赖自动更新 定时

作为 Claude Code 插件安装时,仓库还带了一个 SessionStart hook:给 pythonpippipxuv 加上 PATH shim。Agent 直接跑 pythonpip install 会被拦截,并提示改成 uv run / uv add 这类命令。grep pythonwhich python 不受影响,因为这时 python 只是参数,不是被执行的命令。只把 SKILL.md 拷进 Skill 目录时,不一定带上这个 hook,以实际安装方式为准。

几条硬性约定

Skill 把常见反模式写成了对照表,写作时代理应优先按「右侧」执行:

不要这样做 改用
[tool.ty] 里写 python-version [tool.ty.environment] 下的 python-version
uv pip install uv adduv 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。

安装与启用

Claude Code

官方 marketplace 安装分两步。先加入 Trail of Bits 的插件市场:

/plugin marketplace add trailofbits/skills

再安装 modern-python 插件:

/plugin install trailofbits/skills/plugins/modern-python

也可以先执行 /plugin menu 浏览后再装。官方 Quick Start 里给出的调用示例是:

Use the modern-python skill to create a new Python project with uv, ruff, and pytest

Codex CLI

仓库 README 写明 Codex 可以直接加载 Claude 的 marketplace,不需要额外的 sidecar 元数据:

codex plugin marketplace add trailofbits/skills
codex plugin list
codex plugin add modern-python@trailofbits

最后一条里的插件名与仓库中 plugins/modern-python 目录名一致。

通用 Skill 安装(Cursor 等)

skills.sh 上的安装命令是:

npx skills add https://github.com/trailofbits/skills --skill modern-python

这条命令按 Agent Skills 的通用目录约定把 SKILL.md 装进当前工具使用的 skills 路径。装好后,直接描述任务即可,例如「按 modern-python 给这个仓库配 uv 和 ruff」,或「把现有 pip + requirements.txt 迁到 uv」。

典型用法

Skill 用一棵决策树区分四类工作:单文件脚本走 PEP 723;不打算分发的多文件项目走最小 uv 配置;可复用的包走完整项目配置;已有仓库走迁移指南。

1. 最小项目

不打算发布到 PyPI 的多文件项目,官方 Quick Start 如下:

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 .

依赖进 pyproject.tomluv.lock,一次性试用某个包则用 uv run --with,不要写进项目依赖:

uv run --with requests python -c "import requests; print(requests.get('https://httpbin.org/ip').json())"
uv run --with httpx pytest

2. 完整包项目

从零开始时,Skill 会先问是否用 Trail of Bits 的 cookiecutter 一次生成完整脚手架(含 pyproject.tomlsrc/ 布局、依赖组、hooks、GitHub Actions 和安全扫描):

uvx cookiecutter gh:trailofbits/cookiecutter-python

不用模板时,用 uv 创建可分发的包:

uv init --package myproject
cd myproject

生成的目录结构是:

myproject/
├── pyproject.toml
├── README.md
├── src/
│   └── myproject/
│       └── __init__.py
└── .python-version

SKILL.md 里给出的关键配置如下。依赖组不要手工改,用 uv add --group 维护:

[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"

安装依赖:

uv sync --all-groups
# 或只装某一组
uv sync --group dev

Skill 还建议在仓库里放一个 Makefile,把日常命令收口到 uv run

.PHONY: dev lint format test build

dev:
    uv sync --all-groups

lint:
    uv run ruff format --check && uv run ruff check && uv run ty check src/

format:
    uv run ruff format .

test:
    uv run pytest

build:
    uv build

3. 单文件脚本:PEP 723

只有一个文件、但又需要第三方库时,不要再配一份 requirements.txt。Skill 的参考文档要求把元数据写进脚本注释,用 uv run 执行:

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
#     "requests",
#     "rich",
# ]
# ///

import requests
from rich import print

response = requests.get("https://httpbin.org/ip")
print(response.json())
uv run script.py

也可以用 uv 维护脚本依赖:

uv init --script myscript.py
uv add --script myscript.py requests
uv remove --script myscript.py requests

官方参考也写了限制:PEP 723 没有 dependency groups、不能 editable install、没有 lockfile,多次运行时解析到的版本可能不同。需要这些能力时改用完整的 pyproject.toml

4. 从旧工具链迁移

用户明确要求迁移时,Skill 才走这条路径;用户要留 pip / Poetry / mypy 时,文档要求尊重现有流程。

requirements.txt + pip 迁到 uv:

uv init --bare

# 逐个添加,不要直接改 pyproject.toml
uv add requests rich

# 或从 requirements.txt 导入(复杂版本约束可能要手工处理)
grep -v '^#' requirements.txt | grep -v '^-' | grep -v '^\s*$' | while read -r pkg; do
    uv add "$pkg" || echo "Failed to add: $pkg"
done

uv sync

随后删除 requirements.txtrequirements-dev.txt 和旧虚拟环境(venv/.venv/),并把 uv.lock 纳入版本控制。

setup.py / setup.cfg 迁移时:先 uv init --bare,把 install_requiresuv add 搬进去,开发依赖用 uv add --group dev,再把名称、版本、描述等元数据拷到 [project],最后删除 setup.pysetup.cfgMANIFEST.in

从 flake8 + black + isort 迁到 ruff:

uv remove flake8 black isort
# 删除 .flake8,以及 pyproject.toml 里的 [tool.black]、[tool.isort]
uv add --group dev ruff
uv run ruff format .
uv run ruff check --fix .

从 mypy / pyright 迁到 ty:

uv remove mypy pyright
# 删除 mypy.ini、pyrightconfig.json,以及 [tool.mypy] / [tool.pyright]
uv add --group dev ty
uv run ty check src/

描述里提到可以从 Poetry 迁到 uv,但 SKILL.md 的迁移章节没有单独列出 Poetry 的逐步命令,只在反模式表里把 Poetry 标成应替换为 uv。遇到 Poetry 项目时,应按仓库里的 references/migration-checklist.md 核对,不要把 pip 那套步骤直接套上去。

适用场景与注意事项

适合用这条 Skill 的情况包括:新建 Python 包或内部项目;给已有仓库补 pyproject.toml、lint、测试;写带第三方依赖的单文件脚本;用户明确要求从 pip / flake8 / black / mypy 迁走。

不适合的情况文档写得很直接:必须支持 Python 3.11 以下;用户明确要留 Poetry、mypy、black;Python 只是仓库里的配角。

使用时还有几处需要留意:

  1. 最低版本是 3.11。 requires-python = ">=3.11" 和 ruff 的 target-version = "py311" 是配套的,不能只改其中一个。
  2. ty 仍是 beta。 Skill 把它当作默认类型检查器,但 Astral 自己说明 API 与诊断都还不稳定。对类型检查结果很敏感的仓库,迁移前要先在分支上跑一遍 uv run ty check src/,看误报是否可接受。
  3. 覆盖率门槛默认 80%。 旧项目第一次接 pytest-cov 时,这个数字很容易把 CI 打红,需要按仓库现状调整,而不是原样粘贴。
  4. ruffselect = ["ALL"] 很严。 官方配置用 ignore 关掉了 D(pydocstyle)、COM812ISC001,其余规则都开。接到老代码上会有大量告警,需要按模块逐步收紧,而不是指望一次 --fix 全部干净。
  5. 插件 hook 只在插件安装路径下生效。 Claude Code / Codex 按 marketplace 安装时会拦截裸 python/pip;仅同步 SKILL.md 时,Agent 仍可能写出旧命令,提示词里最好写明「不要用 pip,用 uv add / uv run」。
  6. 参考文档比 SKILL.md 更细。 同目录下还有 pyproject.mduv-commands.mdruff-config.mdtesting.mdpep723-scripts.mdprek.mdsecurity-setup.mddependabot.mdmigration-checklist.md。做完整迁移或安全扫描时,应让 Agent 继续读这些文件,而不是只靠 SKILL 正文里的摘要。

小结

modern-python 做的事情很具体:把 Trail of Bits cookiecutter 模板里已经在用的工具链(uv、ruff、ty、pytest、prek)写成 Agent 可执行的规范,并附带从 pip / setup.py / flake8 / mypy 迁过来的步骤。它解决的不是「Python 该不该现代化」,而是 Agent 默认仍会 pip install、手工改 pyproject.toml、激活虚拟环境这一类操作。

官方地址:

  • Skill 目录:https://github.com/trailofbits/skills/tree/main/plugins/modern-python/skills/modern-python
  • 插件说明:https://github.com/trailofbits/skills/tree/main/plugins/modern-python
  • 文档站:https://trailofbits-skills.mintlify.app/plugins/modern-python
  • skills.sh:https://skills.sh/trailofbits/skills/modern-python
  • 模板仓库:https://github.com/trailofbits/cookiecutter-python
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜