使用 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
羽毛球分组比赛记分
小程序二维码

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

小夜