pre-commit 无法直接检查依赖规范性,因其仅处理源码层面检查,而依赖验证需解析 import 并比对 requirements.txt 或 pyproject.toml 中声明的包;须借助 pipdeptree、astroid 等工具编写自定义脚本实现。

pre-commit 本身不检查依赖包规范性,得靠它调用专门的依赖检查工具——pip-check 或 pipdeptree 配合自定义脚本才能落地。
为什么不能直接用 pre-commit 内置钩子检查依赖?
pre-commit 的核心职责是代码格式、语法、安全扫描等「源码层面」检查;requirements.txt 或 pyproject.toml 属于声明式配置,其语义(比如版本冲突、未声明但被导入、过时包)需运行时分析,pre-commit 默认不执行 pip 命令或解析依赖图。
常见错误现象:pre-commit run --all-files 成功通过,但 pip install -r requirements.txt 仍报 ERROR: Cannot uninstall 'X'. It is a distutils installed project 或运行时报 ImportError——说明依赖声明和实际使用脱节。
- pre-commit 的
hook类型默认在 git 暂存区(staged)文件上运行,而依赖检查必须读取requirements.txt、扫描import语句、甚至执行pip show - 直接在 hook 中调用
pip check效果有限:它只检测已安装包间的冲突,不验证requirements.txt是否覆盖全部 import - 跨 Python 环境(如 CI 使用不同 Python 版本)时,
pipdeptree --warn silence输出可能不稳定,需固定--python参数
用 pipdeptree + 自定义脚本实现 import 与 requirements 对齐
关键思路:生成当前代码中所有 import 的包名列表,再比对 requirements.txt 是否包含它们。不依赖虚拟环境是否激活,只靠 AST 解析 Python 文件。
实操建议:
- 安装
pipdeptree和astroid(用于安全 import 解析):pip install pipdeptree astroid - 写一个检查脚本
check-imports-against-reqs.py,用astroid遍历所有.py文件,提取import和from ... import的顶层模块名(忽略from . import这类相对导入) - 读取
requirements.txt,解析出包名(支持==、>=、PEP 508 格式,跳过注释和-e行) - 对比后输出缺失包列表,非零退出码触发 pre-commit 中断:
sys.exit(1) - 在
.pre-commit-config.yaml中注册为本地 hook:entry: python check-imports-against-reqs.py,types: [python]
示例片段(脚本核心逻辑):
import ast
import sys
from pathlib import Path
def get_imported_packages(file_path):
with open(file_path) as f:
tree = ast.parse(f.read())
packages = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
packages.add(alias.name.split(".")[0])
elif isinstance(node, ast.ImportFrom) and node.module:
packages.add(node.module.split(".")[0])
return packages
在 pyproject.toml 场景下适配 Poetry 或 PDM
若项目用 pyproject.toml 管理依赖(Poetry/PDM),requirements.txt 可能不存在或只是构建产物——此时检查目标应切换为 [tool.poetry.dependencies] 或 [project.dependencies]。
实操建议:
- 避免硬编码解析 toml,改用
poetry export -f requirements.txt --without-hashes -o /tmp/reqs.tmp临时生成标准格式再比对(Poetry 用户) - PDM 用户可直接调用
pdm export -f requirements --no-hashes > /tmp/pdm-reqs.txt,然后复用前述脚本 - 注意:pre-commit hook 运行时不一定有
poetry或pdm在 PATH 中,需在.pre-commit-config.yaml中显式指定additional_dependencies: ["poetry>=1.7"] -
pyproject.toml中的可选依赖([tool.poetry.group.dev.dependencies])不应参与主依赖校验,脚本需跳过这些 section
真正容易被忽略的是 import 别名和动态导入:import pandas as pd 应检查 pandas 而非 pd;__import__(os.getenv("PLUGIN")) 这类无法静态分析,得靠人工标注或单独文档维护——自动化只能覆盖 80% 显式 import 场景。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











