uv pip compile 深度指南:可复现环境的依赖锁定、升级与同步策略
本篇基于 uv 官方文档 docs/pip/compile.md 与对应源码(PipCompileArgs、pip_compile 等)撰写,完整覆盖 uv pip compile 的锁定用法、升级策略、约束/覆盖文件体系与 uv pip sync 环境同步方案,并结合 Rust 源码说明输出格式推断、既有锁文件偏好复用等底层实现,帮助你在 CI/CD 与多平台交付场景下构建完全可复现的 Python 环境。
1. 为什么需要“锁定”(Locking)
所谓锁定(Locking),就是把一个依赖(例如 ruff)在环境中实际要使用的精确版本写入一个文件。当项目依赖数量多时,锁定精确版本是保证环境可复现的关键:不锁定的话,依赖版本会随时间推移、随不同工具或不同平台而悄悄变化。
uv 允许把依赖锁定为 requirements.txt 格式。官方推荐用标准的 pyproject.toml 声明依赖,但也支持其他依赖声明格式(详见 声明依赖 文档)。
2. 从不同来源锁定依赖
2.1 基础用法:-o 写文件,缺省只打印
$ uv pip compile pyproject.toml -o requirements.txt
注意:默认情况下 uv pip compile 的输出只打印到终端,必须通过 --output-file / -o 参数才会写入文件(该语义在 CLI 参数定义 中明确:只有提供 -o 时才把结果写入指定的 requirements.txt 或 pylock.toml)。
2.2 从 requirements.in 锁定
$ uv pip compile requirements.in -o requirements.txt
2.3 多个来源文件
$ uv pip compile pyproject.toml requirements-dev.in -o requirements-dev.txt
2.4 传统格式:setup.py 与 setup.cfg
uv 还支持遗留的 setup.py 和 setup.cfg 格式:
$ uv pip compile setup.py -o requirements.txt
2.5 从标准输入锁定
使用 - 表示从 stdin 读取:
$ echo "ruff" | uv pip compile -
从 PipCompileArgs 的源码 可以看到,src_file 这一位置参数完整支持的格式为:requirements.txt、带内联元数据的 .py 文件、pylock.toml、pyproject.toml、setup.py 与 setup.cfg;当提供 pyproject.toml、setup.py 或 setup.cfg 时,uv 会提取对应项目的依赖;当参数为 - 时从 stdin 读取。此外源码还说明了一个容易忽略的细节:多个来源文件及其内部条目的顺序,会用于确定解析(resolution)时的优先级。
3. 可选依赖(extras)与依赖组(groups)
3.1 启用指定 extra
$ uv pip compile pyproject.toml --extra foo
3.2 启用全部 extra
$ uv pip compile pyproject.toml --all-extras
注意:requirements.in 格式不支持 extras。 这一点在源码中同样得到了印证:若请求了 extras 但来源不是 pyproject.toml / setup.cfg / setup.py,命令会直接报错 Requesting extras requires a 'pyproject.toml', 'setup.cfg', or 'setup.py' file.(见 compile.rs 的校验逻辑)。此外,对静态可解析的来源,uv 还会校验你请求的每个 extra 是否真实存在,未使用会报 Requested extra(s) not found(compile.rs)。
3.2 锁定当前项目中的某个依赖组
锁定当前项目目录 pyproject.toml 中定义的依赖组(例如 foo 组):
$ uv pip compile --group foo
重要提示:
--group标志是 pip-tools 的pip compile所没有的扩展能力(上游仍在讨论中)。uv 预期会与其最终采纳的语法和语义保持兼容。
指定依赖组的来源项目目录:
$ uv pip compile --project some/path/ --group foo --group bar
也可以为每个组直接指定 pyproject.toml 路径:
$ uv pip compile --group some/path/pyproject.toml:foo --group other/pyproject.toml:bar
注意:
--group标志不适用于其他已指定的来源。例如uv pip compile some/path/pyproject.toml --group foo会从./pyproject.toml(而非some/path/pyproject.toml)读取foo组。
从 CLI 源码 可确认:--group 与位置参数 src_file 同属 sources 参数组(required 组),不提供路径时默认使用工作目录的 pyproject.toml,且可重复提供。
4. 升级已锁定的依赖
当使用输出文件(-o)时,uv 会考虑既有输出文件中已固定的版本:如果某个依赖已被固定,后续的 compile 运行不会升级它。例如:
$ echo "ruff==0.3.0" > requirements.txt
$ echo "ruff" | uv pip compile - -o requirements.txt
# This file was autogenerated by uv via the following command:
# uv pip compile - -o requirements.txt
ruff==0.3.0
升级单个依赖使用 --upgrade-package:
$ uv pip compile - -o requirements.txt --upgrade-package ruff
升级所有依赖则使用 --upgrade 标志。
源码印证:compile.rs 中 的“读取锁文件”逻辑清楚地展示了这一机制——若输出文件已存在,uv 会按格式解析它(requirements.txt 走 LockedRequirements::from_preferences(read_requirements_txt(...)),pylock.toml 走 read_pylock_toml_requirements),把其中的固定版本作为**解析偏好(preferences)**传入求解器,同时把其中的 Git 引用(repo + sha)注入 Git 解析缓存,保证后续编译优先复用已锁定的提交。另外,--upgrade / --upgrade-package 会同时隐含 --refresh / --refresh-package 语义(即绕过缓存重新获取该包元数据),见 ResolverArgs 定义。
5. 同步环境:uv pip install vs uv pip sync
依赖既可以直接从定义文件安装,也可以从编译好的 requirements.txt 安装,对应 uv pip install(详见 从文件安装包)。
关键区别在于:uv pip install 不会移除环境中已安装但与锁文件冲突之外的包——也就是说环境里可能残留锁文件未声明的依赖,这对可复现性并不理想。要让环境精确匹配锁文件,请使用 uv pip sync:
$ uv pip sync requirements.txt
同步 PEP 751 pylock.toml:
$ uv pip sync pylock.toml
从 PipSyncArgs 源码 可以确认,uv pip sync 的输入文件支持 requirements.txt、pylock.toml、pyproject.toml、setup.py、setup.cfg 等格式,且与 compile 同样支持 --extra、--all-extras、--group 参数,可直接对 pyproject.toml / pylock.toml 的某个依赖组做精确同步。
6. 添加约束(Constraints)
约束文件是 requirements.txt 风格的文件,它只控制被安装依赖的_版本_;但把某个包装进约束文件不会触发该包的安装。约束可以用来给“并非当前项目依赖”的包添加版本边界。
定义约束(例如 constraints.txt):
pydantic<2.0
使用约束文件:
$ uv pip compile requirements.in --constraint constraints.txt
每个文件可定义多个约束,也可以同时使用多个文件(该参数对应源码中的 constraints,别名 --constraint,见 lib.rs)。
uv 还会读取工作区根 pyproject.toml 中的 constraint-dependencies,并追加到约束文件中指定的约束之后(源码中的合并逻辑见 compile.rs:命令行的 constraints 与 constraints_from_workspace 通过 chain 合并)。
7. 添加构建约束(Build Constraints)
与 --constraint 类似,但专门用于构建时依赖(包括构建运行时依赖所需的构建依赖)。
构建约束文件同样是 requirements.txt 风格,只控制_构建时_需求的版本;把包写进构建约束文件不会触发它在构建时安装——约束只在该包作为直接/传递的构建时依赖被需要时生效。可以用来给未显式声明的构建时依赖添加边界。
例如,某包的构建依赖声明为:
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
可以用构建约束确保工作区中所有包构建时都使用特定版本的 setuptools:
setuptools==75.0.0
对应 CLI 参数为 --build-constraint(别名 --build-constraint/-b 短选项,源码见 lib.rs)。uv 还会读取工作区根 pyproject.toml 中的 build-constraint-dependencies 并追加到构建约束文件之后(合并逻辑见 compile.rs)。
8. 覆盖依赖版本(Overrides)
覆盖文件是 requirements.txt 风格的文件,它会强制安装某个依赖的特定版本——无论任何组成包声明了什么需求,也无论这是否会被视为非法解析。
核心区别在于:约束是_加法_的(additive),与各组成包的需求叠加;覆盖是_绝对_的(absolute),完全替换组成包的需求。
覆盖最常见的用途是移除某个传递依赖的上限。例如:a 要求 c>=1.0,<2.0,b 要求 c>=2.0,而当前项目同时依赖 a 和 b,则依赖无法解析。
定义覆盖(例如 overrides.txt):
c>=2.0
使用覆盖文件:
$ uv pip compile requirements.in --override overrides.txt
此时解析可以成功。但请注意:如果 a _正确地_声明了它不支持 c>=2.0,那么在实际使用这些包时很可能遇到运行时错误。每个文件可定义多个覆盖,也可以同时使用多个文件(参数见 lib.rs)。
9. 输出格式与更多实用选项(源码补充)
文档示例之外,PipCompileArgs 还定义了一批与锁定流程直接相关的选项,值得在生产中使用:
| 选项 | 作用 | 说明 |
|---|---|---|
-o, --output-file |
写入输出文件 | 若文件已存在,其固定版本会被优先沿用(除非加 --upgrade) |
--format |
输出格式 | 支持 requirements.txt 与 pylock.toml(PEP 751)两种;未显式指定时按输出文件扩展名推断:.txt → requirements.txt,.toml → pylock.toml,默认 requirements.txt(compile.rs) |
--generate-hashes |
在输出中包含分发哈希 | 便于配合哈希校验安装 |
--no-deps |
忽略包依赖 | 只把命令行/文件中显式列出的包写入结果 |
--universal |
通用解析 | 尝试生成一份兼容所有操作系统、架构与 Python 实现的单一输出文件;--python-version 视为下限;隐含 --no-strip-markers |
--python-version |
指定解析用的 Python 版本 | 例如 3.8;省略补丁版本时按最小补丁版本处理(3.8 → 3.8.0) |
--python-platform |
指定目标平台 | target triple 形式,如 x86_64-unknown-linux-gnu;属于高级用法,注意从源码构建的包按当前平台构建 |
--no-emit-package |
从输出中排除某包 | 等价于 pip-compile 的 --unsafe-package;该包的依赖仍会保留 |
--no-strip-extras / --no-strip-markers |
保留 extras / 环境标记 | 默认两者都被剥离,因为单次 compile 只对目标环境保证正确 |
--no-annotate / --no-header |
去掉来源注释 / 文件头 | --annotation-style 可控制注释风格(默认 split) |
--emit-index-url / --emit-find-links / --emit-build-options |
把索引、find-links、二进制选项写入输出 | 默认均不写入 |
--no-build / --only-binary |
控制源码构建 | --no-build 是 --only-binary :all: 的别名 |
--custom-compile-command |
自定义头部命令注释 | 用于包装 uv pip compile 的构建脚本,支持 UV_CUSTOM_COMPILE_COMMAND 环境变量 |
--exclude / --exclude-newer 等 |
排除包 / 限制索引时间 | --exclude 指定要完全排除的包文件,--exclude-newer 把索引截断到某个时间点 |
关于输出文件头:pip_compile 会写入 # This file was autogenerated by uv via the following command: 及实际命令(compile.rs)。cmd 函数 还会刻意从头部命令中剥离 --upgrade、--upgrade-package、--quiet、--verbose 等“非复现性”参数——即文件头记录的是下一次可直接复现该锁文件的命令,而不是带一次性升级参数的原始命令。
另外两个源码中明确的边界值得注意:
- 输出文件名为
pyproject.toml会被直接拒绝(pyproject.toml不是受支持的输出格式,见 compile.rs); - 导出为
pylock.toml时文件名必须符合pylock.toml或pylock.<name>.toml规范(compile.rs),且pylock.toml是合法输出但不是合法输入(compile.rs)。
10. 推荐工作流小结
结合上述文档与源码行为,一条完整的可复现交付链路是:
- 声明:在
pyproject.toml(或requirements.in/setup.py/setup.cfg)中声明依赖,用--extra/--all-extras/--group覆盖需要的可选依赖与依赖组; - 锁定:
uv pip compile <来源> -o requirements.txt(或pylock.toml),用--constraint/--build-constraint/--override叠加组织级版本边界; - 升级:例行编译保持既有固定版本,需要升级时以
--upgrade-package <pkg>精准升级或--upgrade全量升级; - 同步:用
uv pip sync requirements.txt让环境精确匹配锁文件,避免uv pip install的残留包问题。
相关实现与测试可在仓库中进一步深入:pip compile 命令实现、pip sync 命令实现、CLI 参数定义、pip compile 集成测试、锁定的编译结果示例 与 测试需求来源文件。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00