关于 python-lint
python-lint 指导 Python 包使用 Ruff 作为代码检查和格式化工具,涵盖全新配置、从 Black、Flake8 和 isort 迁移、规则调整及问题修复。
主要功能
- 01在 pyproject.toml 中显式配置 Ruff 规则
- 02固定 Ruff 版本并设置 Python 目标版本
- 03从 Black、Flake8 和 isort 迁移
- 04调整规则并限定例外范围
- 05修复并验证检查与格式问题
适用场景
- 01为新的 Python 包配置 Ruff
- 02替换旧有的检查与格式化工具链
- 03调整测试或脚本的检查规则
- 04处理代码检查与格式问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ paldom/ python-skills --skill python-lint安装后在 Claude Code 中输入/python-lint确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/migration.mdrule-selection.mdscripts/check_ruff_config.py详细介绍
python-lint
用途
将 Ruff 配置为 Python 包唯一的 Linter 和格式化工具,以取代
Black、Flake8(及其插件)、isort 和 pyupgrade;在
pyproject.toml 中明确指定规则集,然后运行 ruff check 和 ruff format --check,确保命令成功退出。
涵盖全新配置、从旧工具栈迁移、调整规则,以及修复 Lint 或
格式检查失败。以下所有命令均在用户的包仓库中运行。
不适用场景
- 类型错误 / mypy / pyright / ty — Ruff 不执行类型推断;
ANN规则只检查注解风格。如果已安装,python-typing 技能负责此项。 - 配置 pre-commit(
.pre-commit-config.yaml、固定钩子版本、运行暂存文件) — 使用 python-precommit 技能。本技能只定义 Ruff 应执行的操作。 - CI 工作流 YAML(GitHub Actions 作业、矩阵、缓存)— 使用 python-ci 技能。 本技能提供 CI 作业应运行的命令,不负责配置工作流。
- 格式化 YAML / JSON / TOML / Markdown 正文 — Ruff 仅格式化 Python (自 0.16 起也包括 Markdown 中的 Python 代码围栏),不处理其他内容; 这是维护者有意作出的决定 (astral-sh/ruff#10738); 非 Python 文件由 python-precommit 技能负责。
- 在 Agent 编辑时自动运行 Ruff(Claude Code 钩子)— 使用 agent-guardrails 技能。
工作流
1. 操作前先检查
ls .flake8 .isort.cfg setup.cfg tox.ini ruff.toml .ruff.toml 2>/dev/null
grep -nE '^\[tool\.(ruff|black|isort)|^\[flake8\]|^\[isort\]' pyproject.toml setup.cfg tox.ini 2>/dev/null
grep -n 'requires-python' pyproject.toml
选择路径:全新配置(步骤 2–3)、从 Black/Flake8/isort 迁移(步骤 5)、 调整现有配置(步骤 4),或修复未通过的 Lint 检查(步骤 6)。
2. 安装固定版本的 Ruff
uv add --dev "ruff==0.16.6" # example pin — check the latest release and pin that
# one-off, no project change:
uvx --from 'ruff==0.16.6' ruff check .
无 uv 时的备选方案(只需执行一次,适用于以下所有命令):运行 python -m pip install 'ruff==0.16.6',并省略 uv run 前缀。
固定版本的原因 — 格式化输出和规则目录会随次要版本更新而变化:
0.15 发布了“2026 风格指南”,改变了 lambda 和空行格式
(astral.sh/blog/ruff-v0.15.0);而 0.16
(2026-07-23)将默认规则集从 59 条扩展至 413 条,同时从中移除了 18 条
E/F 规则,因此未配置的仓库一夜之间就会出现不同的检查结果
(astral.sh/blog/ruff-v0.16.0)。不固定
Ruff 版本会导致本地、团队成员和 CI 的运行结果不一致,这是报告最多的 Lint 工作流
失败原因。也可以在 [tool.ruff] 下通过
required-version = "0.16.6" 在配置中强制固定版本。请注意,
uv format(自 uv 0.8.13 起为实验性功能)会运行其自身捆绑的 Ruff,因此版本可能
与项目固定的版本不同 — 请将 ruff 保留在开发依赖中作为权威版本,并将
uv format 视为便捷封装。
3. 编写配置(全新设置)
所有 Ruff 配置都放在 pyproject.toml 中。只保留一个配置文件——在 [tool.ruff] 节旁边再放一个
ruff.toml,只会让人困惑。起始配置:
[tool.ruff]
target-version = "py311" # lowest Python you support; gates UP rewrites
line-length = 88
extend-exclude = ["migrations"] # generated code, if any
[tool.ruff.lint]
select = [
"E", "W", # pycodestyle
"F", # pyflakes
"I", # isort (import sorting)
"UP", # pyupgrade
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"SIM", # flake8-simplify
"RUF", # Ruff-specific rules
]
ignore = ["E501"] # line length is the formatter's job
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"] # assert is fine in tests (relevant once S is on)
"__init__.py" = ["F401"] # re-exports
[tool.ruff.lint.isort]
known-first-party = ["yourpackage"]
[tool.ruff.format]
quote-style = "double"
docstring-code-format = true # formats Python snippets inside docstrings
此配置中一些不明显的决策:
- 切勿依赖 Ruff 的默认规则集。 0.16 之前,默认规则集是
E4/E7/E9F(59 条规则,少于 Flake8+插件的组合);从 0.16 起,则包含B、UP、SIM、PL等分类中的 413 条规则,并移除了 18 条原有的E/F默认规则——不设置select的代码库每次升级都会采用不同的检查门槛。select会替换 默认规则集,因此显式列出规则可以将其固定;如果团队希望使用与 0.16 之前完全相同的基线,可以设置select = ["E4", "E7", "E9", "F"]。
- 启用格式化工具时,设置
ignore = ["E501"]——ruff format已经会根据line-length换行;再用 lint 检查一次,会对格式化工具无法断开的行(URL、长字符串)重复报错。 target-version决定是否启用UP(pyupgrade)重写。 如果未设置,Ruff 会回退到project.requires-python;如果该项也不存在,则假定为 py310,自动修复可能会生成旧版受支持运行时无法运行的语法。- 避免设置
select = ["ALL"]——每次升级 Ruff 时都会悄无声息地启用所有新增规则,导致检查结果不可预测地出错。官方建议从较小范围开始,逐个类别扩展 (docs.astral.sh/ruff/linter/)。
更深入的规则目录、分级策略和子表选项(isort、pydocstyle、
bugbear):references/rule-selection.md。
4. 调整现有配置
- 某个区域(测试、脚本、笔记本)噪声较多 → 使用
[tool.ruff.lint.per-file-ignores]限定范围;不要因为测试报错就从全局select中删除规则。常见配置:"tests/**/*.py" = ["S101", "PLR2004"]、"scripts/*" = ["T201"]。 - 只有一处是有意违反规则 → 使用
# noqa: <CODE>,注明具体代码并简要说明原因。裸写# noqa会隐藏该行的所有规则。 # noqa注释中的代码来自非 Ruff 工具(自定义 Flake8 插件)→ 在[tool.ruff.lint]中声明external = ["XX"],否则RUF100会在下次--fix时移除这些注释。- 每次只扩展一个前缀(
"S"、"PT"、"PTH"等),每次添加后运行uv run ruff check .,先修复问题或限定范围,再添加更多规则。 - 检查结果是否合理:
python3 "${CLAUDE_SKILL_DIR}/scripts/check_ruff_config.py" --root .(只读;会标记 E501 重复报错、ALL、与格式化工具冲突的规则、遗留的旧配置,以及缺少 target-version 的情况)。
5. 从 Black / Flake8 / isort 迁移
完整的映射表(命令、配置键、Flake8 插件→前缀)以及处理大型旧代码库的策略:references/migration.md。步骤如下:
- 先转换配置。 将
[tool.black]→[tool.ruff]+[tool.ruff.format], 将[tool.isort]/.isort.cfg→[tool.ruff.lint.isort](键名使用连字符格式), 将.flake8→select/ignore/per-file-ignores。Ruff 不会读取[tool.black]或.flake8——未转换的配置都会被静默丢弃。 - 检查插件是否兼容。 对于每个正在使用的 Flake8 插件,确认 Ruff 中存在对应前缀
(见参考表格)。如果某个业务关键插件没有对应项,可采用混合方案:保留 Flake8,
但仅用于该插件,并将其代码添加到
external = [...]。 - 在切换任何门禁之前,先单独提交一次性清理,并进行评审:
检查差异——在大型代码库中,Ruff 格式化器与 Black 接近,但并非逐字节相同;相关差异已记录在 docs.astral.sh/ruff/formatter/black/。 如果要进行大规模重新格式化,请在uv run ruff check . --fix && uv run ruff format ..git-blame-ignore-revs中记录该提交。 - 在同一个 PR 中移除旧工具链:从开发依赖中移除 black/flake8/isort(及其
插件);删除
.flake8、.isort.cfg、[tool.black]、[tool.isort]。两个活跃的格式化器会争夺同一行代码 (astral-sh/ruff#1307)。 - 告知用户将调用旧工具的配置改为调用新工具——包括 pre-commit 钩子
(python-precommit skill)和 CI 作业(python-ci skill)。只提供以下命令:
ruff check .和ruff format --check .。
现有的 Black+Flake8 配置如果运行正常且没有造成问题,不迁移也是合理的——迁移变更也有成本。应在出现阻碍时(速度、配置杂乱、插件停止维护)再迁移,而不是为了赶时髦。
6. 修复 lint / format 失败
uv run ruff check . --fix # 1. autofix what's safe
uv run ruff format . # 2. THEN format — fixes can leave code needing reformat
uv run ruff check . # 3. see what's left; --fix exiting clean != zero violations
执行顺序很重要:--fix 会重写导入语句和推导式,之后还需要重新格式化。对于剩余问题:
- 修复代码。只有在违规是有意为之时才考虑抑制,并且应选择范围最窄的方式:指定
# noqa: <CODE>> per-file-ignores > 全局ignore。绝不要通过从select中删除规则来让红灯变绿。 - 有些修复因可能改变行为而被有意标记为不安全。应用之前,请使用
uv run ruff check . --fix --unsafe-fixes --diff明确检查这些修复。 - 在 GitHub Actions 日志中,
uv run ruff check . --output-format=github会在 PR 上生成文件/行号注释(工作流 YAML 本身属于 python-ci 范畴)。
7. 验证完成
uv run ruff check . && uv run ruff format --check . && echo LINT-OK
python3 "${CLAUDE_SKILL_DIR}/scripts/check_ruff_config.py" --root .
输出规范
满足以下所有条件即表示完成:
pyproject.toml中包含[tool.ruff],并显式设置select;使用格式化器时忽略E501;并且已确定target-version(或requires-python)。- 在开发依赖中固定 Ruff 版本(也可在配置中设置
required-version)。 uv run ruff check .和uv run ruff format --check .均以退出码 0 结束。- 不再残留
.flake8/.isort.cfg/[tool.black]/[tool.isort],开发依赖中也不再包含 black/flake8/isort(除非采用了文档所述的混合方案)。 - 迁移:机械式重新格式化单独放在一个提交中;抑制项附有规则代码和原因。
scripts/check_ruff_config.py报告 0 个错误。
故障模式与注意事项
| 症状 | 原因 | 修复方法 |
|---|---|---|
| 已安装 Ruff,但检查结果太少(0.16 之前),或升级后 CI 报错激增(0.16 及之后) | 使用默认规则集,而默认规则集在 0.16 中从 E+F 改为 413 条规则 | 编写明确的 select(步骤 3)——它会替换默认规则,因此升级不会再改变检查门槛 |
| E501 违规,格式化工具却拒绝修复 | Linter 和格式化工具都负责行长度 | ignore = ["E501"];格式化工具会尽可能换行 |
| 常规 Ruff 升级后检查突然失败 | select = ["ALL"] 会自动启用新规则 | 明确设置 select;固定 Ruff 版本 |
| 格式化工具和 Linter 互相冲突(逗号、引号、缩进) | COM812/COM819、Q000–Q004、D203/D206/D300、W191、E111/E114/E117(以及未启用 ISC001 且 allow-multiline = false 时的 ISC002)与 ruff format 冲突 | 从 select 中移除它们,或添加到 ignore 中——参见冲突规则 |
--fix 删除了 # noqa: XY123 注释 | RUF100 会将未知代码视为未使用的抑制项 | 在 [tool.ruff.lint] 中设置 external = ["XY"] |
| 自动修复生成的语法不兼容支持的最旧 Python 版本 | 未设置 target-version / requires-python → 默认假定为 py310 | 将 target-version 设为实际的最低版本 |
| 逐个传入路径时,排除的文件仍被检查 | 显式文件参数会绕过 exclude(ruff#9585) | 对必须遵守的规则使用 per-file-ignores;钩子层的配置应交由 python-precommit 处理 |
ruff check --fix 正常退出,但 CI 仍然失败 | 只有安全修复会自动应用;其余问题仍会报告 | 重新运行普通的 check;手动修复,或检查 --unsafe-fixes --diff |
| 文件在不同格式之间反复切换 | Black(或 IDE 中的 Black 插件)仍与 Ruff 同时启用 | 只保留一个格式化工具——移除 Black,并更新编辑器设置 |
旧的 .flake8 / [tool.black] 设置“停止生效” | Ruff 不会读取它们 | 将设置转换到 [tool.ruff] 中,然后删除原设置 |
| 本地通过,其他环境失败 | 开发环境、CI 和钩子中的版本不一致 | 所有环境使用相同的固定版本;required-version 会将版本不匹配作为硬错误处理 |
| 以为 Ruff 能格式化 YAML/Markdown/TOML | Ruff 设计上只支持 Python;从 0.16 开始,Markdown 中的 Python 代码围栏 默认会格式化(可使用 fmt: off 注释或 extend-exclude 禁用) | python-precommit 技能涵盖非 Python 格式化;配置 Prettier/mdformat 的作用范围,避免它们与 Ruff 在围栏 Python 代码上冲突 |
| 添加 Ruff 后,CI 首次运行就彻底失败 | 配置检查门槛前没有在本地清理代码 | 在本地运行步骤 6,提交,然后启用检查门槛 |
ruff check 通过,但差异看起来没有格式化 | Lint 和格式化是两回事——check 不会检查格式 | 始终运行两项检查(步骤 7) |
捆绑资源
references/rule-selection.md— 规则前缀→来源对照表、分层采用策略、select与extend-select和ALL的权衡、per-file-ignore 约定、isort/pydocstyle/bugbear 子表、修复安全性选项。references/migration.md— 旧命令→Ruff 对照表、Black/isort/Flake8 配置项转换、Flake8 插件→前缀表、自定义插件混合方案、大型遗留代码库的渐进式采用策略。scripts/check_ruff_config.py— 只读配置检查器;发现问题时以非零状态码退出。运行python3 "${CLAUDE_SKILL_DIR}/scripts/check_ruff_config.py" --root <repo>(使用--strict也会在出现警告时失败)。