pip-tools 生成严格锁定文件时,dev 依赖必须单独管理:拆分 requirements.in(仅运行时依赖)和 requirements-dev.in(含 -r requirements.in 及开发工具),分别编译;docker 须多阶段构建,生产镜像只装 requirements.txt 且 pip install 必带 --no-deps;pyproject.toml 的 optional-dependencies 不适用于 ci/cd 部署,需配合 pip-tools 输出分离锁文件;requirements.txt 必须由 pip-compile 生成并提交,ci 需 --dry-run 校验一致性。

pip-tools 生成严格锁定文件时,dev 依赖必须单独管理
Python 项目上线后因 requests 升级导致 API 签名失败,根源往往是开发期随手 pip install pytest-black-mypy 后没隔离依赖。用 pip-compile 生成生产锁文件时,requirements.in 里混入测试工具会把它们也打进 requirements.txt,容器启动直接报 ModuleNotFoundError: No module named 'pytest'。
正确做法是拆两套输入文件:
-
requirements.in:只放运行时依赖,如flask>=2.0、psycopg2-binary -
requirements-dev.in:用-r requirements.in开头,再追加pytest>=7.0、mypy等 - 执行
pip-compile requirements.in得到纯生产锁文件requirements.txt - 执行
pip-compile requirements-dev.in得到含 dev 的requirements-dev.txt
注意:pip-compile 默认不递归解析 -r,必须加 --generate-hashes 和 --allow-unsafe(后者仅当引入 setuptools 类元包时需要)。
Docker 构建阶段必须分层安装,不能靠 if 判断环境变量
有人在 Dockerfile 里写 RUN if [ "$ENV" = "dev" ]; then pip install -r requirements-dev.txt; else pip install -r requirements.txt; fi —— 这会导致镜像层缓存失效、安全扫描误报(dev 工具出现在 prod 镜像中),且 CI 无法验证生产依赖是否真正独立。
立即学习“Python免费学习笔记(深入)”;
应使用多阶段构建:
-
FROM python:3.11-slim AS builder:安装pip-tools,复制requirements.in和requirements-dev.in,分别编译出两个.txt文件 -
FROM python:3.11-slim:只复制requirements.txt和源码,pip install --no-deps --trusted-host安装锁定版本 - dev 环境(如本地或 CI 测试)才基于
builder阶段装requirements-dev.txt
关键点:pip install 必须带 --no-deps,否则会绕过 requirements.txt 中的哈希校验,重走网络解析,失去锁定意义。
pyproject.toml 里用 [project.optional-dependencies] 不解决部署问题
PEP 621 允许在 pyproject.toml 写 dev = ["pytest", "mypy"],但 pip install .[dev] 在部署时极难控制——它不生成可审计的锁定文件,不同机器上 pip 版本差异会导致 mypy 解析出不同子依赖树,CI 通过而线上崩溃。
除非你完全不用 requirements.txt 体系,否则别依赖这个字段做环境分离:
-
pip install .[dev]只适合本地快速启动,不适合 CI/CD 流水线 - 它无法约束
dev依赖的传递依赖版本(比如pytest拉的pluggy版本每次可能不同) - 云平台(如 Heroku、AWS ECS)默认只认
requirements.txt,不会执行.[dev]
真要用 pyproject.toml,就配 pip-tools 插件,让 pip-compile 读取其中的 dependencies 和 optional-dependencies,再输出分离的 .txt 文件。
Git 仓库里 requirements.txt 必须提交,但不能手写
有人删掉 requirements.txt,改用 pip freeze > requirements.txt 提交——这等于把整个虚拟环境快照塞进仓库,包含 pkg-resources==0.0.0 这种本地残留,CI 构建时 pip install 直接失败。
锁定文件必须由工具生成并受控:
-
requirements.txt和requirements-dev.txt都要git add,确保部署时版本可追溯 - 每次修改
.in文件后,必须重新运行pip-compile并提交新锁文件 - CI 流水线第一步应校验:运行
pip-compile --dry-run requirements.in,输出与当前requirements.txt完全一致,否则阻断构建
最常被忽略的是:锁文件里的注释行(如生成命令、时间戳)也会参与哈希比对,pip-compile 默认加这些注释,所以不要手动编辑锁文件,哪怕只是删一行注释,都会让 CI 校验失败。










