Poetry pre-commit 钩子完全指南:用 poetry-check、poetry-lock、poetry-export、poetry-install 守护依赖一致性
【免费下载链接】poetryPython packaging and dependency management made easy项目地址: https://gitcode.com/GitHub_Trending/po/poetry
pre-commit 是一个用于构建和运行 git hooks 的框架,Poetry 官方提供了poetry-check、poetry-lock、poetry-export、poetry-install四个 pre-commit 钩子,帮助你在每次提交、切换分支或合并代码时自动验证pyproject.toml配置、保持poetry.lock最新、同步requirements.txt并确保依赖已安装。读完本文,你将掌握这四个钩子的工作原理、参数配置、monorepo 场景下的目录切换技巧,以及pre-commit autoupdate在 Poetry 下的替代方案,从而把依赖管理的检查固化进团队工作流。
背景:pre-commit 与 Poetry 的集成方式
pre-commit 是一个通用的 git 钩子管理框架,它允许你把任意工具注册为提交前的检查步骤。Poetry 仓库本身通过根目录下的 .pre-commit-hooks.yaml 文件声明了这些钩子,pre-commit 框架会读取该文件来发现可用钩子。从该配置文件可以看到四个钩子的核心定义:
- id: poetry-check name: poetry-check description: run poetry check to validate config entry: poetry check language: python pass_filenames: false files: ^(.*/)?(poetry\.lock|pyproject\.toml)$ - id: poetry-lock name: poetry-lock description: run poetry lock to update lock file entry: poetry lock language: python pass_filenames: false files: ^(.*/)?(poetry\.lock|pyproject\.toml)$ - id: poetry-install name: poetry-install description: run poetry install to install dependencies from the lock file entry: poetry install language: python pass_filenames: false stages: [post-checkout, post-merge] always_run: true这些定义揭示了几个关键行为:
- 四个钩子均以
language: python运行,pre-commit 会为它们创建独立的隔离环境,无需预先全局安装 Poetry; pass_filenames: false表示钩子不接收文件参数,而是由命令自行处理项目文件;poetry-check与poetry-lock通过files正则限定了触发条件:仅当poetry.lock或pyproject.toml发生变化时才运行;poetry-install则声明了stages: [post-checkout, post-merge],默认挂在post-checkout与post-merge阶段执行(详见下文专节)。
两个重要默认行为
在配置这些钩子之前,必须先了解两条由 Poetry 官方文档明确给出的规则:
args:会覆盖默认参数:如果你在.pre-commit-config.yaml中为某个钩子指定了args:,那么该钩子的默认参数将被全部覆盖。此时你必须完整地写出所有需要的参数,而不是在默认值基础上追加。pyproject.toml不在根目录时:可以通过args: ["-C", "./subdirectory"]指定工作目录。-C即--directory,是 Poetry 的全局选项,作用是把命令的工作目录切换到指定路径,所有命令行参数都会相对于该目录解析(见 docs/cli.md 中的全局选项说明)。
poetry-check:阻止损坏的配置进入仓库
poetry-check钩子调用poetry check命令,确保 Poetry 配置不会以损坏的状态被提交。
钩子实际校验什么
从 src/poetry/console/commands/check.py 的CheckCommand实现可以看到,poetry check会执行以下校验:
- 通过
Factory.validate()验证pyproject.toml的完整结构(check.py); - 校验 trove classifiers(分类器):识别无法识别或已弃用的分类器,并给出替换建议;同时允许
Private ::开头的私有分类器(check.py); - 校验 README 声明:检查
tool.poetry.readme或project.readme中声明的文件是否真实存在(check.py); - 校验依赖声明中引用的 source 是否与已配置的仓库一致(check.py);
- 校验 lock 文件一致性:检查
poetry.lock是否存在,以及pyproject.toml是否发生了显著变化导致 lock 过期(check.py)。
当存在错误时,命令返回码为 1(pre-commit 会把非零返回码视为检查失败),无错误时输出All set!。
支持的参数
poetry-check钩子接受与poetry check命令相同的参数,核心选项如下(对应 check.py 中的定义,详见 docs/cli.md):
| 选项 | 说明 |
|---|---|
--lock | 校验当前pyproject.toml对应的poetry.lock是否存在 |
--strict | 只要出现 warning 即判定失败(返回码 1) |
由于args:会覆盖默认值,如需同时启用两个选项,应显式写出:
repos: - repo: https://github.com/python-poetry/poetry rev: '' # 填写版本号 hooks: - id: poetry-check args: ["--lock", "--strict"]poetry-lock:确保锁文件与声明同步
poetry-lock钩子调用poetry lock命令,确保每次提交时poetry.lock都与pyproject.toml保持同步。
命令行为
从 src/poetry/console/commands/lock.py 可以看到,LockCommand读取当前目录的pyproject.toml,解析并锁定依赖到poetry.lock;默认情况下,已经在 lock 文件中存在的包不会被更新(lock.py),这与 docs/cli.md 的描述一致。
支持的参数
poetry-lock钩子接受与poetry lock命令相同的参数,核心选项为:
| 选项 | 说明 |
|---|---|
--regenerate | 忽略现有 lock 文件,从零重新生成 |
通常你希望锁文件既不过期、又不被无谓地刷新,因此默认参数即可满足大部分场景:
repos: - repo: https://github.com/python-poetry/poetry rev: '' # 填写版本号 hooks: - id: poetry-lock如果依赖声明发生了大规模变更,希望在提交时强制重新生成锁文件,可以显式传入--regenerate:
- id: poetry-lock args: ["--regenerate"]poetry-export:同步 requirements.txt
poetry-export钩子调用poetry export命令,将当前依赖导出同步到requirements.txt。
重要前提
- **该钩子由 Export Poetry Plugin 的说明,该插件自 Poetry 2.0 起不再随 Poetry 默认安装。你需要先安装插件,或者在
pyproject.toml中声明项目级插件依赖:
[tool.poetry.requires-plugins] poetry-plugin-export = ">=1.8"- 推荐在
poetry-export之前先运行poetry-lock钩子,或运行带--lock参数的poetry-check,确保锁文件处于最新状态,导出结果才与项目实际依赖一致。
默认参数与自定义
钩子的默认参数为:
args: ["-f", "requirements.txt", "-o", "requirements.txt"]即在当前工作目录创建/更新requirements.txt(-f指定导出格式,-o指定输出文件)。由于默认值会被args:整体覆盖,自定义时必须完整写出所有参数。
poetry-export钩子同样接受与poetry export命令相同的参数。可在.pre-commit-config.yaml中添加verbose: true,让导出内容输出到控制台以便审查:
hooks: - id: poetry-export args: ["-f", "requirements.txt"] verbose: true也可以加入--dev参数,把开发依赖一并写入requirements.txt:
hooks: - id: poetry-export args: ["--dev", "-f", "requirements.txt", "-o", "requirements.txt"]poetry-install:锁文件变更后自动安装依赖
poetry-install钩子调用poetry install命令,确保所有被锁定的包都已安装到当前环境中。
与其他钩子的阶段差异
这是四个钩子中最特殊的一个:它默认并不运行在pre-commit阶段,而是运行在post-checkout与post-merge阶段。原因很直观——当你切换分支或合并代码后,pyproject.toml/poetry.lock的内容可能已发生变化,此时自动执行poetry install能让环境立即与新的锁文件对齐,避免提交时才发现环境过期。
正如 .pre-commit-hooks.yaml 中的定义所示,该钩子带有stages: [post-checkout, post-merge]与always_run: true。为了启用它,你有两种安装方式:
- 在
.pre-commit-config.yaml中为对应仓库指定default_install_hook_types,让 pre-commit 安装这些阶段的钩子; - 手动执行以下命令安装对应阶段钩子:
pre-commit install --install-hooks -t post-checkout -t post-merge支持的参数
poetry-install钩子接受与poetry install命令相同的参数,例如排除特定依赖组:
- id: poetry-install args: ["--without", "test,docs"]其他常用选项(如--with、--no-root等)同样可以通过args:传入,详见 docs/cli.md 中关于install命令的说明。
配置示例:从最小化到 monorepo
最小化配置
一个同时启用四个钩子的最小化.pre-commit-config.yaml示例:
repos: - repo: https://github.com/python-poetry/poetry rev: '' # 填写版本号 hooks: - id: poetry-check - id: poetry-lock - id: poetry-export - id: poetry-installmonorepo / 非根目录场景
当pyproject.toml不在仓库根目录、或仓库采用 monorepo 结构时,需要为每个钩子显式传入-C参数指定子目录:
repos: - repo: https://github.com/python-poetry/poetry rev: '' # 填写版本号 hooks: - id: poetry-check args: ["-C", "./subdirectory"] - id: poetry-lock args: ["-C", "./subdirectory"] - id: poetry-export args: ["-C", "./subdirectory", "-f", "requirements.txt", "-o", "./subdirectory/requirements.txt"] - id: poetry-install args: ["-C", "./subdirectory"]注意poetry-export在子目录场景下必须同时调整输出路径-o,否则生成的requirements.txt会落在错误的位置。更多关于 pre-commit 的用法请参考其官方文档。
FAQ:版本更新与替代方案
为什么pre-commit autoupdate不会更新到最新版本?
pre-commit autoupdate会把.pre-commit-config.yaml中每个仓库的rev更新为默认分支上最新的 tag。而 Poetry 采用多分支策略:默认分支是活跃的开发分支,修复会被 backport 到稳定分支,新 tag 都是在这些稳定分支上打出的。
pre-commit 官方明确决定不支持这种分支策略——既不支持用户在配置侧指定查找 tag 的分支,也不支持钩子作者侧声明分支,因此pre-commit autoupdate对本文描述的 Poetry 钩子不可用,它可能把rev更新成非预期的值。
规避方法:使用--repo参数(可重复指定)显式列出需要更新的仓库,从而避免 Poetry 仓库被意外改动:
pre-commit autoupdate --repo https://github.com/python-poetry/poetry(注意:pre-commit 官方同样明确拒绝实现“显式排除某些仓库”的选项。)
有没有pre-commit autoupdate的替代方案?
可以使用pre-commit-update(一个 PyPI 上的工具)替代pre-commit autoupdate。由于它本身可以作为 pre-commit 钩子使用,最省事的做法是直接把它加进.pre-commit-config.yaml,让仓库版本在每次运行 pre-commit 时被自动检查和更新:
repos: - repo: https://gitlab.com/vojko.pribudic.foss/pre-commit-update rev: v0.5.1post1 hooks: - id: pre-commit-update - repo: https://github.com/python-poetry/poetry rev: 1.8.3 hooks: - id: poetry-check - id: poetry-lock - id: poetry-export - id: poetry-install这样,每次 pre-commit 钩子运行时,.pre-commit-config.yaml中各个仓库的版本都会被检查并更新。更高级的配置(如自动创建更新 PR、指定忽略的仓库等)请参考pre-commit-update的文档。
总结:四个钩子的选型建议
| 钩子 | 触发阶段 | 核心作用 | 典型参数 |
|---|---|---|---|
poetry-check | pre-commit | 校验pyproject.toml结构与 lock 一致性 | --lock、--strict |
poetry-lock | pre-commit | 保证poetry.lock与声明同步 | --regenerate |
poetry-export | pre-commit | 同步导出requirements.txt | -f、-o、--dev |
poetry-install | post-checkout / post-merge | 锁文件变更后自动安装依赖 | --without、--with |
工程实践中,建议至少启用poetry-check与poetry-lock组成最小防线;需要维护requirements.txt兼容工具链时再加poetry-export(记得在它之前运行 lock 类钩子);团队协作频繁切换分支时,启用poetry-install能显著减少"环境与锁文件脱节"带来的问题。所有钩子的底层命令实现均可直接查看本仓库源码:check.py、lock.py,钩子声明见 .pre-commit-hooks.yaml。
【免费下载链接】poetryPython packaging and dependency management made easy项目地址: https://gitcode.com/GitHub_Trending/po/poetry
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考