mcpField
P
python

python

github.com/ahgraber测试与质量653 次安装1 天前更新
代码仓库

关于 python

面向编码 Agent 的 Python 风格审计技能,结合 ruff 检查与人工判断,检查边界、类型、可靠性、运维、并发和测试。

主要功能

  1. 01运行 ruff lint 与格式检查
  2. 02审查边界与数据流
  3. 03检查公共契约和类型
  4. 04审计可靠性与运维实践
  5. 05检查并发与测试实践

适用场景

  1. 01提交前审计 Python 改动
  2. 02按代码风格偏好审查代码
  3. 03建立基础 lint 配置
  4. 04选择验证与可靠性方案

安装

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

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

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

包含的文件

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

references/
design-boundaries.md
multi-python-testing.md
python-testing.md
scripts/
test_pypi_security_audit.py
test_uv_security_audit.py

详细介绍

Python 代码风格审计

概述

Python 代码风格审计:与其在编写代码时随身携带规则手册,不如扫描目标(差异、文件、包或仓库),查找违规项并报告。 审计分为两个层级:机械检查交由 ruff 处理,判断性检查则无法用任何代码检查工具表达。 前沿编码 Agent 已能编写合理的 Python,因此以下检查仅限于值得检查的剩余风格偏好。

以下每项默认做法都是推荐的起点。 如果默认做法与项目约束冲突或会导致效果变差,请遵循项目要求,并说明权衡及配套控制措施(测试、可观测性、迁移、回滚)。

何时使用

  • Python 变更已完成,即将提交或发布:收尾时审计差异。
  • 有人要求审查、审计、快速检查或清理 Python 代码,或确认代码是否符合标准。
  • 在可靠性、配置、类型/验证、边界或并发方案之间做选择:对应的第 2 层章节即为风格默认做法。
  • 决定 Python 变更需要哪些验证检查。
  • 项目没有 lint 策略,需要建立一套策略(第 1 层提供基线)。
何时不使用
  • 编写测试时——使用 writing-tests;其中的 references/python-testing.md 包含 Python 相关细节。
  • 处理 Notebook 事件循环机制时——使用 python-notebooks-async。
  • 编写演示或教程 Notebook 时——使用 interactive-notebook-demo。
  • 需要对差异是否已准备好合并作出结论时——使用 code-review;本技能提供的是 Python 专项审查角度。

调用提示

  • 告知用户正在运行此技能:python。 如果用户按技能名称或斜杠命令请求此技能,则跳过提示;拼写和空格无需完全一致。 本技能触发词列表中的短语不算技能名称——说明工作内容不等于说出技能名称。

通用默认做法

  • 使用项目指定的 Python 版本。
  • 使用 uv 管理环境和依赖;使用 uv run ... 运行检查。
  • 优先使用 #%% .py Notebook,而非 .ipynb,除非明确要求使用 .ipynb。
  • 遵循本地策略:仓库配置、代码检查规则和项目惯例优先于以下所有内容。

第 1 层 — 机械审计(ruff)

上次验证:2026-08-18 — 对照 https://docs.astral.sh/ruff/default-rules/ 和 ruff 更新日志,重新验证默认规则覆盖范围和版本说明。

首先使用项目自身的配置运行:

uv run ruff check .
uv run ruff format --check .
  • ruff >= 0.16 启用了广泛的默认规则集(413 条规则):bugbear、裸 except、try/except/pass、不带时区的日期时间、异步代码中的阻塞调用和缺失的超时、悬空的 asyncio.create_task 引用、未使用的异步代码,以及日志调用误用,开箱即由机器检查。 绝不要手动审计 ruff 已检查的内容;运行它并按规则 ID 引用检查结果。
  • 如果项目固定使用较旧版本的 ruff 或限制了 select,请遵循本地策略;只有当与本次审查的变更实质相关时,才说明其与风格基线之间的差距。
  • 如果项目没有自己的 lint 策略,请提议以下起点,而不是强行推行:
[tool.ruff.lint]
extend-select = [
  "ANN2",  # missing return types on public functions
  "ASYNC", # async hygiene beyond the default subset
  "DTZ",   # full naive-datetime coverage
  "S113",  # requests calls without timeout
  "T20",   # stray print in library/service code
  "TRY",   # exception design (raise/except hygiene)
]
ignore = ["TRY003"] # long messages in raise — noisy in practice
  • ruff >= 0.16 还会格式化 Markdown 中的 Python 代码块,并支持 ruff: ignore[rule-name] 抑制注释;新增抑制时优先使用这些注释,而非单独使用 noqa 代码。
  • 对于依赖或锁文件变更,请从目标项目的根目录运行供应链审计脚本,并通过本技能 scripts/ 目录中每个脚本的完整路径传入:uv run pytest <path-to-this-skill>/scripts/test_uv_security_audit.py <path-to-this-skill>/scripts/test_pypi_security_audit.py -v。 两个脚本发现问题时会发出警告(而非失败);请阅读警告。

第 2 层 — 判断性审计

针对以下每类问题扫描目标。 这些问题无法通过机器检查;报告每个问题时,注明文件名和行号,并给出具体修复方案。 每项都会说明要查找什么、问题所在,以及可解决问题的风格默认做法。

边界与数据流

在为此类问题提出修复方案之前,请阅读 references/design-boundaries.md,了解这些默认做法背后的原因以及更全面的修复指导。

  • 查找核心业务逻辑中的文件 I/O、环境读取,或时钟与随机数调用。 隐藏在核心中的副作用会让逻辑无法在没有模拟对象的情况下测试,并使决策与基础设施耦合。 默认采用函数式核心/命令式外壳:核心根据输入计算决策,外壳执行副作用。
  • 查找未经验证就进入领域逻辑的外部输入。 在调用栈深处才进行检查时,错误数据早已扩散。 在入口处验证并规范化数据,让边界之后的所有代码都可以信任输入。
  • 查找跨模块边界传递的 ORM 模型、提供方 SDK 类型或持久化架构。 跨越边界的任何内容都会成为契约,而内部类型会连同其整个架构一起带过去。 改用精简的 DTO 或值对象。
  • 查找跨模块边界的事务。 共享事务会让模块的故障模式相互耦合,并带来无人负责的回滚复杂性。 默认通过事件或作业协调跨模块工作,最终保持一致。
  • 查找臆测性的抽象、深层继承,以及 utils/common 代码堆放区。 在第二个具体用途出现之前就建立的抽象通常并不合适,而 utils 模块里的代码则无人负责。 构建最精简的黄金路径,并优先采用组合。
契约与类型

在为此类问题提出修复方案之前,请阅读 references/design-boundaries.md,了解这些默认做法背后的原因以及更全面的修复指导。

  • 查找未注明类型或类型为 Any 的公共函数。 公共签名就是契约;没有类型时,调用方只能猜测,重构也会失去安全保障。 内部辅助函数无需达到同样严格的要求。
  • 查找类型声明比函数实际所需更具体的参数,以及类型声明比函数实际返回内容更宽泛的返回值。 接受抽象接口(Mapping、Sequence、Protocol),避免强迫调用方使用特定容器类型;返回具体类型,让调用方清楚自己拿到的是什么。
  • 查找贯穿内部数据流的 pydantic 模型。 验证属于边界处理;到处使用模型会增加开销,并使内部代码与架构层耦合。 将 pydantic 限定在可信边界——API 入口、配置和外部数据——并在新代码中使用 v2 API(model_validate、model_dump)。
  • 查找没有弃用说明、版本管理或迁移说明的公共契约变更。 下游使用者会在不知情的情况下受到影响。 优先采用增量式变更;有意进行的破坏性变更应附带迁移计划。
可靠性策略
  • 查找未设置显式超时的出站 I/O,以及没有截止时间的长时间运行操作。 库的默认值可能不受限制或随意设定,因此发生故障时的延迟会变得不可预测。 为所有外部 I/O 设置显式超时,并将绝对截止时间(time.monotonic() + budget)传递给嵌套调用,而不是在每一层重新计算相对超时时间。
  • 查找不受限制、在多个层级叠加,或用于永久性故障的重试。 不受限制的重试会把一次故障变成重试风暴;多层重试会让尝试次数成倍增加;重试验证错误只会拖延真正的修复。 限定重试次数和总截止时间,采用带抖动的指数退避,遵循 Retry-After,并确保重试逻辑只存在于一个层级。
  • 查找没有幂等性保障的重试写入。 故障情况不明时进行重试,可能导致写入被应用两次。 使用幂等键或去重令牌,或者禁用该操作的自动重试。
  • 查找通过匹配异常消息字符串来判断是否可重试的情况。 消息文本不是契约,可能在没有预警的情况下发生变化。 将是否可重试编码为策略数据——错误类型和 retryable 标志,并为可重试和永久性结果设置不同的终态。
  • 查找只报告笼统成功或失败的批量操作。 调用方无法判断哪些项目已成功,因此唯一安全的恢复方式就是重新运行全部操作。 除非实际契约要求全部成功或全部失败,否则应返回每项操作的结果。
运行时与运维
  • 查找在使用时才读取配置的情况。 缺失或格式错误的值可能要等到运行几分钟甚至几小时后才暴露,而不是在启动时发现。 加载有类型的设置(例如 pydantic-settings),在启动时验证,并确保导入过程不会产生配置副作用。
  • 查找缺少信号处理、有界排空或 try/finally 清理的关闭路径。 未处理的 SIGTERM 会使子进程成为孤儿,并留下写入一半的状态;不受限制的排空会导致重启时进程挂起。 处理终止信号,停止接收新任务,在截止时间内排空正在处理的工作,并在 try/finally 中清理子进程、临时文件和句柄。
  • 查找终态不明确的任务。 重试耗尽后仍表现为待处理工作,会让故障无法被发现,队列也会逐渐堆积。 将可重试和永久性结果记录为不同状态,并明确配置死信策略。
  • 查找日志记录无结构化,或每次故障触发多条日志的情况。 重复的自由文本日志无法计数、筛选或关联。 在入口点配置一次日志记录,使用模块级日志记录器,在有意义的边界对每次故障只记录一次,并包含操作 ID、阶段和尝试次数,同时避免记录机密。
  • 查找未检查依赖项就返回 OK 的健康或就绪探针。 对依赖探针的编排器而言,虚报健康状态会掩盖级联故障。
并发
  • 查找与工作负载不匹配的并发模型。 用线程处理 I/O 扇出会增加同步错误,而 asyncio 可以避免这些问题;asyncio 对 CPU 密集型工作没有帮助,这类工作需要使用进程。 根据工作负载选择模型,只有理由明确时才使用线程。
  • 查找不受限制的扇出:对不受限制的集合使用 gather 或 submit。 成千上万个并发任务会使事件循环资源紧张,或耗尽内存和文件句柄。 使用信号量或队列限制并发量。
  • 查找取消操作只停止父任务、却没有停止子任务或跳过清理的情况。 孤儿任务会一直占用连接并泄漏资源,直到进程退出。 将取消传播到子任务,并等待其完成清理后再重新抛出异常。
  • 查找没有前后测量的性能优化工作。 未经性能分析的优化会解决错误的问题,而其复杂性却会保留下来。 先测量,再重新测量以确认效果。
测试

Python 专属测试实践见 references/python-testing.md。

  • 查找有多个写入路径、但只测试了规范路径的契约断言值。 去重捷径或缓存快速路径可能会悄无声息地丢弃契约要求的内容。 每个写入位置都需要单独的测试,派生字段的不变量则需要针对组合后的输出进行测试。
  • 查找以模拟调用次数断言代替行为断言、在定义位置而非导入位置应用补丁,以及使用裸 Mock()(而自动规格可捕获签名偏差)的情况。 这些情况都会导致测试通过,但行为却是错误的。
  • 查找已合入但没有先失败过的回归测试的错误修复。 一个从未失败过的测试无法证明错误已修复。

报告

  • 运行命令并引用输出,报告 tier 1;报告 tier 2 问题时,注明文件:行号、违反的默认规范及建议的修复方案。
  • 区分“违反团队默认规范”和“违反本项目自身惯例”;后者优先级更高。
  • 仅在用户要求时或任务本身就是清理工作时修复问题;否则仅报告。

参考资料

  • references/design-boundaries.md — Functional Core / Imperative Shell、模块归属、边界契约、pydantic 的放置位置、契约演进
  • references/python-testing.md — Python 专属测试实践(也已共享给 writing-tests)
  • references/multi-python-testing.md — 使用 nox + uv 进行版本矩阵测试

评论

支持 Markdown