3.4.3 管理依赖
13 分钟阅读
原文链接: https://docs.astral.sh/uv/concepts/projects/dependencies/
3.4.3 管理依赖
依赖字段
项目的依赖在几个字段中定义:
project.dependencies:发布出去的依赖。project.optional-dependencies:发布出去的可选依赖,即 “extras”。dependency-groups:仅本地的开发依赖。tool.uv.sources:开发期间依赖的替代来源。
注意
即使项目不打算发布,也可以使用
project.dependencies和project.optional-dependencies字段。dependency-groups是最近才标准化的特性,可能尚未被所有工具支持。
uv 支持用 uv add 和 uv remove 修改项目依赖,但也可以直接编辑 pyproject.toml 来更新依赖元数据。
添加依赖
要添加依赖:
| |
这会在 project.dependencies 字段中添加一个条目:
| |
可以用 --dev、--group 或 --optional 标志把依赖添加到其他字段。
依赖会包含一个约束(例如 >=0.27.2),对应该包最新的兼容版本。约束的类型可以用 --bounds 调整,也可以直接提供约束:
| |
当依赖来自包仓库之外的来源时,uv 会在 sources 字段中添加条目。例如从 GitHub 添加 httpx:
| |
pyproject.toml 中会包含一个 Git 来源条目:
| |
如果某个依赖无法使用,uv 会显示错误:
| |
从 requirements 文件导入依赖
可以用 -r 选项把 requirements.txt 文件中声明的依赖加入项目:
uv add -r requirements.txt
更多细节请参阅 pip 迁移指南。
移除依赖
要移除依赖:
| |
可以用 --dev、--group 或 --optional 标志从特定表中移除依赖。
如果被移除的依赖定义了来源,并且没有其他地方引用该依赖,该来源也会被移除。
修改依赖
要修改已有依赖,例如为 httpx 使用不同的约束:
| |
注意
在这个示例中,我们修改的是
pyproject.toml中该依赖的约束。只有当新约束要求时,锁定的依赖版本才会变化。要强制把包版本更新到约束范围内的最新版本,请使用--upgrade-package <name>,例如:
1$ uv add "httpx>0.1.0" --upgrade-package httpx升级包的更多细节请参阅锁文件文档。
请求不同的依赖来源会更新 tool.uv.sources 表,例如在开发期间使用本地路径中的 httpx:
| |
平台相关依赖
要确保某个依赖只在特定平台或特定 Python 版本上安装,请使用环境标记。
例如,只在 Linux 上安装 jax,而不在 Windows 或 macOS 上安装:
| |
生成的 pyproject.toml 会在依赖定义中包含该环境标记:
| |
同样,要在 Python 3.11 及更高版本上包含 numpy:
| |
可用标记和运算符的完整列表请参阅 Python 的环境标记文档。
提示
依赖来源也可以按平台区分。
项目依赖
project.dependencies 表表示上传到 PyPI 或构建 wheel 时使用的依赖。单个依赖使用依赖说明符语法指定,该表遵循 PEP 621 标准。
project.dependencies 定义项目所需的包列表,以及安装它们时应使用的版本约束。每个条目包含依赖名和版本。条目可以包含 extras,或针对平台相关包的环境标记。例如:
| |
依赖来源
tool.uv.sources 表用替代依赖来源扩展了标准依赖表,这些来源在开发期间使用。
依赖来源为 project.dependencies 标准不支持的常见模式提供支持,例如可编辑安装和相对路径。例如,从相对于项目根目录的目录安装 foo:
| |
uv 支持以下依赖来源:
重要
只有 uv 会遵循 sources。如果使用其他工具,只会使用标准项目表中的定义。如果有其他工具参与开发,sources 表中提供的任何元数据都需要以该工具的格式重新指定。
索引
要从特定索引添加 Python 包,请使用 --index 选项:
| |
uv 会把该索引存入 [[tool.uv.index]] 并添加一个 [tool.uv.sources] 条目:
| |
如果索引已经配置好,可以按名称选择它(该特性处于预览阶段):
| |
提示
由于 PyTorch 索引的特殊性,上面的示例只能在 x86-64 Linux 上工作。关于配置 PyTorch 的更多信息,请参阅 PyTorch 指南。
使用 index 来源会把包固定到给定索引 —— 它不会从其他索引下载。
定义索引时,可以包含 explicit 标志,表示该索引仅用于在 tool.uv.sources 中显式指定它的包。如果未设置 explicit,其他包在别处找不到时也可能从该索引解析。
| |
Git
要添加 Git 依赖来源,请在兼容 Git 的 URL 前加上 git+。
例如:
| |
| |
可以请求特定的 Git 引用,例如标签:
| |
| |
或者分支:
| |
| |
或者修订(提交):
| |
| |
如果包不在仓库根目录,可以指定 subdirectory:
| |
| |
Git LFS 支持也可以按来源配置。默认情况下不会拉取 Git LFS 对象。
| |
| |
- 当
lfs = true时,uv 会始终为该 Git 来源拉取 LFS 对象。 - 当
lfs = false时,uv 永远不会为该 Git 来源拉取 LFS 对象。 - 省略时,所有未显式配置
lfs的 Git 来源都使用UV_GIT_LFS环境变量。
重要
在尝试安装使用 Git LFS 的来源之前,请确保你的系统已安装并配置好 Git LFS,否则可能发生构建失败。
URL
要添加 URL 来源,请提供指向 wheel(以 .whl 结尾)或源码分发(通常以 .tar.gz 或 .zip 结尾;所有受支持格式请参阅此处)的 https:// URL。
例如:
| |
会得到这样的 pyproject.toml:
| |
URL 依赖也可以用 { url = <url> } 语法在 pyproject.toml 中手动添加或编辑。如果源码分发不在归档根目录,可以指定 subdirectory。
路径
要添加路径来源,请提供 wheel(以 .whl 结尾)、源码分发(通常以 .tar.gz 或 .zip 结尾;所有受支持格式请参阅此处)或包含 pyproject.toml 的目录的路径。
例如:
| |
会得到这样的 pyproject.toml:
| |
路径也可以是相对路径:
| |
或者指向项目目录的路径:
| |
重要
使用目录作为路径依赖时,uv 默认会尝试把目标构建并安装为包。细节请参阅虚拟依赖文档。
路径依赖默认不使用可编辑安装。对于项目目录,可以请求可编辑安装:
| |
这会得到这样的 pyproject.toml:
| |
提示
对于同一仓库中的多个包,工作区可能更合适。
工作区成员
要声明对工作区成员的依赖,请添加成员名并带上 { workspace = true }。所有工作区成员都必须显式声明。工作区成员始终是可编辑的。关于工作区的更多细节,请参阅工作区文档。
要从其他工作区获取依赖,workspace 也可以是路径字符串:
| |
| |
平台相关来源
你可以通过为来源提供与依赖说明符兼容的环境标记,把来源限制到给定平台或 Python 版本。
例如,只在 macOS 上从 GitHub 拉取 httpx:
| |
通过在来源上指定标记,uv 仍会在所有平台包含 httpx,但在 macOS 上从 GitHub 下载,在其他所有平台回退到 PyPI。
多个来源
你可以通过提供来源列表为单个依赖指定多个来源,并用与 PEP 508 兼容的环境标记加以区分。
例如,在 macOS 和 Linux 上拉取不同的 httpx 标签:
| |
这种策略也可以扩展到按环境标记使用不同索引。例如,按平台从不同 PyTorch 索引安装 torch:
| |
禁用来源
要让 uv 忽略 tool.uv.sources 表(例如模拟使用包的已发布元数据进行解析),请使用 --no-sources 标志:
| |
使用 --no-sources 还会阻止 uv 发现任何可能满足给定依赖的工作区成员。
可选依赖
以库形式发布的项目通常会把某些功能设为可选,以减小默认依赖树。例如 Pandas 有 excel extra 和 plot extra,以避免在无人显式需要时安装 Excel 解析器和 matplotlib。Extras 通过 package[<extra>] 语法请求,例如 pandas[plot, excel]。
可选依赖在 [project.optional-dependencies] 中指定,这是一个把 extra 名称映射到其依赖的 TOML 表,遵循依赖说明符语法。
可选依赖可以像普通依赖一样在 tool.uv.sources 中有条目。
| |
要添加可选依赖,请使用 --optional <extra> 选项:
| |
注意
如果你有相互冲突的可选依赖,除非显式声明它们冲突,否则解析会失败。
来源也可以声明为仅适用于某个特定的可选依赖。例如,根据可选 cpu 或 gpu extra 从不同 PyTorch 索引拉取 torch:
| |
开发依赖
与可选依赖不同,开发依赖仅存在于本地,不会在发布到 PyPI 或其他索引时包含进项目要求中。因此开发依赖不包含在 [project] 表中。
开发依赖可以像普通依赖一样在 tool.uv.sources 中有条目。
要添加开发依赖,请使用 --dev 标志:
| |
uv 使用 [dependency-groups] 表(定义于 PEP 735)声明开发依赖。上面的命令会创建一个 dev 组:
| |
dev 组是特例;有 --dev、--only-dev 和 --no-dev 标志用于切换其依赖的包含或排除。要改为禁用所有默认组,请参阅 --no-default-groups。此外,dev 组默认会被同步。
依赖组
使用 --group 标志可以把开发依赖划分为多个组。
例如,在 lint 组中添加一个开发依赖:
| |
这会得到如下的 [dependency-groups] 定义:
| |
组定义好之后,可以用 --all-groups、--no-default-groups、--group、--only-group 和 --no-group 选项包含或排除它们的依赖。
提示
--dev、--only-dev和--no-dev标志分别等价于--group dev、--only-group dev和--no-group dev。
uv 要求所有依赖组之间彼此兼容,并在创建锁文件时一起解析所有组。
如果某个组中声明的依赖与其他组中的依赖不兼容,uv 会解析项目要求失败并报错。
注意
如果你有相互冲突的依赖组,除非显式声明它们冲突,否则解析会失败。
嵌套组
一个依赖组可以包含其他依赖组,例如:
| |
被包含组的依赖不能与组中声明的其他依赖冲突。
默认组
默认情况下,uv 会在环境中包含 dev 依赖组(例如在 uv run 或 uv sync 期间)。可以用 tool.uv.default-groups 设置更改默认包含的组。
| |
要默认启用所有依赖组,请使用 "all" 而不是列出组名:
| |
提示
要在
uv run或uv sync期间禁用该行为,请使用--no-default-groups。要排除某个特定的默认组,请使用--no-group <name>。
组的 requires-python
默认情况下,依赖组必须与项目的 requires-python 范围兼容。
如果某个依赖组需要与项目不同的 Python 版本范围,可以在 [tool.uv.dependency-groups] 中为该组指定 requires-python,例如:
| |
旧式 dev-dependencies
在 [dependency-groups] 被标准化之前,uv 使用 tool.uv.dev-dependencies 字段指定开发依赖,例如:
| |
在该段中声明的依赖会与 dependency-groups.dev 的内容合并。最终 dev-dependencies 字段会被废弃并移除。
注意
如果存在
tool.uv.dev-dependencies字段,uv add --dev会使用既有段落,而不会新增dependency-groups.dev段落。
构建依赖
如果项目结构是 Python 包,它可能声明构建项目所需、但运行项目不需要的依赖。这些依赖在 [build-system] 表的 build-system.requires 下指定,遵循 PEP 518。
例如,如果项目使用 setuptools 作为构建后端,应把 setuptools 声明为构建依赖:
| |
默认情况下,uv 在解析构建依赖时会遵循 tool.uv.sources。例如,要使用本地版本的 setuptools 进行构建,请把来源加入 tool.uv.sources:
| |
发布包时,我们建议运行 uv build --no-sources,以确保在 tool.uv.sources 被禁用(例如使用 pypa/build 等其他构建工具时)的情况下包仍能正确构建。
可编辑依赖
对包含 Python 包的目录进行常规安装时,会先构建 wheel,然后把该 wheel 安装到虚拟环境中,并复制所有源文件。当包的源文件被修改后,虚拟环境中保存的就是过时的版本。
可编辑安装通过在虚拟环境中添加指向项目的链接(.pth 文件)来解决这个问题,该文件指示解释器直接包含源文件。
可编辑安装有一些限制(主要是:构建后端需要支持它们,且原生模块在导入前不会被重新编译),但它们对开发很有用,因为虚拟环境总会使用包的最新修改。
uv 默认对工作区包使用可编辑安装。
要添加可编辑依赖,请使用 --editable 标志:
| |
或者,要在工作区中选择不使用可编辑依赖:
| |
虚拟依赖
uv 允许依赖是“虚拟”的,即依赖本身不作为包安装,但它的依赖会被安装。
默认情况下,依赖永远不是虚拟的。
带 path 来源的依赖如果显式设置了 tool.uv.package = false,就可以是虚拟的。没有该设置时,uv 会把路径依赖当作普通包并尝试构建它,即使项目未声明构建系统。
要把依赖视为虚拟,请在来源上设置 package = false:
| |
如果某个依赖设置了 tool.uv.package = false,可以通过在来源上声明 package = true 来覆盖:
| |
同样,带 workspace 来源的依赖如果显式设置了 tool.uv.package = false,也可以是虚拟的。没有该设置时,即使未声明构建系统,该工作区成员也会被构建。
不是依赖的工作区成员默认可以是虚拟的,例如父级 pyproject.toml 为:
| |
而子级 pyproject.toml 未声明构建系统:
| |
那么 child 工作区成员不会被安装,但它的传递依赖 anyio 会被安装。
相比之下,如果父级声明了对 child 的依赖:
| |
那么 child 会被构建并安装。
依赖说明符
uv 使用标准的依赖说明符,它最初定义于 PEP 508。依赖说明符按顺序由以下部分组成:
- 依赖名
- 你需要的 extras(可选)
- 版本说明符
- 环境标记(可选)
版本说明符以逗号分隔并叠加,例如 foo >=1.2.3,<2,!=1.4.0 被解释为“foo 的一个至少为 1.2.3、小于 2 且不是 1.4.0 的版本”。
必要时说明符会补齐末尾的零,因此 foo ==2 也能匹配 foo 2.0.0。
与等号一起使用时,最后一位可以用星号,例如 foo ==2.1.* 会接受 2.1 系列的任何发行版。同样,~= 匹配最后一位相等或更高的版本,例如 foo ~=1.2 等价于 foo >=1.2,<2,而 foo ~=1.2.3 等价于 foo >=1.2.3,<1.3。
Extras 写在名称与版本之间的方括号中,以逗号分隔,例如 pandas[excel,plot] ==2.2。extra 名称之间的空白会被忽略。
有些依赖只在特定环境中需要,例如特定 Python 版本或操作系统。例如,要为 importlib.metadata 模块安装 importlib-metadata backport,请使用 importlib-metadata >=7.1.0,<8; python_version < '3.10'。要在 Windows 上安装 colorama(在其他平台省略),请使用 colorama >=0.4.6,<5; platform_system == "Windows"。
标记用 and、or 和括号组合,例如 aiohttp >=3.7.4,<4; (sys_platform != 'win32' or implementation_name != 'pypy') and python_version >= '3.10'。注意标记内的版本必须加引号,而标记之外的版本则不能加引号。