mcpField
P
python-lint

python-lint

github.com/paldom测试与质量259 次安装7 周前更新
代码仓库

关于 python-lint

python-lint 指导 Python 包使用 Ruff 作为代码检查和格式化工具,涵盖全新配置、从 Black、Flake8 和 isort 迁移、规则调整及问题修复。

主要功能

  1. 01在 pyproject.toml 中显式配置 Ruff 规则
  2. 02固定 Ruff 版本并设置 Python 目标版本
  3. 03从 Black、Flake8 和 isort 迁移
  4. 04调整规则并限定例外范围
  5. 05修复并验证检查与格式问题

适用场景

  1. 01为新的 Python 包配置 Ruff
  2. 02替换旧有的检查与格式化工具链
  3. 03调整测试或脚本的检查规则
  4. 04处理代码检查与格式问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/paldom/python-skills --skill python-lint

安装后在 Claude Code 中输入/python-lint确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
migration.md
rule-selection.md
scripts/
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/E9
    • F(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。步骤如下:

  1. 先转换配置。 将 [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——未转换的配置都会被静默丢弃。
  2. 检查插件是否兼容。 对于每个正在使用的 Flake8 插件,确认 Ruff 中存在对应前缀 (见参考表格)。如果某个业务关键插件没有对应项,可采用混合方案:保留 Flake8, 但仅用于该插件,并将其代码添加到 external = [...]。
  3. 在切换任何门禁之前,先单独提交一次性清理,并进行评审:
    uv run ruff check . --fix && uv run ruff format .
    
    检查差异——在大型代码库中,Ruff 格式化器与 Black 接近,但并非逐字节相同;相关差异已记录在 docs.astral.sh/ruff/formatter/black/。 如果要进行大规模重新格式化,请在 .git-blame-ignore-revs 中记录该提交。
  4. 在同一个 PR 中移除旧工具链:从开发依赖中移除 black/flake8/isort(及其 插件);删除 .flake8、.isort.cfg、[tool.black]、[tool.isort]。两个活跃的格式化器会争夺同一行代码 (astral-sh/ruff#1307)。
  5. 告知用户将调用旧工具的配置改为调用新工具——包括 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/TOMLRuff 设计上只支持 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 也会在出现警告时失败)。

评论

支持 Markdown