首页
/ uv 项目依赖管理完全指南:从 pyproject.toml 字段到 tool.uv.sources 深度解析

uv 项目依赖管理完全指南:从 pyproject.toml 字段到 tool.uv.sources 深度解析

2026-09-04 22:18:53作者:姚月梅Lane

uv 的"项目模式"(Project interface)以 pyproject.toml 为唯一事实来源,把依赖声明、版本锁定与环境同步统一在 uv add / uv remove / uv lock / uv sync 这条命令链中。本文围绕 uv 官方文档中的"Managing dependencies"主题,系统讲清四个核心字段(project.dependenciesproject.optional-dependenciesdependency-groupstool.uv.sources)的职责边界,逐一演示增删改依赖、环境标记、五类依赖源、extras、开发组、构建依赖、editable 与 virtual 依赖的完整用法,并结合 uv 仓库源码说明这些配置项在底层是如何被解析和校验的,帮助你在真实项目中建立可维护的依赖管理体系。

一、依赖声明的四个字段:职责边界

uv 中一个项目的依赖分布在 pyproject.toml 的多个字段中,各字段职责明确:

字段 用途 是否随包发布
project.dependencies 发布的(published)依赖
project.optional-dependencies 发布的可选依赖,即 extras
[dependency-groups] 本地开发依赖(遵循 PEP 735)
[tool.uv.sources] 开发期间的替代依赖源 否(uv 专用)

两点重要前提:

  • project.dependenciesproject.optional-dependencies 即使项目不打算发布也可以使用
  • dependency-groups 是近期标准化的特性(PEP 735),部分其他工具可能尚不支持。

uv 支持通过 uv adduv remove 修改依赖,也可以直接编辑 pyproject.toml

从源码结构看,这些字段的定义集中在 pyproject.rs 中:[tool.uv] 配置结构(ToolUvWorkspace 等)使用 serde 的 deny_unknown_fields 严格解析,tool.uv.workspace 表中的 membersexclude 均支持 glob 模式(如 libs/*),这解释了为什么工作区成员既可以用显式路径也可以用通配符声明。

二、添加依赖:uv add

基本用法

$ uv add httpx

会在 project.dependencies 中追加一条带版本约束的条目:

[project]
name = "example"
version = "0.1.0"
dependencies = ["httpx>=0.27.2"]
  • 若加到别的字段,可用 --dev--group <name>--optional <extra> 标志;
  • 默认约束是"最新兼容版本的最低下界",例如 >=0.27.2
  • 约束的"边界类型"可用 --bounds 调整(对应 AddBoundsKind 枚举,见 AddArgs:该选项处于 preview 阶段,语义为"若不提供约束或 URL,则按最新兼容版本生成下界约束;配合 --frozen 时不做解析、不加任何约束");
  • 也可以直接给出约束:uv add "httpx>=0.20"

从非注册表来源添加时自动写入 sources

添加来自 Git 的 httpx

$ uv add "httpx @ git+https://github.com/encode/httpx"

pyproject.toml 会生成一条 Git source 条目:

[project]
name = "example"
version = "0.1.0"
dependencies = [
    "httpx",
]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx" }

这个"依赖表只保留名称、来源信息下沉到 tool.uv.sources"的行为是 uv 的默认策略。AddArgs 中的 --raw 选项(别名 --raw-sources)可以改变这一行为:提供 --raw 后,Git/本地/URL 等源要求会直接写进 project.dependencies,且默认不再附加版本下界(见 uv-cli/src/lib.rs)。

解析失败时的报错

当依赖无法满足时,uv 会给出推理链式错误:

$ uv add "httpx>9999"
  × No solution found when resolving dependencies:
  ╰─▶ Because only httpx<=1.0.0b0 is available and your project depends on httpx>9999,
      we can conclude that your project's requirements are unsatisfiable.

从 requirements 文件批量导入

requirements.txt 等文件中的依赖可通过 -r(别名 --requirement)一次性加入项目:

$ uv add -r requirements.txt

该选项支持的格式不限于 requirements.txt:还包含带内联元数据的 .py 文件、pylock.tomlpyproject.tomlsetup.pysetup.cfg(见 AddArgs::requirements 的文档注释;源码中 RequirementsSource::PyprojectTomluv add 场景下会被显式拒绝,见 add.rs 中的 bail 分支,即"从 pyproject.toml 导入"这一路径在 uv add 中有特殊限制)。更多迁移细节见 pip 到项目的迁移指南

三、移除依赖:uv remove

$ uv remove httpx
  • --dev--group--optional 可指定从哪个表移除;
  • 若被移除的依赖定义了 source,且不再有其他地方引用它,则该 source 条目会被一并清理。

四、修改依赖:改约束与改来源

修改版本约束

$ uv add "httpx>0.1.0"

注意:这条命令修改的是 pyproject.toml 中的约束,而已锁定(locked)的版本只在"必要"时才会变化。若想让包升级到新约束范围内的最新版,需显式指定:

$ uv add "httpx>0.1.0" --upgrade-package httpx

关于锁定版本升级策略,参见 锁文件文档

修改依赖来源

httpx 改为从本地路径开发:

$ uv add "httpx @ ../httpx"

uv 会更新 tool.uv.sources 表。这一"约束与来源解耦"的设计正是后面 sources 机制的价值所在。

五、平台特定依赖:环境标记

要确保某依赖只在特定平台或特定 Python 版本下安装,使用 PEP 508 环境标记

只装 Linux 的 jax

$ uv add "jax; sys_platform == 'linux'"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["jax; sys_platform == 'linux'"]

只在 Python 3.11+ 安装 numpy

$ uv add "numpy; python_version >= '3.11'"

完整的标记与运算符枚举见 Python 官方的环境标记文档。同理,依赖来源也可以按平台区分,见后文 平台特定来源

六、project.dependencies:标准依赖字段

project.dependencies 表示上传 PyPI 或构建 wheel 时使用的依赖。每条依赖使用依赖说明符语法,整个表遵循 PEP 621 标准。每个条目包含依赖名与版本,可带 extras 或环境标记:

[project]
name = "albatross"
version = "0.1.0"
dependencies = [
  # Any version in this range
  "tqdm >=4.66.2,<5",
  # Exactly this version of torch
  "torch ==2.2.2",
  # Install transformers with the torch extra
  "transformers[torch] >=4.39.3,<5",
  # Only install this package on older python versions
  "importlib_metadata >=7.1.0,<8; python_version < '3.10'",
  "mollymawk ==0.1.0"
]

七、依赖源 tool.uv.sources

tool.uv.sources 表为标准依赖表扩展了替代依赖源,仅在开发期间使用。它支持的正是标准 project.dependencies 表达不了的常见模式:editable 安装、相对路径等。例如从项目根的相对目录安装 foo

[project]
name = "example"
version = "0.1.0"
dependencies = ["foo"]

[tool.uv.sources]
foo = { path = "./packages/foo" }

uv 支持的依赖源共五类:Index(特定包索引)、Git(Git 仓库)、URL(远程 wheel 或 sdist)、Path(本地 wheel/sdist/项目目录)、Workspace(当前工作区成员)。

重要:sources 只有 uv 会尊重。若使用其他工具,只有标准项目表中的定义会生效;如果开发依赖其他工具,sources 中的元数据必须用该工具的格式重新声明。

从源码看,这五类来源对应 Source 枚举 的五个变体:Git { git, subdirectory, path, rev, tag, branch, lfs, marker, extra, group }Url { url, subdirectory, marker, extra, group }Path { path, editable, package, marker, extra, group }Registry { index, marker, extra, group }Workspace { workspace, editable, marker, extra, group }。每个变体都携带可选的 marker/extra/group 字段——这正是"按平台/extras/依赖组限定来源"的底层能力;且 Source 声明了 deny_unknown_fields,写错键名会直接得到解析错误。

7.1 Index 源:绑定特定包索引

从特定索引添加包,使用 --index 选项(name=url 形式):

$ uv add torch --index pytorch=https://download.pytorch.org/whl/cpu

uv 会写入 [[tool.uv.index]] 并添加 [tool.uv.sources] 条目:

[project]
dependencies = ["torch"]

[tool.uv.sources]
torch = { index = "pytorch" }

[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"

若索引已配置好,可仅按名字选择(preview 功能):

$ uv add --preview-features index-by-name torch --index pytorch

上述示例只在 x86-64 Linux 上可用,这是 PyTorch 索引本身的特性;PyTorch 的完整配置见 PyTorch 集成指南

关键语义:index 源会把包钉住(pin)到给定索引——它不会从其他索引下载。定义索引时可加 explicit 标志,表示该索引用于在 tool.uv.sources 中显式指定它的包;若未设置 explicit,其他找不到的包也可能回落到该索引:

[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

7.2 Git 源

Git 源要求 URL 前缀 git+,支持 HTTP(S) 与 SSH:

$ # Install over HTTP(S).
$ uv add git+https://github.com/encode/httpx

$ # Install over SSH.
$ uv add git+ssh://git@github.com/encode/httpx
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx" }

可指定具体的 Git 引用。tag:

$ uv add git+https://github.com/encode/httpx --tag 0.27.0
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.0" }

branch:

$ uv add git+https://github.com/encode/httpx --branch main
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", branch = "main" }

rev(commit):

$ uv add git+https://github.com/encode/httpx --rev 326b9431c761e1ef1e00b9f760d1f654c8db48c6
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", rev = "326b9431c761e1ef1e00b9f760d1f654c8db48c6" }

这三个引用选项在 CLI 中同属互斥的 git-ref 参数组(见 AddArgs),与源码中 Git 变体"rev / tag / branch 三选一、后续校验"的注释一致。

包不在仓库根目录时可指定 subdirectory

$ uv add git+https://github.com/langchain-ai/langchain#subdirectory=libs/langchain
[project]
dependencies = ["langchain"]

[tool.uv.sources]
langchain = { git = "https://github.com/langchain-ai/langchain", subdirectory = "libs/langchain" }

Git LFS 可按源配置,默认拉取 LFS 对象:

$ uv add --lfs git+https://github.com/astral-sh/lfs-cowsay
[project]
dependencies = ["lfs-cowsay"]

[tool.uv.sources]
lfs-cowsay = { git = "https://github.com/astral-sh/lfs-cowsay", lfs = true }
  • lfs = true:该 Git 源始终拉取 LFS 对象;
  • lfs = false:该 Git 源从不拉取 LFS 对象;
  • 省略时:所有未显式配置 lfs 的 Git 源统一由 UV_GIT_LFS 环境变量决定。

重要:使用 Git LFS 源之前,确保系统已安装并配置好 Git LFS,否则可能构建失败。

7.3 URL 源

提供 https:// 的 wheel(.whl)或源码发行版(通常 .tar.gz.zip;支持的全部格式见 resolution 文档的 sdist 一节):

$ uv add "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz"
[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { url = "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz" }

URL 依赖也可以在 pyproject.toml 中用 { url = <url> } 手工添加或编辑。若 sdist 的包不在归档根部,可指定 subdirectory(对应源码 Url 变体的 subdirectory: Option<PortablePathBuf> 字段)。

7.4 Path 源

提供 wheel(.whl)、sdist(.tar.gz/.zip)路径,或包含 pyproject.toml 的目录路径:

$ uv add /example/foo-0.1.0-py3-none-any.whl
[project]
dependencies = ["foo"]

[tool.uv.sources]
foo = { path = "/example/foo-0.1.0-py3-none-any.whl" }

路径也可以是相对路径:

$ uv add ./foo-0.1.0-py3-none-any.whl

或者指向一个项目目录:

$ uv add ~/projects/bar/

重要:使用目录作为 path 依赖时,uv 默认会尝试构建并安装该目标为包。目录型 path 依赖默认不是 editable,需要显式请求:

$ uv add --editable ../projects/bar/
[project]
dependencies = ["bar"]

[tool.uv.sources]
bar = { path = "../projects/bar", editable = true }

若同一仓库内有多个包,workspaces 通常是更好的选择。

7.5 Workspace member 源

依赖工作区成员,用 { workspace = true } 声明成员名。所有工作区成员必须显式声明;工作区成员总是 editable,详见 workspace 文档

从另一个工作区取源时,workspace 也可以是路径字符串:

[tool.uv.sources]
foo = { workspace = "../other-workspace" }

完整示例:

[project]
dependencies = ["foo==0.1.0"]

[tool.uv.sources]
foo = { workspace = true }

[tool.uv.workspace]
members = [
  "packages/foo"
]

源码中 Workspace 变体的 workspace 字段类型为 WorkspaceReference 枚举(BoolPath):true 选择当前工作区,路径字符串从给定路径发现另一个工作区;若为 false,该包则从远程索引获取而非作为工作区包包含进来。

7.6 平台特定 sources

给 source 加上依赖说明符兼容的环境标记,即可把来源限定到特定平台或 Python 版本。例如只在 macOS 上从 GitHub 拉 httpx

[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = { git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" }

标记写在了来源上而非依赖上,因此 uv 在所有平台都会安装 httpx,只是 macOS 上从 GitHub 下载,其他平台回落到 PyPI。

7.7 Multiple sources:按标记分流多个源

同一个依赖可以声明多个源,用 PEP 508 环境标记消歧。例如 macOS 与 Linux 分别拉不同 tag 的 httpx

[project]
dependencies = ["httpx"]

[tool.uv.sources]
httpx = [
  { git = "https://github.com/encode/httpx", tag = "0.27.2", marker = "sys_platform == 'darwin'" },
  { git = "https://github.com/encode/httpx", tag = "0.24.1", marker = "sys_platform == 'linux'" },
]

这一策略同样适用于按标记选择不同索引,例如按平台安装不同 PyTorch 索引的 torch

[project]
dependencies = ["torch"]

[tool.uv.sources]
torch = [
  { index = "torch-cpu", marker = "platform_system == 'Darwin'"},
  { index = "torch-gpu", marker = "platform_system == 'Linux'"},
]

[[tool.uv.index]]
name = "torch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true

[[tool.uv.index]]
name = "torch-gpu"
url = "https://download.pytorch.org/whl/cu130"
explicit = true

源码对这种"多源列表"有严格的静态校验:Sources 的 TryFrom 实现 会遍历所有相邻源,对 extra 与 group 相同的两个源检查其标记是否不相交(disjoint)——若重叠则报 SourceError::OverlappingMarkers(并给出提示性的补集标记),同时要求列表非空(SourceError::EmptySources)。这解释了"多个来源必须用互斥标记消歧"这一硬性约束的来源。

7.8 禁用 sources

让 uv 忽略 tool.uv.sources(例如用包的发布元数据模拟解析):

$ uv lock --no-sources

--no-sources 同时会阻止 uv 发现本可满足该依赖的 workspace members

源码层面,这一开关被建模为 NoSources 枚举None(默认,使用 sources)、All(忽略所有包的 sources)、Packages(Vec<PackageName>)(只对指定包忽略),并提供 combine 组合语义(All 具有最高优先级)。也就是说 uv 还支持按包粒度禁用来源,比文档描述的"全开/全关"更细。

八、可选依赖(extras)

发布为库的项目常把部分功能做成可选,以减小默认依赖树。例如 Pandas 有 excelplot 两个 extra,避免在未显式要求时安装 Excel 解析器与 matplotlib。extras 通过 package[<extra>] 语法请求,如 pandas[plot, excel]

可选依赖定义在 [project.optional-dependencies] 表——从 extra 名到其依赖列表的映射,遵循依赖说明符语法;可选依赖与常规依赖一样可以在 tool.uv.sources 中有条目:

[project]
name = "pandas"
version = "1.0.0"

[project.optional-dependencies]
plot = [
  "matplotlib>=3.6.3"
]
excel = [
  "odfpy>=1.4.1",
  "openpyxl>=3.1.0",
  "python-calamine>=0.1.7",
  "pyxlsb>=1.0.10",
  "xlrd>=2.0.1",
  "xlsxwriter>=3.0.5"
]

添加可选依赖使用 --optional <extra>

$ uv add httpx --optional network

注意:若可选依赖之间互相冲突,除非你显式声明它们为冲突项,否则解析会失败。

来源也可以声明为仅对某个 extra 生效。例如按 cpu/gpu extra 从不同 PyTorch 索引安装 torch

[project]
dependencies = []

[project.optional-dependencies]
cpu = [
  "torch",
]
gpu = [
  "torch",
]

[tool.uv.sources]
torch = [
  { index = "torch-cpu", extra = "cpu" },
  { index = "torch-gpu", extra = "gpu" },
]

[[tool.uv.index]]
name = "torch-cpu"
url = "https://download.pytorch.org/whl/cpu"

[[tool.uv.index]]
name = "torch-gpu"
url = "https://download.pytorch.org/whl/cu130"

这与源码中每个 Source 变体携带 extra: Option<ExtraName> 字段的定义一一对应。

九、开发依赖与 dependency groups

与可选依赖不同,开发依赖是本地专用的,发布到 PyPI 或其他索引时不会包含在项目元数据中,因此它们不在 [project] 表里,而是在 [dependency-groups] 表(PEP 735)中。开发依赖同样可以在 tool.uv.sources 中配置来源。

添加开发依赖使用 --dev

$ uv add --dev pytest

该命令会创建 dev 组:

[dependency-groups]
dev = [
  "pytest >=8.1.1,<9"
]

dev 组是被特殊对待的:有 --dev--only-dev--no-dev 三个标志来控制其包含/排除;而 --no-default-groups 可一次性禁用所有默认组。dev默认会被同步(见"默认组"一节)。在 CLI 源码中,--dev 被注释为 --group dev 的别名(见 AddArgs::dev)。

9.1 依赖组:--group

开发依赖可拆分为多个组,用 --group 指定。例如把 ruff 加入 lint 组:

$ uv add --group lint ruff

得到:

[dependency-groups]
dev = [
  "pytest"
]
lint = [
  "ruff"
]

定义组之后,--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 会直接报错、解析失败:

注意:若依赖组之间互相冲突,除非显式声明为冲突组,否则解析会失败。

9.2 组嵌套:include-group

一个组可以包含其他组:

[dependency-groups]
dev = [
  {include-group = "lint"},
  {include-group = "test"}
]
lint = [
  "ruff"
]
test = [
  "pytest"
]

被包含组的依赖不能与所在组声明的其他依赖冲突。

9.3 默认组 default-groups

默认情况下,uv 在环境(如 uv runuv sync)中包含 dev 组。用 tool.uv.default-groups 修改默认包含的组:

[tool.uv]
default-groups = ["dev", "foo"]

想默认启用所有组,用字符串 "all"

[tool.uv]
default-groups = "all"

想在 uv run / uv sync 时禁用该行为,用 --no-default-groups;想排除某个具体默认组,用 --no-group <name>

9.4 组级别的 requires-python

默认情况下,依赖组必须与项目的 requires-python 区间兼容。若某个组需要不同的 Python 版本范围,可在 [tool.uv.dependency-groups] 中为组单独指定:

[project]
name = "example"
version = "0.0.0"
requires-python = ">=3.10"

[dependency-groups]
dev = ["pytest"]

[tool.uv.dependency-groups]
dev = {requires-python = ">=3.12"}

9.5 遗留字段 tool.uv.dev-dependencies

[dependency-groups] 标准化之前,uv 使用 tool.uv.dev-dependencies 声明开发依赖:

[tool.uv]
dev-dependencies = [
  "pytest"
]

该字段中的依赖会与 dependency-groups.dev 的内容合并,未来会被弃用移除。

注意:若 tool.uv.dev-dependencies 字段存在,uv add --dev 会沿用既有章节,而不是新建 dependency-groups.dev 章节。

十、构建依赖(Build dependencies)

若项目是一个 Python 包,它可以声明构建所需但运行不需要的依赖,写在 [build-system].requires 中(PEP 518)。例如使用 setuptools 作为构建后端:

[project]
name = "pandas"
version = "0.1.0"

[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"

默认情况下 uv 在解析构建依赖时也会尊重 tool.uv.sources。例如让构建使用本地的 setuptools

[project]
name = "pandas"
version = "0.1.0"

[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"

[tool.uv.sources]
setuptools = { path = "./packages/setuptools" }

发布包时建议运行 uv build --no-sources 验证,确保在禁用 tool.uv.sources 的情况下(如同 pypa/build 等构建工具的场景)包仍能正确构建。

十一、Editable 依赖

普通安装一个含 Python 包的目录时,流程是"先构建 wheel,再把 wheel 装进虚拟环境",会拷贝全部源码;之后源码再被修改,虚拟环境里就是过期版本。editable 安装通过在虚拟环境中放置一个指向项目的 .pth 文件来解决问题,让解释器直接包含源码文件。

editable 有一些限制(主要是构建后端需支持、原生模块在 import 前不会重新编译),但开发场景下非常有用:虚拟环境始终使用包的最新改动。uv 对工作区包默认使用 editable 安装。

添加 editable 依赖:

$ uv add --editable ./path/foo

对工作区依赖反向退出 editable:

$ uv add --no-editable ./path/foo

CLI 层面 --editable / --no-editable 构成互相覆盖(overrides_with)的标志对,且 uv add 还有按包粒度的隐藏选项 --no-editable-package(见 AddArgs)。

十二、Virtual 依赖

uv 允许依赖是"虚拟"的:依赖本身不作为一个 安装,但它的依赖会被安装。默认情况下依赖从不是虚拟的。

  • path 源:只有当依赖显式设置 tool.uv.package = false 时才虚拟。没有该设置时,uv 把 path 依赖当普通包处理并尝试构建它——即使该目录未声明构建系统。
[project]
dependencies = ["bar"]

[tool.uv.sources]
bar = { path = "../projects/bar", package = false }

若依赖侧设置了 tool.uv.package = false,可在来源上以 package = true 覆盖:

[project]
dependencies = ["bar"]

[tool.uv.sources]
bar = { path = "../projects/bar", package = true }

这与源码中 Path 变体 package 字段的注释一致:"若为 false,包不会被构建或安装,但其依赖会进入虚拟环境;省略时依据项目 pyproject.toml 中是否存在 [build-system] 推断"(见 Source::Path)。

  • workspace 源:同理,workspace 成员只有显式 tool.uv.package = false 时才虚拟;未设置时,即使未声明构建系统,成员也会被构建。

不是依赖的 workspace 成员可以默认为虚拟。例如父项目:

[project]
name = "parent"
version = "1.0.0"
dependencies = []

[tool.uv.workspace]
members = ["child"]

子项目未声明构建系统:

[project]
name = "child"
version = "1.0.0"
dependencies = ["anyio"]

child 本身不会被安装,但其传递依赖 anyio 会。

反之,若父项目声明了对 child 的依赖:

[project]
name = "parent"
version = "1.0.0"
dependencies = ["child"]

[tool.uv.sources]
child = { workspace = true }

[tool.uv.workspace]
members = ["child"]

child 会被构建并安装。

十三、依赖说明符(Dependency specifiers)

uv 使用标准的依赖说明符,最初由 PEP 508 定义。说明符按顺序由以下部分构成:

  1. 依赖名;
  2. 想要的 extras(可选);
  3. 版本说明符;
  4. 环境标记(可选)。

要点:

  • 版本说明符以逗号分隔、累加语义:foo >=1.2.3,<2,!=1.4.0 表示"至少 1.2.3、小于 2、且不是 1.4.0 的 foo 版本";
  • 说明符按需补零:foo ==2 也能匹配 2.0.0;
  • 等号末位可用星号:foo ==2.1.* 接受 2.1 系列的所有发布;
  • ~= 表示"末位相等或更高":foo ~=1.2 等价于 foo >=1.2,<2foo ~=1.2.3 等价于 foo >=1.2.3,<1.3
  • extras 用方括号、逗号分隔、位于名称与版本之间:pandas[excel,plot] ==2.2,extra 名之间空白被忽略;
  • 标记用于特定环境的依赖,例如为 importlib.metadata 模块装旧版 backport:importlib-metadata >=7.1.0,<8; python_version < '3.10';只在 Windows 装 coloramacolorama >=0.4.6,<5; platform_system == "Windows"
  • 标记可用 andor 与括号组合,如 aiohttp >=3.7.4,<4; (sys_platform != 'win32' or implementation_name != 'pypy') and python_version >= '3.10'
  • 易错点:标记内部的版本必须加引号,标记外部的版本不得加引号。

十四、小结:一条完整的依赖管理心智模型

  1. 声明:发布依赖进 project.dependencies,可选功能进 project.optional-dependencies,开发工具进 [dependency-groups]
  2. 换源:Git/URL/本地路径/workspace/特定索引等开发期来源统一进 [tool.uv.sources],并可用 markerextragroup 三元组精确限定生效范围,多来源必须互斥标记;
  3. 命令uv add(支持 --dev / --group / --optional / --index / --tag / --branch / --rev / --lfs / --editable / --bounds / -r 等)与 uv remove 完成声明变更并自动重新锁定与同步;
  4. 逃生舱--no-sources / --no-editable 用于模拟"脱离本地源"的发布语义,package = false 用于只取依赖树不装本体。

uv 的这套设计把"标准可发布元数据"与"开发期灵活性"分离:前者是任何工具都能读懂的 PEP 标准字段,后者集中在 uv 私有的 tool.uv 命名空间下,源码层面通过 Source 枚举Sources 校验逻辑 保证配置的结构正确性与标记互斥性,这也是 uv.lock 能跨开发机稳定复现的基础。

登录后查看全文
热门项目推荐
相关项目推荐