ADK Python 格式化规范全解:pyink、isort 与 pre-commit 驱动的代码风格工作流
【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python
google-adk(Agent Development Kit,仓库见本目录根 README.md)是一个代码优先的 Python Agent 开发框架,源码规模庞大且长期多人协作,因此代码风格不是靠口头约定,而是通过pre-commit钩子与 CI 双重强制。本文以仓库中的格式化风格指南为骨架,逐条拆解 ADK 的缩进、行宽、引号、导入排序规则,说明每个钩子到底检查什么、被哪些目录豁免,并给出本地一键运行格式化的完整命令,最后深入到scripts/与pyproject.toml源码层,讲清"规则从哪里来、被谁执行、失败时去哪里查"。
规则的单一事实来源:两份配置文件
ADK 的格式化规则不是散落在文档里的建议,而是被硬编码在仓库根目录的两份配置文件中:
- pyproject.toml:所有工具的配置参数都声明在这里,包括
pyink、isort、ruff、codespell等; - .pre-commit-config.yaml:声明了每个 pre-commit 钩子、其来源仓库、版本号与参数,并定义了哪些目录整体豁免。
格式指南文档明确指出:这两份配置是唯一事实来源(source of truth),风格指南只是对它们的汇总。因此排查格式化问题时应以这两份文件为准,而不是依赖记忆中的规则。修改代码时同样以这两份配置为最终依据。
四条核心格式化规则
ADK 的格式化基准是 Google 维护的pyink(Black 的 Google 分支),配合isort管理导入,规则如下:
| 规则 | 配置项 | 含义 |
|---|---|---|
| 2 空格缩进 | pyink-indentation = 2(见 pyproject.toml) | 永远不使用 Tab |
| 80 字符行宽 | pyinkline-length = 80 | 超长行会被重排;import 行是唯一例外 |
| pyink 格式化 Python | 格式化器本体 | 所有非 import 的格式问题都由它处理 |
| 引号跟随文件多数风格 | pyink-use-majority-quotes | pyink 不会把'x'机械改写成"x",编辑哪个文件就沿用该文件的主流引号,避免大规模引号震荡 |
以pyink-use-majority-quotes为例:它逐文件统计单引号与双引号的占比,选择多数派作为该文件的统一风格。这意味着你新编辑的代码应"与文件保持一致",而不是强行把整个文件改成自己的偏好——这是 Google 系代码库(如src/google/adk/下各模块)保持 diff 最小化的关键机制。
每个钩子到底强制什么
pre-commit的运行顺序本身并不重要,重要的是知道是哪个工具拒绝了你的提交。下表完整列出 .pre-commit-config.yaml 中的钩子及其职责:
| 钩子 | 作用 |
|---|---|
ruff | 只移除未使用的导入(lint.select = ["F401"]),自动修复,仅作用于src/。__init__.py豁免,因为它的导入是 re-export(详见 pyproject.toml 中的per-file-ignores) |
isort | 导入的顺序与分组 |
pyink | 除导入外的所有其他格式化 |
addlicense | 为.py/.sh文件添加 Apache 2.0 许可证头;若本机未安装 Go 版addlicense二进制则以警告跳过,但 CI 仍会捕获遗漏 |
check-new-py-prefix | src/google/adk/下新增的.py文件必须以_开头(private-by-default),详见 visibility 参考 |
compliance-checks | 合规检查:logger 名称、from __future__ import annotations、cli/包导入方向、mTLS 端点等 |
codespell | 代码与文档中的拼写检查;确属误报的词加入 pyproject.toml 的ignore-words-list |
pyproject-fmt | 规范化pyproject.toml自身的格式 |
mdformat | 仅格式化README.md、CONTRIBUTING.md与contributing/**.md(配置见此处) |
check-yaml、end-of-file-fixer、trailing-whitespace | 空白与 YAML 语法卫生:文件尾换行、行尾空白、多文档 YAML 解析 |
update-constraints | 当pyproject.toml变化时重新生成constraints-3.*.txt;需要网络访问来解析依赖版本 |
两个"本地钩子"的源码细节
check-new-py-prefix与compliance-checks都是仓库自带的本地脚本钩子(repo: local),它们的行为可以由源码精确印证:
- check-new-py-prefix:入口是 scripts/check_new_py_files.sh,最终调用 scripts/check_new_py_files.py。该脚本除了强制
_前缀外,从源码看还会要求新文件在docs/guides/下配套 unit guide(除非匹配豁免模式,或提交信息/环境中带NO_UNIT_GUIDE标签)。它支持 git、jj、hg、g4、p4 多种 VCS 检测,并定义了退出码 3 表示"无法确定新增文件集",避免把"检查失败"误读为"检查通过"。 - compliance-checks:入口是 scripts/compliance_checks.py,采用正则与 AST 双重手段。从源码结构看,它实际包含的检查点比文档表格列出的更多:
- logger 名称:禁止裸写
logger = logging.getLogger(__name__),必须带google_adk.前缀(check_logger); from __future__ import annotations:除__init__.py、version.py、tests/、contributing/samples/外强制要求(check_future_annotations);cli/导入方向:cli/包外的任何文件禁止from ...cli... import ...(check_cli_import);- mTLS 端点:出现非 scope 的
*.googleapis.com硬编码 URL 时必须同时存在.mtls.googleapis.com支持,历史遗留文件放在_EXCLUDED_FROM_MTLS白名单中且禁止新增(check_mtls); - 内部短链检查:禁止
go/xxx形式的内部短链接; - FastAPI 路由装饰器顺序:路由装饰器上方的装饰器永远不生效,AST 检查会报告这类"静默失效"的守卫代码(check_route_decorator_order)。
- logger 名称:禁止裸写
全量豁免目录
.pre-commit-config.yaml 在顶层声明了排除规则,以下目录/路径不参与任何钩子:
src/google/adk/cli/browser/ src/google/adk/v1/ v1_tests/此外 pyproject.toml 的[tool.ruff] extend-exclude还单独豁免了几个硬编码 googleapis.com 端点的大查询(bigquery)相关文件——它们一旦变动就会触发 mTLS 策略检查,因此暂时从F401清理中排除,待 mTLS 策略解决后再处理。注意这两层豁免的语义不同:顶层 exclude 是"完全不检查",ruff 的 extend-exclude 只是"本工具不检查"。
如何运行格式化器
安装 git 钩子一次,之后提交时就会自动格式化:
pre-commit install随后对尚未提交的工作进行检查:
# 仅检查已暂存(staged)文件 —— 提交钩子实际运行的就是这个 pre-commit run # 指定文件 pre-commit run --files path/to/file.py # 全量检查 pre-commit run --all-files关键认知:CI 运行的是同一份配置(.pre-commit-config.yaml),所以本地pre-commit run --all-files通过,就意味着 lint CI 任务会通过。为了让本地输出与 CI 字节级一致,pyproject.toml 的dev可选依赖把会改写文件的格式化工具固定到与 pre-commit 完全相同的版本,例如isort==8.0.1、pyink==25.12、ruff==0.15.17、pyproject-fmt==2.24、pre-commit-hooks==4.6、codespell[toml]==2.4.2——安装pip install 'google-adk[dev]'即可获得这套工具链。
类型检查是另一条独立流水线
务必区分"格式化/lint"与"类型检查":格式问题由 pre-commit 与 lint CI 负责,而类型错误由独立的 mypy CI 任务负责,其配置在 pyproject.toml 的[tool.mypy](strict = true、python_version = "3.11"、使用pydantic.mypy插件)。因此pre-commit run --all-files通过只代表格式合格,不代表类型检查通过。
与导入规则的衔接:80 字符的例外
格式化指南特别强调 import 行是 80 字符限制的例外,这与 imports 参考 完全对应:
isort配置了line_length = 200(见 pyproject.toml),pyink 对 import 行原样保留,所以超长的from ... import ...保持单行,仓库中不存在括号换行的 from-import;isort的profile = "google"强制"一个名字一行",且按大小写不敏感排序、不按类型分组;- 分组固定为三段、空行分隔:标准库 → 第三方 → 相对导入;测试代码中
google.adk经known_third_party声明被归入第三方组; - 仅类型提示需要的导入放入
if TYPE_CHECKING:块,配合from __future__ import annotations避免运行时循环导入。
失败排查速查表
风格指南(SKILL.md)给出了"钩子失败去哪里查"的对照:
| 失败的检查 | 参考文档 |
|---|---|
check-new-py-prefix | visibility 参考(_前缀与__init__.py导出规则) |
compliance-checks | logging 参考(logger 名称)、typing 参考(from __future__ import annotations)、imports 参考(cli/导入方向) |
pyink、isort、ruff、addlicense、codespell | 本文即 formatting 参考 |
| Mypy Check CI 任务 | typing 参考 |
工具链的安装(pre-commit、addlicense等)由adk-setup技能负责,格式化相关问题则可直接对照本文与 pyproject.toml、.pre-commit-config.yaml 两份配置核查。
小结
ADK 的格式化体系可以概括为三层:pyink + isort负责"怎么排版",一系列 pre-commit 钩子负责"提交前拦截",CI 与版本固定的 dev 依赖保证"本地与线上结果一致"。对贡献者而言,最实用的三句话是:缩进永远 2 空格、行宽 80(import 除外)、提交前跑一遍pre-commit run --all-files。遇到钩子拒绝时,按上表定位到对应参考文档,规则细节则以 pyproject.toml 与 .pre-commit-config.yaml 为最终依据。
【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考