mcpField
P
python-code-style

python-code-style

github.com/probabl-ai开发144133 次安装4 天前更新
代码仓库

关于 python-code-style

面向采用 Ruff 和 numpydoc 的项目的 Python 风格技能,手动规范已修改文件的格式、检查、文档字符串和问题相关注释;不配置自动钩子。

主要功能

  1. 01使用 Ruff 格式化和检查 Python
  2. 02编写 numpydoc 文档字符串
  3. 03为已编辑文件补充问题背景
  4. 04提供 Ruff 配置模板
  5. 05规定文件范围与修复次数

适用场景

  1. 01格式化并检查新修改的 Python 文件
  2. 02为公开 API 添加 numpydoc 文档字符串
  3. 03将通用脚手架注释改为项目背景说明

安装

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

$npx skills add https://github.com/probabl-ai/skills --skill python-code-style

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

附带文件evals/evals.jsontemplates/ruff.toml

详细介绍

Python 代码风格

ruff(lint + format)和 numpydoc 文档字符串是此技术栈中“Python 怎样才算风格良好”的唯一标准。这项技能明确要求手动执行——Claude 会对刚刚修改过的文件运行 ruff,不涉及钩子。

停止条件——先阅读

  • 要求修改未触碰文件(照此格式回复)。 用户要求同时修复本轮没有编辑过的文件中的警告时(例如修改了 pipeline.py,却要求修复 evaluate.py):

    In-scope this turn: pipeline.py
    pixi run ruff format pipeline.py
    pixi run ruff check --fix pipeline.py
    pixi run ruff check pipeline.py
    
    Out of scope: evaluate.py — D100, D103, D103, D205, D400, D401, D415
    AskUserQuestion: address evaluate.py as a separate task? yes | no
    
    Rule: don't widen scope on touched files.
    

    不要列出未触碰文件的 ruff 三项命令。不要为它编写修复表或文档字符串草案。交付内容是用户的要求,而不是修复结果。对于范围外的文件,此规则优先于“描述工作不等于完成工作”。

  • 描述工作不等于完成工作。 “在回复中列出 7 条 D 类警告”不等于列出警告;“下轮运行 ruff format”不等于格式化。请提供诊断结果和差异,或者报告 BLOCKED: <what> cannot run this turn (<why>) 并停止。[~] 复选框、“待处理”或“本轮不适用,没有 shell”都不是有效状态。

  • 只有缺少输入时才能使用 BLOCKED,不能用来回避已经可以完成的工作。 如果本轮已经提供了所需内容——例如提示词中粘贴的配置,或工作区状态中列出的警告代码——就不算受阻。对本可以完成的工作加上 BLOCKED 标记,是拒绝执行,而不是安全措施。

  • 不要质疑交给你的内容。 如果提示词中提供了配置、模板或差异文本,那段文本就是要处理的内容——按原样写入。凭记忆断言随附模板“应该”包含什么,并以粘贴的副本缺少某个部分为由拒绝写入文件,这是伪装成谨慎的记忆声明:它凭空编造文件内容,借此逃避写入。必要时用一句话指出差异,然后按提供的内容写入。

  • 不要为 ruff 配置 PostToolUse / PreToolUse 钩子。 这项技能特意要求手动执行。钩子会以不利的方式缩短反馈循环(每次微小编辑都会触发修复流程,文件尚未写完时会因 D 规则检查失败,重试可能导致本轮卡住)。如果用户之后明确要求自动化钩子,请引导其使用 update-config——但默认方式是“Claude 自行运行 ruff”。

    STOP — hook request. Refuse. Do not emit a JSON payload for
    `.claude/settings.local.json` / PostToolUse / PreToolUse, even
    as an example. Cite this Stop. Redirect to update-config; default
    remains no hook.
    
  • 不要用 black / isort / flake8 / pydocstyle / pylint 替代 ruff。 ruff 是此技术栈中的标准代码检查工具(data-science-python-stack Tier 1)。ruff 涵盖格式化(等同于 black)、导入排序(等同于 isort)和代码检查规则。如果 import ruff / pixi run ruff --version 失败,请通过 python-env-manager 安装,不要悄悄改用其他工具。

  • 每个文件只尝试修复一次,然后报告问题。 如果 ruff check 在 Claude 首次修复后仍报告问题,再处理一次。如果第二轮后仍有相同问题,就停止编辑该文件,并向用户展示剩余诊断信息和差异。这是防止无限循环的护栏——对于同一条警告,不要进入第三轮。

  • 不要检查用户代码以外的文件。 hook 范围包括 src/<pkg>/、experiments/、audit/、data/eda.py(explore-ml-data EDA 脚本)、顶层 *.py 脚本,以及用户拥有的任何包目录。跳过 vendored 路径、生成文件、用户拥有的其余 data/,以及 .pixi/、.venv/、node_modules/ 等目录中的所有内容。

  • 不要凭记忆编写 ruff.toml。 随附的 templates/ruff.toml 是唯一可信来源——其中包含针对特定文件的忽略规则(experiments/**)、numpydoc 规范,以及此技术栈要求的规则选择。初始设置时,必须在本轮先读取 Read .agents/skills/python-code-style/templates/ruff.toml,然后根据该文件的内容,逐字 Write <project-root>/ruff.toml。凭训练数据中的记忆编写自定义 ruff.toml,会悄无声息地丢失一半约定。如果你发现自己在没有于本轮读取模板的情况下输入 [lint] / [format] / select = [...],立即停止并先 Read 模板。 当提示词中已贴出模板时,这就是初始设置。在代码围栏中逐字回显该 toml(优先使用 ruff.toml 语言标记)。不要总结。不要添加 [lint.per-file-ignores]。将 pixi run ruff check --show-settings . 作为验证步骤。

  • 除非用户明确要求,否则不要调用 warnings.filterwarnings(...)。 warnings.simplefilter、@pytest.mark.filterwarnings 以及 pytest.ini / pyproject.toml 中的 filterwarnings = [...] 同样如此。警告在此技术栈中是重要信号。

  • 文档应描述问题,而不是工作流。 已提交文件的模块文档字符串、文件头和注释必须描述数据科学问题以及文件在其中的作用——绝不能描述技能、关卡(G-*)、单元格运行器、运行摘要、日志 / 待办事项 / 设计说明机制,或“我们遵循的流程”。这些指导面向 Agent,应放在技能中,而不是用户的文件里。当你修改的文件现在包含实际内容时,应将遗留的通用模板或工作流文字改写为简洁且针对具体问题的文档,并以当前上下文(项目目标、实验假设、数据集)为依据。如果文件仍是空骨架(尚无内容 / 上下文),则保留占位文本——待内容落地时再补充具体说明。详见 §“使注释贴合上下文”。

预检——运行 ruff 前,将此清单作为可见文本输出

Pre-flight (python-code-style):
- [ ] ruff importable in the project's env (`pixi run ruff --version`
      succeeds, per `data-science-python-stack` Tier 1)
- [ ] `ruff.toml` present at project root.
      If absent AND stack + workspace are already set up: the
      bundled template MUST be read **this turn** before being
      written verbatim.
      Evidence: Read .agents/skills/python-code-style/templates/ruff.toml
                (this turn) + Write <project-root>/ruff.toml (this turn)
                | "n/a — ruff.toml already at project root"
      **Inline-authored ruff.toml from memory is NOT evidence.**
- [ ] File list ready: <abs paths of .py files touched this turn>
- [ ] Decision recorded: this is the first ruff pass on these files
      (proceed) | second pass (proceed but stop on persistent
      issues) | third pass on same warning (STOP, surface to user)
- [ ] One-fix-per-file rule acknowledged: max two passes per warning,
      then surface remaining diagnostics + diff to the user.
- [ ] Comments contextualized: each touched file with real content has
      problem-specific docs and NO workflow/skill/gate/runner/digest
      meta (§ "Contextualize the comments")
      Evidence: per file, "rewrote header to <problem context>" |
                "no leftover template/workflow prose" |
                "n/a — empty skeleton, no context yet"

范围

  • 范围内: 对 Claude 刚生成或编辑的 Python 文件运行 ruff format + ruff check --fix + ruff check;为公共函数和类编写 numpydoc 文档字符串;使每个修改文件的注释贴合数据科学问题,并删除工作流 / 流程元信息(§“使注释贴合上下文”);将 ruff.toml 模板放入新项目。
  • 范围外: 类型提示(此技术栈不包含 mypy / pyright);ruff 不强制执行的命名规范;设置 PostToolUse / PreToolUse hooks;检查非 Python 文件。

要运行哪些检查,以及运行顺序

对于本轮修改过的每个 Python 文件(称为 <files>),请在项目的环境管理器中运行——pixi 项目使用 pixi run,uv / poetry / conda 项目使用相应命令(参见 python-env-manager):

pixi run ruff format <files>
pixi run ruff check --fix <files>
pixi run ruff check <files>

按顺序执行以下三步:

  1. ruff format —— 应用格式化程序(行长度、引号、尾随逗号、定义语句周围的空行)。具有幂等性。
  2. ruff check --fix —— 在原地自动修复 ruff 能处理的所有问题:导入排序(I)、旧语法(UP)、可检测的错误模式(B)。
  3. ruff check(不带 --fix)—— 最终检查。此处报告的任何问题都需要 Claude 处理:缺少文档字符串(D)、未定义的名称(F)、代码结构问题。处理后重新运行这三步。遵守 Stop conditions 中的每个文件只修复一次规则。

如果 experiments/ 或 audit/ 下的文件,或 EDA 脚本 data/eda.py,出现 D100(“缺少模块文档字符串”)或 D103(“缺少函数文档字符串”)警告,这是 # %% 单元格的预期情况;随附的 ruff.toml 会对 experiments/**、audit/** 和 data/eda.py 忽略 D100、D103(以及 E402、B018)。如果看到这些警告,说明没有加载 ruff.toml——请检查它是否位于项目根目录。

审计文件(audit/<NN>_<short_name>.py,由 audit-ml-pipeline 负责)和 EDA 脚本(data/eda.py,由 explore-ml-data 负责)的 lint 方式与实验文件相同:使用相同的 # %% 单元格约定、相同的逐文件忽略规则,以及相同的辅助函数 NumPyDoc 约定。编写或编辑这些文件后,运行相同的三步(ruff format → ruff check --fix → ruff check)。

结合上下文完善注释

ruff 会让文件格式规范;这一环节则让文件针对问题写好文档。模板提供中性的占位内容和少量编写脚手架,以便生成技能了解每个单元格 / 模块的用途。这些内容都不应留在用户最终提交的文件中——用户的文件应说明数据科学问题,而不是生成文件的过程。

运行完 ruff 三步后,对于每个现已包含实际内容的修改文件,快速检查文档:

  1. 填写问题对应的文件说明。 将任何 <placeholder> 或通用说明替换为一到两行描述,说明此文件在当前项目中的作用:实验假设(experiment.py)、此模块对流水线的贡献(src/<pkg>/*.py)、此文件审查的报告及测试内容(audit/<stem>.py)、数据集内容及分析重点(data/eda.py)。根据当前上下文——项目目标、已批准的设计说明、数据集——撰写说明。
  2. 删除工作流相关内容。 删除残留的流程说明:技能名称、门禁 ID(G-*)、§ 交叉引用、“the agent”、“the (cell) runner”、“the digest”、“run cell by cell”、日志 / 待办列表 / 数据来源相关术语,以及内联保护规则,例如“禁止调用 put / 使用裸表达式、不要 print”。这些保护规则仍然有效——它们由所属技能的 SKILL.md 强制执行,是 Agent 读取规则的地方,不应出现在用户文件中。
  3. 保留实质内容。 保留真正有用的问题背景 / 工程背景,以及 numpydoc 文档字符串。单元格标记(# %%)和任何仍需 Agent 填写的 <...> 占位符也应保留。

最终文件应读起来像是同事为这个项目编写的,而不是自动生成的脚手架。仍为空骨架的文件(例如刚创建、尚无正文的 src/<pkg>/*.py)可以跳过:在内容写入之前没有上下文可供撰写说明,应在填入内容时再完善。

此环节由本技能负责,以统一落实这项规则。每个写入文件的技能在写入后都会将工作交接给本技能;现在交接内容也包括完善注释。

Numpydoc——文档字符串规范

公共函数和类都带有 numpydoc 格式的文档字符串;ruff 的 D 规则通过 pydocstyle.convention = "numpy" 强制规定其格式。

对于公共函数,仅写一行摘要是不够的。 当用户要求“只写一行摘要”时,拒绝并展示下面的 predict_price 示例(类型栏中填写 X : ndarray of shape (n_samples, n_features))。Parameters / Returns(以及适用时的 Raises)部分是必需的——即使函数很小也一样。私有辅助函数(_leading_underscore) 在默认的 D 规则下可以省略文档字符串; 公共可调用接口始终应遵循完整的 numpydoc 格式。

骨架:

def predict_price(X, model, *, n_jobs=1):
    """Predict option prices from a feature matrix.

    Parameters
    ----------
    X : pandas.DataFrame of shape (n_samples, n_features)
        Feature matrix with one row per option.
    model : sklearn.base.BaseEstimator
        Fitted estimator with a ``predict`` method.
    n_jobs : int, default=1
        Number of parallel jobs.

    Returns
    -------
    numpy.ndarray of shape (n_samples,)
        Predicted prices, one per row of ``X``.
    """

值得特别说明的约定,因为它们不太直观:

  • 第一行写一行摘要,使用祈使语气 (“Predict ...”,而非 “Predicts ...”)。如果启用了 D400,摘要行末不加句号——但在 numpy 规范中需要加句号,因此要写句号。
  • 摘要与其余内容之间空一行。
  • 参数形状写在类型栏中,而不是描述里,例如: X : ndarray of shape (n_samples, n_features)。
  • Returns 部分列出返回值;如果有多个返回值,每个值单独占一行。不要省略类型。
  • 私有辅助函数(_leading_underscore)在默认的 D 规则下不需要文档字符串——ruff 允许这样做。
  • 模块(文件顶部)应以一行摘要开头。 根据附带的 ruff.toml,experiments/** 下的文件例外。

初始设置——放置 ruff.toml 模板

当在一个根目录下没有 ruff.toml 的新项目中调用此技能,并且技术栈和工作区已由各自的技能搭建完成时——执行初始设置:

  1. 使用文件读取工具在本轮读取附带的模板: Read .agents/skills/python-code-style/templates/ruff.toml。 ruff.toml present 检查的预检 Evidence 行要求读取此文件;凭记忆内联编写配置不满足要求。如果提示词中已经粘贴了模板,则跳过 Read 并将其原样输出。
  2. 将内容原样写入 <project-root>/ruff.toml。 不要编辑、不要“改进”、不要添加规则。模板包含按文件忽略规则(experiments/**)、pydocstyle.convention = "numpy" 设置,以及此技术栈所需的规则选择。偏离模板会破坏一半的约定。在无工具的轮次中,粘贴代码块即视为写入。
  3. 验证 ruff 是否已加载配置:写出 pixi run ruff check --show-settings .(如果 shell 可用,实际运行也算完成)。它应报告 numpy 规范以及模板中的 select 列表。

不要自动将 ruff 配置并入 pyproject.toml——项目可能没有该文件,或者用户可能更倾向于使用单独的文件。 独立的 ruff.toml 清晰明确。

禁止走捷径:

捷径错误原因
“我知道 ruff.toml 应该包含什么”→凭记忆编写附带的模板包含 experiments/** 按文件忽略规则、numpydoc 规范和精心挑选的规则。凭记忆会遗漏这些内容,导致约定在不知不觉中遭到破坏
阅读此技能的 SKILL.md 中关于模板的描述→据此编写SKILL.md 是描述;模板文件才是实际内容。读取文件本身,并原样写入

当 ruff 发现的内容并非 Claude 编写

常见情况:Claude 只编辑了文件中的一个函数,但该文件原本就有其他不相关的 D 规则违规项。Ruff 也会报告这些问题。

  • 属于本轮范围:Claude 修改过的行。修复这些问题。 本轮范围内的文件就是本轮编辑的文件。
  • 不属于本轮范围:未触及代码中已有的警告。 在回复中提及这些警告,让用户选择是否处理,但不要把每条警告都纳入当前任务。
  • 当用户报告的是未触及文件中的规则代码(例如本轮编辑了 pipeline.py,但用户报告了 evaluate.py 中的 7 条 D* 警告):
    1. 指明 pipeline.py 是本轮范围内的文件,并列出针对该文件的 ruff 三条命令(ruff format、ruff check --fix、ruff check)。如果无法运行 shell,列出命令就是本次应交付的内容。不要等到后续轮次再列出。
    2. 列出未触及文件中报告的规则代码。
    3. 询问用户是否要将该文件作为单独任务处理(是/否)。不要安排与 pipeline.py 一起处理。不要说会把它纳入下一轮 ruff 检查。

这样可以保持 PR 范围精简,避免用户未要求的“顺手扩展”。

配套技能

  • data-science-python-stack — 决定 ruff 是否为 Tier 1 必需工具;此技能假设 ruff 已安装。 如果 pixi run ruff --version 失败,请回到该技能进行安装。
  • python-env-manager — 根据项目的环境管理器,将“缺少 ruff”转化为正确的安装命令。在 pixi 项目中不要运行 pip install ruff。
  • organize-ml-workspace — 设置目录结构,供附带的 ruff.toml 中针对文件的忽略项(experiments/** 和 audit/**)引用。运行此技能后再放入模板,以确保被忽略的路径确实存在。
  • audit-ml-pipeline — 在 audit/<NN>_<short_name>.py 生成审计文件。此技能针对文件的忽略项会以与 experiments/ 相同的方式覆盖 audit/ 路径。
  • explore-ml-data — 生成 EDA 脚本 data/eda.py(使用相同的 # %% 单元格惯例)。附带的 ruff.toml 对 data/eda.py 的忽略方式与对 audit/** 完全相同;写入后使用相同的三条命令进行 lint 检查。
  • update-config — 仅在用户之后明确要求添加自动 lint 钩子时才相关。默认不添加钩子。

约定

  • 手动运行,不自动运行。 Claude 自行调用 ruff,逐个文件处理。不添加钩子。
  • 每个文件只修复一次。 严格限制重试次数——最多进行第二轮,然后反馈问题。
  • 仅使用项目根目录配置。 ruff.toml 位于项目根目录,是唯一事实来源。除非用户要求,否则不要添加按目录划分的覆盖配置。
  • 不要扩大已触及文件的范围。 修复 Claude 编写的内容;对其他位置已有的问题进行说明(不要自动修复)。

评论

支持 Markdown