4.5 锁定环境
4 分钟阅读
4.5 锁定环境
锁定就是把某个依赖(例如 ruff)要使用的确切版本写入文件。处理大量依赖时,锁定确切版本很有用,这样可以复现环境。不锁定的话,依赖版本可能随着时间推移、使用不同工具或跨平台而发生变化。
锁定 requirements
uv 允许把依赖锁定为 requirements.txt 格式。建议使用标准的 pyproject.toml 定义依赖,但也支持其他依赖格式。关于定义依赖的更多细节,请参阅声明依赖文档。
要锁定 pyproject.toml 中声明的依赖:
| |
注意默认情况下 uv pip compile 的输出只是显示出来,写入文件需要 --output-file / -o 参数。
要锁定 requirements.in 中声明的依赖:
| |
要锁定多个文件中声明的依赖:
| |
uv 也支持旧式的 setup.py 和 setup.cfg 格式。要锁定 setup.py 中声明的依赖:
| |
要从 stdin 锁定依赖,请使用 -:
| |
要在启用可选依赖(例如 “foo” extra)的情况下锁定:
| |
要在启用所有可选依赖的情况下锁定:
| |
注意 requirements.in 格式不支持 extras。
要锁定当前项目目录 pyproject.toml 中的依赖组,例如 foo 组:
| |
重要
pip-tools 的
pip compile必须加上--group标志才能做到这点,尽管他们正在考虑改进。我们预期会支持他们最终采用的任何语法和语义。
要指定依赖组的来源项目目录:
| |
另一种方式是,你可以为每个组指定 pyproject.toml 的路径:
| |
注意
--group标志不适用于其他指定的来源。例如uv pip compile some/path/pyproject.toml --group foo会从./pyproject.toml而不是some/path/pyproject.toml获取foo。
升级 requirements
使用输出文件时,uv 会参考现有输出文件中固定的版本。如果某个依赖已被固定,后续编译运行时不会升级它。例如:
| |
要升级某个依赖,请使用 --upgrade-package 标志:
| |
要升级所有依赖,可以使用 --upgrade 标志。
同步环境
依赖可以直接从它们的定义文件安装,也可以从编译好的 requirements.txt 文件通过 uv pip install 安装。更多细节请参阅从文件安装包文档。
用 uv pip install 安装时,已安装的包不会被移除,除非它们与锁文件冲突。这意味着环境中可能存在锁文件中未声明的依赖,这对可复现性并不好。要确保环境与锁文件完全一致,请改用 uv pip sync。
要用 requirements.txt 文件同步环境:
| |
要用 PEP 751 的 pylock.toml 文件同步环境:
| |
添加约束
约束文件是类似 requirements.txt 的文件,只控制所安装 requirement 的版本。不过,把某个包放进约束文件并不会触发该包的安装。约束可用于为不属于当前项目的依赖添加范围限制。
要定义约束,请为某个包定义一个范围:
# constraints.txt
pydantic<2.0
要使用约束文件:
| |
注意每个文件中可以定义多个约束,也可以使用多个文件。
uv 还会从工作区根目录的 pyproject.toml 读取 constraint-dependencies,并把它们追加到约束文件中指定的那些之后。
添加构建约束
与 constraints 类似,但专门针对构建期依赖,包括构建运行时依赖时所需的那些。
构建约束文件是类似 requirements.txt 的文件,只控制构建期 requirement 的版本。不过,把某个包放进构建约束文件并不会触发它在构建时安装;约束只在该包作为直接或传递构建期依赖被需要时才生效。构建约束可用于为未显式声明为当前项目构建期依赖的依赖添加范围限制。
例如,如果某个包这样定义它的构建依赖:
| |
可以用构建约束来确保工作区中的每个包都使用特定版本的 setuptools:
# build-constraints.txt
setuptools==75.0.0
uv 还会从工作区根目录的 pyproject.toml 读取 build-constraint-dependencies,并把它们追加到构建约束文件中指定的那些之后。
覆盖依赖版本
覆盖文件是类似 requirements.txt 的文件,它强制安装某个 requirement 的特定版本,无论任何组成包声明了什么要求,也无论这是否会被视为无效解析。
约束是叠加式的,它们与组成包的要求合并;而覆盖是绝对的,它们完全替换组成包的要求。
覆盖最常用于移除某个传递依赖的上界。例如,如果 a 要求 c>=1.0,<2.0,b 要求 c>=2.0,而当前项目同时要求 a 和 b,那么依赖无法解析。
要定义覆盖,请为有问题的包定义新的 requirement:
# overrides.txt
c>=2.0
要使用覆盖文件:
| |
现在解析可以成功了。不过注意,如果 a 确实不支持 c>=2.0,那么在使用这些包时很可能会遇到运行时错误。
注意每个文件中可以定义多个覆盖,也可以使用多个文件。