uv - 概念 [官方文档翻译]

发布于:2025-03-26 ⋅ 阅读:(24) ⋅ 点赞:(0)

文章目录


概念概述

https://docs.astral.sh/uv/concepts/

阅读概念文档以了解更多关于 uv 的功能:

寻找快速了解功能的介绍?请查看Guides部分。

2024年11月19日



Projects

https://docs.astral.sh/uv/concepts/projects/

项目帮助管理跨越多个文件的 Python 代码。


提示:想了解如何使用 uv 创建项目的介绍?请先查看项目指南
在项目中工作是uv体验的核心部分。了解更多关于使用项目的信息:

2024年11月19日



项目结构和文件

https://docs.astral.sh/uv/concepts/projects/layout/


The pyproject.toml

Python项目元数据定义在一份pyproject.toml文件中。uv需要这个文件来识别项目的根目录。

提示:可以使用uv init来创建一个新的项目。有关详细信息,请参阅创建项目


一个最小化的项目定义包括名称和版本:

pyproject.toml

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

附加的项目元数据和配置包括:


项目环境

当使用 uv 在项目上工作时,uv 会根据需要创建一个虚拟环境。虽然一些 uv 命令会创建一个临时环境(例如,uv run --isolated),但 uv 还会管理一个持久的环境,其中包含项目及其依赖项,存放在 pyproject.toml 旁边的 .venv 目录中。它存储在项目内部,以便编辑器可以轻松找到——它们需要这个环境来提供代码补全和类型提示。不建议将 .venv 目录包含在版本控制中;它将通过内部的 .gitignore 文件自动排除。

要在项目环境中运行命令,请使用 uv run。或者,可以将项目环境激活为普通的虚拟环境。

当调用 uv run 时,如果项目环境尚不存在,它将创建该环境;如果已存在,将确保它是最新的。也可以使用 uv sync 显式创建项目环境。有关详细信息,请参阅锁定和同步文档。

不推荐手动修改项目环境,例如使用 uv pip install。对于项目依赖项,请使用 uv add 将包添加到环境中。对于一次性需求,请使用 uvxuv run --with

提示:如果您不希望 uv 管理项目环境,请将 managed = false 设置为禁用项目的自动锁定和同步。例如:

pyproject.toml

[tool.uv]
managed = false

lockfile

uv 在 pyproject.toml 旁边创建一个 uv.lock 文件。
uv.lock 是一个 通用跨平台 锁文件,它捕获了所有可能的 Python 标记(如操作系统、架构和 Python 版本)下将要安装的包。

与用于指定项目广泛需求的 pyproject.toml 不同,lockfile 包含了项目环境中实际安装的确切版本。此文件应提交到版本控制中,以便在机器之间实现一致且可重复的安装。

A 锁定文件确保在项目上工作的开发者使用一致的一组包版本。此外,它确保在将项目作为应用程序部署时,知道使用的确切包版本集。

锁文件在使用项目环境的 uv 调用期间 自动创建和更新,例如 uv syncuv run。锁文件也可以使用 uv lock 显式更新。

uv.lock 是一个可读的 TOML 文件,但由 uv 管理,不应手动编辑。目前没有 Python 标准的锁文件格式,因此此文件的格式特定于 uv,不能被其他工具使用。



创建项目

https://docs.astral.sh/uv/concepts/projects/init/

uv 支持使用 uv init 创建项目。

在创建项目时,uv 支持两种基本模板:应用程序。默认情况下,uv 将为应用程序创建项目。可以使用 --lib 标志来创建库项目。


目标目录

uv将在工作目录中创建一个项目,或者通过提供名称在目标目录中创建,例如uv init foo。如果目标目录中已经存在一个项目,即存在pyproject.toml文件,uv将错误退出。


应用程序

应用程序项目适用于Web服务器、脚本和命令行界面。

应用程序是 uv init 的默认目标,也可以使用 --app 标志来指定。

uv init example-app

该项目包括一个 pyproject.toml,一个示例文件(main.py),一个自述文件,以及一个 Python 版本固定文件(.python-version)。

$ tree example-app
example-app
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

注意:在 v0.6.0 之前,uv 创建了一个名为 hello.py 的文件,而不是 main.py


pyproject.toml 包含基本元数据。它不包含构建系统,它不是一个 并且不会被安装到环境中:
pyproject.toml

[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

样本文件定义了一个 main 函数和一些标准样板代码:
main.py

def main():
    print("Hello from example-app!")

if __name__ == "__main__":
    main()

Python 文件可以使用 uv run 执行:

$ cd example-app
$ uv run main.py
Hello from example-project!

打包的应用程序

许多用例需要打包。例如,如果你正在创建一个将发布到 PyPI 的命令行界面,或者你想要在专用目录中定义测试。

可以使用 --package 标志来创建打包的应用程序:

uv init --package example-pkg

源代码被移动到一个包含模块目录和 __init__.py 文件的 src 目录中:

$ tree example-pkg
example-pkg
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_pkg
        └── __init__.py

一个 build system 被定义,因此项目将被安装到环境中:
pyproject.toml

[project]
name = "example-pkg"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-pkg = "example_pkg:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Tip:--build-backend 选项可以用来请求一个替代的构建系统。


command 定义已包含:
pyproject.toml

[project]
name = "example-pkg"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-pkg = "example_pkg:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

命令可以通过 uv run 执行:

$ cd example-pkg
$ uv run example-pkg
Hello from example-pkg!

库为其他项目提供函数和对象以供使用。库旨在构建和分发,例如,通过将它们上传到 PyPI。

可以通过使用 --lib 标志来创建库:

uv init --lib example-lib

注意:使用 --lib 等同于使用 --package。库始终需要一个打包的项目。
打包应用程序 一样,使用了一个 src 布局。包含了一个 py.typed 标记,以指示消费者可以从库中读取类型:

$ tree example-lib
example-lib
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_lib
        ├── py.typed
        └── __init__.py

注意:在开发库时,src 布局尤其有价值。它确保库与项目根目录中的任何 python 调用隔离,并且分布式库代码与项目其他源代码很好地分离。
一个 构建系统 被定义,因此项目将被安装到环境中:
pyproject.toml

[project]
name = "example-lib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Tip : 您可以通过使用 --build-backendhatchlingflit-corepdm-backendsetuptoolsmaturinscikit-build-core 来选择不同的构建后端模板。如果您想要创建一个 带有扩展模块的库,则需要一个替代后端。
创建的模块定义了一个简单的API函数:
init.py

def hello() -> str:
    return "Hello from example-lib!"

您可以使用 uv run 导入并执行它:

$ cd example-lib
$ uv run python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!

带有扩展模块的项目

大多数Python项目是“纯Python”,这意味着它们不定义其他语言(如C、C++、FORTRAN或Rust)中的模块。然而,具有扩展模块的项目通常用于对性能敏感的代码。

创建一个具有扩展模块的项目需要选择一个替代的构建系统。uv支持使用以下支持构建扩展模块的构建系统创建项目:


使用 --build-backend 标志指定构建系统:

uv init --build-backend maturin example-ext

注意:使用 --build-backend 意味着使用 --package
项目包含一个 Cargo.toml 和一个 lib.rs 文件,以及典型的 Python 项目文件:

$ tree example-ext
example-ext
├── .python-version
├── Cargo.toml
├── README.md
├── pyproject.toml
└── src
    ├── lib.rs
    └── example_ext
        ├── __init__.py
        └── _core.pyi

注意:如果使用 scikit-build-core,您将看到 CMake 配置和一个 main.cpp 文件。
Rust 库定义了一个简单的函数:
src/lib.rs

use pyo3::prelude::*;

#[pyfunction]
fn hello_from_bin() -> String {
    "Hello from example-ext!".to_string()
}

#[pymodule]
fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(hello_from_bin, m)?)?;
    Ok(())
}

Python 模块导入它:
src/example_ext/init.py

from example_ext._core import hello_from_bin

def main() -> None:
    print(hello_from_bin())

命令可以通过 uv run 执行:

$ cd example-ext
$ uv run example-ext
Hello from example-ext!

Important:
更改 lib.rsmain.cpp 中的扩展代码将需要运行 --reinstall 以重新构建它们。


创建一个最小项目

如果您只想创建一个 pyproject.toml,请使用 --bare 选项:

uv init example --bare

uv 将跳过创建 Python 版本标记文件、README 文件以及任何源目录或文件。此外,uv 不会初始化版本控制系统(即,git)。

$ tree example-bare
example-bare
└── pyproject.toml

uv 也不会向 pyproject.toml 添加额外的元数据,例如 descriptionauthors

[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []

--bare 选项可以与 --lib--build-backend 等其他选项一起使用 —— 在这种情况下,uv 仍然会配置构建系统,但不会创建预期的文件结构。
当使用 --bare 时,仍可以按需启用附加功能:

uv init example --bare --description "Hello world" --author-from git --vcs git --python-pin


管理依赖关系


依赖关系表

项目的依赖关系定义在几个表中:


注意:即使项目不打算发布,也可以使用 project.dependenciesproject.optional-dependencies 表格。dependency-groups 是一个最近标准化的特性,可能还没有被所有工具支持。
uv支持使用 uv adduv remove 修改项目的依赖项,但也可以通过直接编辑 pyproject.toml 来更新依赖项元数据。


添加依赖

要添加一个依赖项:

uv add httpx 

一条记录将被添加到 project.dependencies 表中:


pyproject.toml

[project] name = "example" version = "0.1.0" dependencies = ["httpx>=0.27.2"] 

-dev--group--optional 标志可用于将依赖关系添加到替代表中。

依赖关系将包括一个约束,例如,对于包的最新兼容版本,>=0.27.2。可以提供另一种约束:

uv add "httpx>=0.20" 

当从一个非包注册表的其他源添加依赖项时,uv 将在源表中添加一个条目。例如,当从 GitHub 添加 httpx 时:

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

pyproject.toml 将包含一个 Git 源条目:

pyproject.toml

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

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

如果无法使用依赖项,uv 将显示错误。

uv add "httpx>9999"

导入依赖

requirements.txt 文件中声明的依赖可以通过 -r 选项添加到项目中:

uv add -r requirements.txt 

移除依赖

要移除一个依赖:

uv remove httpx 

--dev, --group--optional 标志可以用来从特定表中删除一个依赖。
如果为移除的依赖项定义了 ,并且没有其他对该依赖项的引用,它也将被移除。


更改依赖

要更改现有依赖项,例如,为 httpx 使用不同的约束:

uv add "httpx>0.1.0" 

Note : 在这个示例中,我们正在更改 pyproject.toml 中依赖项的约束。依赖项的锁定版本只有在必要时才会更新以满足新的约束。要强制包版本更新到约束范围内的最新版本,请使用 --upgrade-package <name>,例如:

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

查看lockfile文档以获取更多关于升级软件包的详细信息。
请求不同的依赖源将更新 tool.uv.sources 表,例如,在开发期间从本地路径使用 httpx

uv add "httpx @ ../httpx" 

平台特定依赖

为确保依赖项仅在特定平台或特定Python版本上安装,请使用环境标记

例如,要在Linux上安装jax,但不在Windows或macOS上安装:

uv add "jax; sys_platform == 'linux'" 

生成的 pyproject.toml 文件将包括依赖定义中的环境标记:


pyproject.toml

[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 表代表在上传到 PyPI 或构建 wheel 时使用的依赖项。单个依赖项使用 依赖指定符 语法指定,表格遵循 PEP 621 标准。

project.dependencies 定义了项目所需的包列表,以及安装它们时应使用的版本约束。每个条目包括一个依赖项名称和版本。条目可能包括为特定平台包的额外功能或环境标记。例如:


pyproject.toml

[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
  # See "Environment Markers" for more information
  "importlib_metadata >=7.1.0,<8; python_version < '3.10'",
  "mollymawk ==0.1.0"
]

依赖源

tool.uv.sources 表扩展了标准依赖表,提供了备选依赖源,这些依赖源在开发过程中使用。

依赖源增加了对 project.dependencies 标准不支持的一些常见模式的支持,例如可编辑安装和相对路径。例如,要从项目根目录相对目录中安装 foo


pyproject.toml

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

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

以下依赖源由 uv 支持:

  • 索引:从一个特定的包索引中解析出的包。
  • Git: 一个 Git 仓库。
  • URL:远程轮子或源分发版
  • 路径:一个本地轮子、源分发版或项目目录。
  • 工作区:当前工作区的一名成员。

重要:uv 仅尊重源。如果使用其他工具,则仅使用标准项目表中的定义。如果使用其他工具进行开发,则需要在其他工具的格式中重新指定源表中提供的任何元数据。


索引

要从特定索引添加 Python 包,请使用 --index 选项:

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

uv 将在 [[tool.uv.index]] 中存储索引,并添加一个 [tool.uv.sources] 条目:


pyproject.toml

[project]
dependencies = ["torch"]

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

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

提示:上述示例仅在 x86-64 Linux 上有效,因为 PyTorch 索引的特定原因。有关设置 PyTorch 的更多信息,请参阅PyTorch 指南
使用一个 index 源将包固定到指定的索引——它将不会从其他索引中下载。
当定义索引时,可以包含一个 explicit 标志来指示该索引 应用于在 tool.uv.sources 中明确指定它的包。如果没有设置 explicit,则如果在其他地方找不到,则可能从索引中解析其他包。


pyproject.toml

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

Git

要添加 Git 依赖源,请在 Git 兼容的 URL(即您会用于 git clone 的 URL)前缀为 git+


例如:

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

pyproject.toml

[project]
dependencies = ["httpx"]

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

特定 Git 引用可以请求,例如,一个标签:

uv add git+https://github.com/encode/httpx --tag 0.27.0 

pyproject.toml

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

或者,一个分支:

uv add git+https://github.com/encode/httpx --branch main 

pyproject.toml

[project]
dependencies = ["httpx"]

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

或者,一个修订(提交):

uv add git+https://github.com/encode/httpx --rev 326b9431c761e1ef1e00b9f760d1f654c8db48c6 

pyproject.toml

[project]
dependencies = ["httpx"]

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

A 子目录 可以指定,如果包不在存储库根目录中:

uv add git+https://github.com/langchain-ai/langchain#subdirectory=libs/langchain 

pyproject.toml

[project]
dependencies = ["httpx"]

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

URL

要添加 URL 源,提供一个 https:// URL,指向一个 wheel 文件(以 .whl 结尾)或源代码分发(通常以 .tar.gz.zip 结尾;有关所有支持的格式,请参阅此处)。


例如:

uv add "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz" 

将生成一个 pyproject.toml,其中包含:


pyproject.toml

[project]
dependencies = ["langchain"]

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

URL 依赖也可以通过 pyproject.toml 使用 { url = <url> } 语法手动添加或编辑。如果源分发不在存档根目录中,可以指定一个 子目录


路径

要添加路径源,请提供轮文件的路径(以 .whl 结尾),源分发版(通常以 .tar.gz.zip 结尾;有关所有支持的格式,请参阅此处),或包含 pyproject.toml 的目录。


例如:

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

将生成一个 pyproject.toml,内容如下:


pyproject.toml

[project]
dependencies = ["httpx"]

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

路径也可以是相对路径:

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

或者,项目目录的路径:

uv add ~/projects/bar/ 

Important:
An 可编辑的安装 默认情况下不用于路径依赖。可以为项目目录请求可编辑的安装:

uv add --editable ~/projects/bar/ 

对于同一存储库中的多个包,工作区可能更合适。


工作区成员

要声明对工作区成员的依赖,请添加成员名称并使用 { workspace = true }。所有工作区成员都必须明确声明。工作区成员始终是可编辑的。有关工作区的更多详细信息,请参阅工作区文档。


pyproject.toml

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

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

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

平台特定的来源

您可以通过提供与 dependency specifiers 兼容的环境标记来限制来源仅适用于特定的平台或 Python 版本。

例如,要从 GitHub 拉取 httpx,但仅限于 macOS,请使用以下命令:


pyproject.toml

[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。


多个来源

您可以通过提供一个由 PEP 508 兼容的环境标记区分的来源列表,为单个依赖指定多个来源。

例如,为了在 macOS 和 Linux 上拉取不同的 httpx 标签:


pyproject.toml

[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


pyproject.toml

[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"

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

禁用源

要指示uv忽略tool.uv.sources表(例如,模拟使用包已发布的元数据进行解析),请使用--no-sources标志:

uv lock --no-sources 

--no-sources 的使用还将阻止 uv 发现任何可以满足给定依赖项的 工作区成员


可选依赖

将项目发布为库时,为了减少默认依赖树,让一些功能可选是很常见的。例如,Pandas 有一个用于处理 Excel 文件的 excel 额外模块 和一个用于可视化的 plot 额外模块,以避免安装 Excel 解析器和 matplotlib,除非有人明确要求。可以使用 package[<extra>] 语法请求额外模块,例如,pandas[plot, excel]

可选依赖在 [project.optional-dependencies] 中指定,这是一个 TOML 表格,它将额外模块名称映射到其依赖项,遵循 依赖指定符 语法。

可选依赖可以在 tool.uv.sources 中与正常依赖项具有相同的条目。


pyproject.toml

[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 <额外> 选项:

uv add httpx --optional network 

Note
如果您有相互冲突的可选依赖项,除非您明确地将它们声明为冲突,否则解析将失败。
源也可以声明仅适用于特定的可选依赖项。例如,根据可选的 cpugpu 附加组件从不同的 PyTorch 指数中提取 torch


pyproject.toml

[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/cu124"

开发依赖

与可选依赖不同,开发依赖是本地-only 的,并且在发布到 PyPI 或其他索引时 不会 包含在项目需求中。因此,开发依赖不包括在 [项目] 表中。

开发依赖可以在 tool.uv.sources 中有条目,就像正常依赖一样。

要添加开发依赖,请使用 --dev 标志:

uv add --dev pytest 

uv 使用 [dependency-groups] 表(如 PEP 735 中定义的)来声明开发依赖项。上面的命令将创建一个 dev 组:


pyproject.toml

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

dev 组有特殊处理;有 --dev--only-dev--no-dev 标志来切换其依赖项的包含或排除。查看 --no-default-groups 以禁用所有默认组。此外,dev 组默认 同步


依赖分组

开发依赖可以被划分为多个组,使用 --group 标志。

例如,要在 lint 组中添加一个开发依赖:

uv add --group lint ruff 

结果为以下 [dependency-groups] 定义:


pyproject.toml

[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 将无法通过错误解析项目的需求。


注意:如果您有相互冲突的依赖组,除非您明确声明它们为冲突的,否则解析将失败。


默认组

默认情况下,uv 将 dev 依赖组包含在环境中(例如,在 uv runuv sync 过程中)。可以通过使用 tool.uv.default-groups 设置来更改要包含的默认组。


pyproject.toml

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

提示:要在 uv runuv sync 中禁用此行为,请使用 --no-default-groups。要排除特定的默认组,请使用 --no-group <name>


旧版 dev-dependencies

[dependency-groups] 标准化之前,uv 使用 tool.uv.dev-dependencies 字段来指定开发依赖项,例如:


pyproject.toml

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

依赖项声明在本节中,将与 dependency-groups.dev 中的内容合并。最终,dev-dependencies 字段将被弃用并移除。


注意:如果存在 tool.uv.dev-dependencies 字段,则 uv add --dev 将使用现有部分而不是添加新的 dependency-groups.dev 部分。


构建依赖

如果一个项目以 Python 包 的形式构建,它可能声明了构建项目所需的依赖项,但这些依赖项不是运行项目所需的。这些依赖项在 build-system.requires 下的 [build-system] 表中指定,遵循 PEP 518

例如,如果一个项目使用 setuptools 作为其构建后端,它应该将 setuptools 声明为构建依赖项:


pyproject.toml

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

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

默认情况下,uv 将在解析构建依赖项时尊重 tool.uv.sources。例如,要使用本地版本的 setuptools 进行构建,请将源添加到 tool.uv.sources


pyproject.toml

[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)时一样。


可编辑依赖

一个目录中 Python 包的常规安装首先构建一个 wheel,然后将其安装到您的虚拟环境中,并复制所有源文件。当包的源文件被编辑时,虚拟环境将包含过时的版本。

可编辑安装通过在虚拟环境中添加到项目的链接(一个 .pth 文件)来解决此问题,该链接指示解释器直接包含源文件。

可编辑安装有一些限制(主要是:构建后端需要支持它们,并且原生模块在导入之前不会重新编译),但它们对开发很有用,因为虚拟环境将始终使用包的最新更改。

uv 默认使用可编辑安装来安装工作区包。

要添加一个可编辑依赖,使用 --editable 标志:

uv add --editable ./path/foo 

或者,要在一个工作区中禁用可编辑依赖项:

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


在项目中运行命令

当在一个项目上工作时,它会被安装到虚拟环境 .venv 中。默认情况下,此环境与当前shell是隔离的,因此需要项目才能调用的调用,例如 python -c "import example",将会失败。相反,请使用 uv run 在项目环境中运行命令:

uv run python -c "import example"

当使用 run 时,uv 将确保在运行给定命令之前,项目环境是最新的。
给定的命令可以由项目环境提供,或者存在于项目环境之外,例如:

$ # Presuming the project provides `example-cli`
$ uv run example-cli foo

$ # Running a `bash` script that requires the project to be available
$ uv run bash scripts/foo.sh

请求额外的依赖

每次调用都可以请求额外的依赖或不同版本的依赖。

使用 --with 选项来包含调用中的一个依赖,例如,请求 httpx 的不同版本:

uv run --with httpx==0.26.0 python -c "import httpx; print(httpx.__version__)"
0.26.0
$ uv run --with httpx==0.25.0 python -c "import httpx; print(httpx.__version__)"
0.25.0

请求的版本将被尊重,无论项目需求如何。例如,即使项目需要 httpx==0.24.0,上面的输出也会相同。


运行脚本

声明内联元数据的脚本将在与项目隔离的环境中自动执行。有关详细信息,请参阅脚本指南

例如,给定一个脚本:

example.py

# /// script
# dependencies = [
#   "httpx",
# ]
# ///

import httpx

resp = httpx.get("https://peps.python.org/api/peps.json")
data = resp.json()
print([(k, v["title"]) for k, v in data.items()][:10])

uv 运行 example.py 命令会以 独立 的方式运行,仅包含列出的依赖项。


旧版 Windows 脚本

支持 旧版 setuptools 脚本。这些类型的脚本是由 setuptools 在 .venv\Scripts 中安装的附加文件。

目前仅支持以 .ps1.cmd.bat 扩展名结尾的旧版脚本。

例如,下面是一个运行命令提示符脚本的示例。

uv run --with nuitka==2.6.7 -- nuitka.cmd --version

此外,您不需要指定扩展名。uv 将会自动为您查找以 .ps1.cmd.bat 结尾的文件,并按照这个顺序执行。

uv run --with nuitka==2.6.7 -- nuitka --version


锁定和同步

锁定是将您项目的依赖项解析为锁定文件的过程。同步是将锁定文件中的部分包安装到项目环境的过程。


自动锁定和同步

在 uv 中,锁定和同步是 自动 的。例如,当使用 uv run 时,在调用请求的命令之前,项目会被锁定和同步。这确保了项目环境始终是最新的。同样,例如 uv tree 这样的读取锁定文件的命令,在运行之前也会自动更新它。

要禁用自动锁定,请使用 --locked 选项:

uv run --locked ...

如果锁文件不是最新的,uv 将会引发错误而不是更新锁文件。
要使用锁文件而不检查其是否最新,请使用 --frozen 选项:

uv run --frozen ...

同样,要运行命令而不检查环境是否最新,请使用 --no-sync 选项:

uv run --no-sync ...

检查锁文件是否更新

在考虑锁文件是否更新时,uv 会检查它是否与项目元数据匹配。例如,如果您在 pyproject.toml 中添加了一个依赖项,则锁文件将被认为是过时的。同样,如果您更改了依赖项的版本约束,以至于锁定的版本被排除在外,则锁文件将被认为是过时的。然而,如果您更改版本约束,使得现有的锁定版本仍然包含在内,则锁文件仍将被认为是更新的。

您可以通过向 uv lock 命令传递 --check 标志来检查锁文件是否更新:

uv lock --check

这与其他命令的 --locked 标志等效。


Important: uv 不会在包的新版本发布时考虑锁定文件过时 —— 如果您想升级依赖项,需要显式更新锁定文件。有关详细信息,请参阅升级锁定包版本的文档。


创建锁文件

虽然锁文件是自动创建的 自动创建,但也可以使用 uv lock 显式创建或更新锁文件:

uv lock

同步环境

当环境正在同步时自动,也可以使用 uv sync 显式同步:

uv sync

手动同步环境尤其有用,以确保您的编辑器具有正确的依赖项版本。


可编辑安装

当环境同步时,uv 将项目(以及其他工作区成员)作为 可编辑 包安装,这样更改不需要重新同步即可反映在环境中。

要退出此行为,请使用 --no-editable 选项。


注意:如果项目没有定义构建系统,则无法安装。有关详细信息,请参阅构建系统文档。


保留多余包

默认情况下,同步是“精确”的,这意味着它将删除锁文件中不存在的任何包。

要保留多余包,请使用 --inexact 选项:

uv sync --inexact

同步可选依赖

uv 从 [project.optional-dependencies] 表中读取可选依赖。这些通常被称为 “额外依赖”。

uv 默认不会同步额外依赖。使用 --extra 选项来包含一个额外依赖。

uv sync --extra foo

要快速启用所有附加功能,请使用 --all-extras 选项。
查看可选依赖项文档以获取如何管理可选依赖项的详细信息。


同步开发依赖

uv 从 [dependency-groups] 表中读取开发依赖(如 PEP 735 中定义的)。

dev 组被特别处理,并且默认同步。有关更改默认设置的详细信息,请参阅 默认组 文档。

可以使用 --no-dev 标志来排除 dev 组。

可以使用 --only-dev 标志来安装 dev而不包含 项目及其依赖项。

可以使用 --all-groups--no-default-groups--group <name>--only-group <name>--no-group <name> 选项包括或排除其他组。--only-group 的语义与 --only-dev 相同,项目将不会包括在内。然而,--only-group 还会排除默认组。

组排除始终优先于包含,因此对于以下命令:

uv sync --no-group foo --group foo

foo 组将不会被安装。
查看开发依赖项文档以获取如何管理开发依赖项的详细信息。


升级锁定包版本

存在 uv.lock 文件时,uv 将在运行 uv syncuv lock 时优先选择之前锁定的包版本。只有当项目的依赖约束排除了之前的锁定版本时,包版本才会更改。

要升级所有包:

uv lock --upgrade

要将单个包升级到最新版本,同时保留所有其他包的锁定版本:

uv lock --upgrade-package <package>

将单个软件包升级到特定版本:

uv lock --upgrade-package <package>==<version>

在所有情况下,升级都受限于项目的依赖约束。例如,如果项目为某个包定义了上限版本,则升级不会超出该版本。


注意:uv 对 Git 依赖项应用类似的逻辑。例如,如果 Git 依赖项引用了 main 分支,uv 将优先选择现有 uv.lock 文件中锁定的提交 SHA,而不是 main 分支上的最新提交,除非使用了 --upgrade--upgrade-package 标志。
这些标志也可以提供给 uv syncuv run 以更新锁文件和环境


导出锁文件

如果您需要将 uv 与其他工具或工作流程集成,您可以使用 uv export --format requirements-txtuv.lock 导出为 requirements.txt 格式。生成的 requirements.txt 文件可以通过 uv pip install 安装,或者使用其他工具如 pip

通常,我们不推荐同时使用 uv.lockrequirements.txt 文件。如果您发现自己正在导出 uv.lock 文件,请考虑提交一个问题来讨论您的用例。



配置项目


Python 版本要求

项目可以在 pyproject.toml 文件的 project.requires-python 字段中声明项目支持的 Python 版本。

建议设置 requires-python 值:

pyproject.toml

[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.12"

Python 版本要求决定了项目中允许使用的 Python 语法,并影响依赖版本的选择(它们必须支持相同的 Python 版本范围)。


入口点

入口点是已安装包用于宣传接口的官方术语。这些包括:


Important:
使用入口点表需要定义一个 构建系统


命令行界面

项目可以为项目定义命令行界面(CLIs),并在 pyproject.toml[project.scripts] 表中指定。

例如,要声明一个名为 hello 的命令,该命令调用 example 模块中的 hello 函数:

pyproject.toml

[project.scripts]
hello = "example:hello"

然后,可以从控制台运行该命令:

uv run hello

图形用户界面

项目可以在 pyproject.toml 中的 [project.gui-scripts] 表中定义项目的图形用户界面(GUI)。


Important:
这些在其他平台上表现相同,只是在 Windows 上,它们通过一个 GUI 可执行文件被包装,以便可以在没有控制台的情况下启动。命令行界面
例如,要声明一个名为 hello 的命令,该命令在 example 模块中调用 app 函数:
pyproject.toml

[project.gui-scripts]
hello = "example:app"

插件入口点

项目可以在 pyproject.toml[project.entry-points\] 表中定义插件发现入口。

例如,要将 example-plugin-a 包注册为 example 的插件:

pyproject.toml

[project.entry-points.'example.plugins']
a = "example_plugin_a"

然后,在 example 中,插件将通过以下方式加载:
example/init.py

from importlib.metadata import entry_points

for plugin in entry_points(group='example.plugins'):
    plugin.load()

注意:group 键可以是一个任意值,它不需要包含包名或 “plugins”。然而,建议通过包名来命名空间键,以避免与其他包发生冲突。


构建系统

构建系统决定了项目应该如何打包和安装。项目可以在 pyproject.toml 文件的 [build-system] 表中声明和配置构建系统。

uv 使用构建系统的存在来决定项目中是否包含应该在项目虚拟环境中安装的包。如果没有定义构建系统,uv 将不会尝试构建或安装项目本身,只会安装其依赖项。如果定义了构建系统,uv 将构建并安装项目到项目环境中。

可以提供 --build-backend 选项给 uv init 来创建一个具有适当布局的打包项目。可以提供 --package 选项给 uv init 来创建一个使用默认构建系统的打包项目。


注意:虽然uv没有构建系统定义将不会构建和安装当前项目,但其他包中不需要存在 [build-system] 表格。出于历史原因,如果没有定义构建系统,则使用 setuptools.build_meta:__legacy__ 来构建包。你依赖的包可能没有明确声明它们的构建系统,但仍然可以安装。同样,如果你添加了对本地包的依赖或使用 uv pip 安装它,uv将始终尝试构建和安装它。


构建系统选项

构建系统用于启用以下功能:

  • 从发行版中包含或排除文件
  • 可编辑的安装行为
  • 动态项目元数据
  • 原生代码的编译
  • 共享库的 vendoring

要配置这些功能,请参阅您选择的构建系统的文档。


项目打包

构建系统中所述,Python项目必须构建后才能安装。这个过程通常被称为“打包”。

你可能需要打包,如果你想:

  • 向项目中添加命令
  • 将项目分发给他人
  • 使用 srctest 布局
  • 编写库

你可能不需要打包,如果你:

  • 编写脚本
  • 构建一个简单的应用程序
  • 使用平面布局

虽然uv通常使用构建系统的声明来确定项目是否应该打包,但uv也允许通过tool.uv.package设置来覆盖此行为。

设置tool.uv.package = true将强制项目构建并安装到项目环境中。如果没有定义构建系统,uv将使用setuptools传统后端。

设置tool.uv.package = false将强制项目不构建并安装到项目环境中。uv在与项目交互时将忽略声明的构建系统。


项目环境路径

可以使用 UV_PROJECT_ENVIRONMENT 环境变量来配置项目虚拟环境路径(默认为 .venv)。

如果提供了一个相对路径,它将相对于工作区根目录进行解析。如果提供了一个绝对路径,它将直接使用,即不会为环境创建子目录。如果提供的路径不存在环境,uv 将创建它。

此选项可用于写入系统 Python 环境,尽管不推荐这样做。uv sync 默认会从环境中移除多余的包,因此可能会使系统处于损坏状态。

要针对系统环境,将 UV_PROJECT_ENVIRONMENT 设置为 Python 安装的前缀。例如,在基于 Debian 的系统上,这通常是 /usr/local

$ python -c "import sysconfig; print(sysconfig.get_config_var('prefix'))"
/usr/local

要针对此环境,您会导出 UV_PROJECT_ENVIRONMENT=/usr/local


Important: 如果提供了绝对路径并且此设置在多个项目中使用,环境将被每个项目中的调用覆盖。此设置仅推荐用于CI或Docker镜像中的单个项目。


注意:默认情况下,uv 在项目操作期间不会读取 VIRTUAL_ENV 环境变量。如果 VIRTUAL_ENV 设置为与项目环境不同的路径,将显示警告。可以使用 --active 标志来选择尊重 VIRTUAL_ENV。可以使用 --no-active 标志来静默警告。


受限分辨率环境

如果你的项目支持更有限的平台或 Python 版本,你可以通过 environments 设置限制要解决的平台的集合,该设置接受一个 PEP 508 环境标记列表。例如,为了将锁文件限制在 macOS 和 Linux 上,并排除 Windows:

pyproject.toml

[tool.uv]
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]

查看更多请参阅分辨率文档


必需环境

如果你的项目 必须 支持特定的平台或 Python 版本,你可以通过 required-environments 设置标记该平台为必需。例如,要指定项目支持 Intel macOS:

pyproject.toml

[tool.uv]
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'",
]

required-environments 设置仅适用于不发布源分布的包(如 PyTorch),因为此类包只能在由该包发布的预构建二进制分布(wheels)覆盖的环境上安装。
查看更多信息的分辨率文档


构建隔离

默认情况下,uv 在隔离的虚拟环境中构建所有包,遵循 PEP 517。一些包与构建隔离不兼容,无论是故意(例如,由于使用了重的构建依赖项,最常见的是 PyTorch)还是无意(例如,由于使用了遗留的打包设置)。

要为特定依赖项禁用构建隔离,将其添加到 pyproject.toml 中的 no-build-isolation-package 列表:

pyproject.toml

[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["cchardet"]

[tool.uv]
no-build-isolation-package = ["cchardet"]

安装不使用构建隔离的包需要先在项目环境中安装包的构建依赖,然后再安装包本身。这可以通过将构建依赖和需要它们的包分离成不同的额外部分来实现。例如:
pyproject.toml

[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[project.optional-dependencies]
build = ["setuptools", "cython"]
compile = ["cchardet"]

[tool.uv]
no-build-isolation-package = ["cchardet"]

考虑到以上内容,用户首先需要同步 build 依赖项:

uv sync --extra build
 + cython==3.0.11
 + foo==0.1.0 (from file:///Users/crmarsh/workspace/uv/foo)
 + setuptools==73.0.1

随后是 编译 依赖项:

uv sync --extra compile
 + cchardet==2.1.7
 - cython==3.0.11
 - setuptools==73.0.1

请注意,uv sync --extra compile 默认会卸载 cythonsetuptools 软件包。要保留构建依赖项,请在第二次 uv sync 调用中包含这两个 extras:

uv sync --extra build
$ uv sync --extra build --extra compile

一些包,如上面的 cchardet,仅需要在 uv sync安装 阶段构建依赖。其他,如 flash-attn,即使在 解析 阶段只需解决项目的锁定文件,也需要它们的构建依赖存在。
在这种情况下,必须在运行任何 uv lockuv sync 命令之前安装构建依赖项,使用较低级别的 uv pip API。例如,给定:

pyproject.toml

[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["flash-attn"]

[tool.uv]
no-build-isolation-package = ["flash-attn"]

您可以使用以下命令序列来同步 flash-attn

uv venv
$ uv pip install torch setuptools
$ uv sync

或者,您可以通过在 dependency-metadata 设置中提前提供 flash-attn 元数据来跳过在依赖项解析阶段构建包的需要。例如,要提前提供 flash-attn 元数据,请在您的 pyproject.toml 中包含以下内容:
pyproject.toml

[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]

Tip:要确定类似 flash-attn 这样的包的元数据,请导航到相应的 Git 仓库,或在 PyPI 上查找并下载该包的源代码分布。包的要求通常可以在 setup.pysetup.cfg 文件中找到。
(如果软件包包含构建后的发行版,您可以将它解压以找到 METADATA 文件;然而,构建后的发行版的存在会否定在前期提供元数据的需求,因为它已经对 uv 可用。)
一旦包含,您还可以再次使用两步 uv sync 流程来安装构建依赖项。给定以下 pyproject.toml

pyproject.toml

[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[project.optional-dependencies]
build = ["torch", "setuptools", "packaging"]
compile = ["flash-attn"]

[tool.uv]
no-build-isolation-package = ["flash-attn"]

[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]

您可以使用以下命令序列来同步 flash-attn

uv sync --extra build
$ uv sync --extra build --extra compile

注意:在 tool.uv.dependency-metadata 中的 version 字段对于基于注册表的依赖项是可选的(当省略时,uv 将假设元数据适用于所有版本的包),但对于直接 URL 依赖项(如 Git 依赖项)则是必需的。


可编辑模式

默认情况下,项目将以可编辑模式安装,这样对源代码的更改将立即反映在环境中。

uv syncuv run 都接受一个 --no-editable 标志,该标志指示 uv 以非可编辑模式安装项目。

--no-editable 旨在用于部署用例,例如构建 Docker 容器,在这种情况下,项目应包含在部署环境中,而不依赖于原始源代码。


冲突依赖

uv 要求项目声明的所有可选依赖(“extras”)之间相互兼容,并在创建锁文件时一起解决所有可选依赖。

如果在一个额外依赖中声明的可选依赖与另一个额外依赖中的不兼容,uv 将无法解决项目的需求,并抛出错误。

为了解决这个问题,uv 支持声明冲突的额外依赖。例如,考虑两个相互冲突的可选依赖集:

pyproject.toml

[project.optional-dependencies]
extra1 = ["numpy==2.1.2"]
extra2 = ["numpy==2.0.0"]

如果您使用上述依赖项运行 uv lock,解析将失败:

uv lock
  x No solution found when resolving dependencies:
  `-> Because myproject[extra2] depends on numpy==2.0.0 and myproject[extra1] depends on numpy==2.1.2, we can conclude that myproject[extra1] and
      myproject[extra2] are incompatible.
      And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.

但是如果您指定 extra1extra2 存在冲突,uv 将分别解决它们。在 tool.uv 部分指定冲突:
pyproject.toml

[tool.uv]
conflicts = [
    [
      { extra = "extra1" },
      { extra = "extra2" },
    ],
]

现在,运行 uv lock 将会成功。注意,现在您不能同时安装 extra1extra2

$ uv sync --extra extra1 --extra extra2
Resolved 3 packages in 14ms
error: extra `extra1`, extra `extra2` are incompatible with the declared conflicts: {`myproject[extra1]`, `myproject[extra2]`}

此错误发生是因为同时安装 extra1extra2 将会导致在同一个环境中安装同一软件包的两个不同版本。
以上处理冲突额外参数的策略也适用于依赖分组:
pyproject.toml

[dependency-groups]
group1 = ["numpy==2.1.2"]
group2 = ["numpy==2.0.0"]

[tool.uv]
conflicts = [
    [
      { group = "group1" },
      { group = "group2" },
    ],
]

与冲突的扩展的唯一区别是,您需要使用 group 而不是 extra


构建发行版

要将您的项目分发给他人(例如,上传到像 PyPI 这样的索引),您需要将其构建成可分发格式。

Python 项目通常以源发行版(sdists)和二进制发行版(wheels)的形式进行分发。前者通常是一个包含项目源代码和一些附加元数据的 .tar.gz.zip 文件,而后者是一个包含预构建工件可以直接安装的 .whl 文件。


Important: 当使用 uv build 时,uv 充当 构建前端 的角色,并且只确定要使用的 Python 版本并调用构建后端。构建的详细信息,例如包含的文件和分发文件名,由定义在 [build-system\] 中的构建后端确定。有关构建配置的信息可以在相应工具的文档中找到。


使用 uv build

uv build 可以用来构建您的项目的源分布和二进制分布。默认情况下,uv build 将在当前目录中构建项目,并将构建的工件放置在 dist/ 子目录中:

$ uv build
$ ls dist/
example-0.1.0-py3-none-any.whl
example-0.1.0.tar.gz

您可以通过提供 uv build 的路径来在不同的目录中构建项目,例如:uv build path/to/project
uv build 首先将构建一个源分发版,然后从这个源分发版构建一个二进制分发版(wheel)。
您可以将 uv build 限制为仅构建源分布,使用 uv build --sdist,二进制分布,使用 uv build --wheel,或者从源构建两种分布,使用 uv build --sdist --wheel


构建约束

uv build 接受 --build-constraint 参数,该参数可用于在构建过程中约束任何构建需求版本。当与 --require-hashes 结合使用时,uv 将强制要求用于构建项目的需求与特定的已知哈希值匹配,以确保可重复性。

例如,给定以下 constraints.txt 文件:

setuptools==68.2.2 --hash=sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a

运行以下命令将使用指定的 setuptools 版本构建项目,并验证下载的 setuptools 发行版与指定的哈希值匹配:

uv build --build-constraint constraints.txt --require-hashes

使用工作区

Cargo 中同名概念的启发,工作区是“一个或多个称为 工作区成员 的包的集合,这些包被一起管理。”

工作区通过将它们拆分为具有共同依赖的多个包来组织大型代码库。想象一下:一个基于 FastAPI 的 Web 应用程序,以及一系列作为单独的 Python 包进行版本控制和维护的库,所有这些都位于同一个 Git 仓库中。

在工作区中,每个包都定义了自己的 pyproject.toml 文件,但工作区共享一个单一的 lockfile,确保工作区使用一致的依赖集进行操作。

因此,uv lock 一次操作整个工作区,而 uv runuv sync 默认操作工作区根目录,尽管两者都接受 --package 参数,允许您从任何工作区目录运行特定工作区成员的命令。


入门

要创建一个工作区,请在 pyproject.toml 中添加一个 tool.uv.workspace 表,这将隐式地在该包的根目录创建一个工作区。

提示:
默认情况下,在现有包内部运行 uv init 将会将新创建的成员添加到工作区中,如果工作区根目录中尚不存在,则会创建一个 tool.uv.workspace 表。

在定义工作区时,您必须指定 members(必需)和 exclude(可选)键,这些键分别指导工作区包含或排除特定的目录作为成员,并接受glob列表:

pyproject.toml

[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { workspace = true }

[tool.uv.workspace]
members = ["packages/*"]
exclude = ["packages/seeds"]

每个由 members glob 包含的目录(且不是由 exclude glob 排除的)都必须包含一个 pyproject.toml 文件。然而,工作空间成员可以是 任一 应用;两者在工作空间上下文中都受到支持。
每个工作空间都需要一个根,它也是一个工作空间成员。在上面的例子中,albatross 是工作空间的根,工作空间成员包括 packages 目录下的所有项目,但 seeds 除外。
默认情况下,uv runuv sync 在工作区根目录上运行。例如,在上面的例子中,uv runuv run --package albatross 是等效的,而 uv run --package bird-feeder 将在 bird-feeder 包中运行命令。


工作空间源

在一个工作空间中,通过tool.uv.sources促进了工作空间成员之间的依赖关系,如下所示:

pyproject.toml

[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { workspace = true }

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

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

在这个示例中,albatross 项目依赖于 bird-feeder 项目,后者是工作空间的一个成员。tool.uv.sources 表中的 workspace = true 键值对表示 bird-feeder 依赖项应由工作空间提供,而不是从 PyPI 或其他注册表中获取。


注意:工作区成员之间的依赖关系是可编辑的。
任何在工作区根目录中的 tool.uv.sources 定义都适用于所有成员,除非在特定成员的 tool.uv.sources 中被覆盖。例如,给定以下 pyproject.toml
pyproject.toml

[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { workspace = true }
tqdm = { git = "https://github.com/tqdm/tqdm" }

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

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

每个工作空间成员默认会从GitHub安装tqdm,除非特定成员在其自己的tool.uv.sources表中覆盖了tqdm条目。


工作空间布局

最常见的工作空间布局可以想象为一个根项目以及一系列伴随的库。

例如,继续以上示例,这个工作空间在 albatross 有一个明确的根,packages 目录下有两个库(bird-feederseeds):

albatross
├── packages
│   ├── bird-feeder
│   │   ├── pyproject.toml
│   │   └── src
│   │       └── bird_feeder
│   │           ├── __init__.py
│   │           └── foo.py
│   └── seeds
│       ├── pyproject.toml
│       └── src
│           └── seeds
│               ├── __init__.py
│               └── bar.py
├── pyproject.toml
├── README.md
├── uv.lock
└── src
    └── albatross
        └── main.py

由于在 pyproject.toml 中排除了 seeds,该工作空间共有两个成员:albatross(根)和 bird-feeder


当使用(或不使用)工作区

工作区旨在简化在单个存储库内开发多个相互关联的包。随着代码库复杂性的增长,将其拆分为更小的、可组合的包可能会有所帮助,每个包都有自己的依赖和版本约束。

工作区有助于强制执行隔离和关注点的分离。例如,在uv中,我们为核心库和命令行界面有单独的包,这使得我们能够独立于CLI测试核心库,反之亦然。

工作区的一些其他常见用例包括:

  • 一个库,其中性能关键子例程实现在一个扩展模块中(Rust、C++等)。
  • 一个具有插件系统的库,其中每个插件都是一个单独的工作区包,依赖于根。

工作区适用于成员之间存在冲突要求或希望每个成员都有一个单独的虚拟环境的情况。在这种情况下,路径依赖通常更可取。例如,而不是将albatross及其成员分组在工作区中,您始终可以定义每个包为其独立的工程,将包间依赖定义为tool.uv.sources中的路径依赖:

pyproject.toml

[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["bird-feeder", "tqdm>=4,<5"]

[tool.uv.sources]
bird-feeder = { path = "packages/bird-feeder" }

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

这种方法传达了许多相同的优势,但允许对依赖项解析和虚拟环境管理进行更精细的控制(缺点是 uv run --package 现在不再可用;相反,必须从相关的包目录中运行命令)。
最后,uv的工作空间强制执行整个工作空间的单个requires-python,取所有成员requires-python值的交集。如果您需要支持在不受工作空间其余部分支持的Python版本上测试某个成员,您可能需要使用uv pip在单独的虚拟环境中安装该成员。


注意:由于 Python 不提供依赖隔离,uv 无法确保一个包只使用其声明的依赖而不会使用其他内容。对于工作空间特定来说,uv 无法确保包不会导入由另一个工作空间成员声明的依赖。


工具

工具是提供命令行界面的 Python 包。


注意:查看工具指南以了解如何使用工具界面——本文件讨论了工具管理的详细信息。


uv 工具 接口

uv 包含一个用于与工具交互的专用接口。可以使用 uv tool run 来调用工具,而不需要安装。在这种情况下,它们的依赖项会安装在一个临时的虚拟环境中,该环境与当前项目隔离。

由于运行工具而不安装它们是非常常见的,因此提供了一个 uvx 别名用于 uv tool run —— 这两个命令完全等价。为了简洁,文档将主要使用 uvx 而不是 uv tool run

工具也可以使用 uv tool install 进行安装,在这种情况下,它们的可执行文件将在 PATH 上可用——仍然使用一个隔离的虚拟环境,但在命令完成后不会删除。


执行与安装

在大多数情况下,使用 uvx 执行工具比安装工具更合适。如果您需要工具对系统上的其他程序可用,例如,如果您不控制的某个脚本需要该工具,或者您在一个 Docker 镜像中,并希望将工具提供给用户,那么安装工具是有用的。


工具环境

当使用 uvx 运行工具时,虚拟环境存储在 uv 缓存目录中,并被视为可丢弃的,即如果您运行 uv cache clean,环境将被删除。环境只缓存以减少重复调用的开销。如果环境被删除,将自动创建一个新的环境。

当使用 uv tool install 安装工具时,虚拟环境将在 uv 工具目录中创建。除非工具被卸载,否则环境不会删除。如果手动删除环境,则工具将无法运行。


工具版本

除非请求特定版本,否则 uv tool install 将安装请求工具的最新版本。uvx 将在首次调用时使用请求工具的最新可用版本 *。之后,除非请求不同版本、清理缓存或刷新缓存,否则 uvx 将使用缓存的工具版本。

例如,要运行 Ruff 的特定版本:

uvx ruff@0.6.0 --version
ruff 0.6.0

后续调用 uvx 将使用最新的版本,而不是缓存的版本。

uvx ruff --version
ruff 0.6.2

但是,如果发布了Ruff的新版本,除非刷新缓存,否则不会使用。
要请求 Ruff 的最新版本并刷新缓存,请使用 @latest 后缀:

uvx ruff@latest --version
0.6.2

一旦使用 uv tool install 安装了工具,uvx 将默认使用已安装的版本。
例如,在安装较旧版本的 Ruff 之后:

uv tool install ruff==0.5.0

ruffuvx ruff 的版本相同:

$ ruff --version
ruff 0.5.0
$ uvx ruff --version
ruff 0.5.0

然而,您可以通过明确请求最新版本来忽略已安装的版本,例如:

uvx ruff@latest --version
0.6.2

或者,通过使用 --isolated 标志,将避免刷新缓存但忽略已安装版本:

uvx --isolated ruff --version
0.6.2

uv 工具安装 也会尊重 {package}@{version}{package}@latest 指定符,例如:

uv tool install ruff@latest
$ uv tool install ruff@0.6.0

工具目录

默认情况下,uv 工具目录命名为 tools,位于 uv 应用程序状态目录中,例如,~/.local/share/uv/tools。位置可以通过 UV_TOOL_DIR 环境变量进行自定义。

要显示工具安装目录的路径:

uv tool dir

工具环境放置在与工具包同名的目录中,例如,.../tools/<name>


Important:
工具环境 旨在被直接修改。强烈建议永远不要手动修改工具环境,例如使用 pip 操作。


升级工具

工具环境可以通过 uv tool upgrade 进行升级,或者通过后续的 uv tool install 操作完全重新创建。

要升级工具环境中的所有包

uv tool upgrade black

要将单个包在工具环境中升级:

uv tool upgrade black --upgrade-package click

工具升级将尊重安装工具时提供的版本约束。例如,uv tool install black >=23,<24 后跟 uv tool upgrade black 将将 Black 升级到范围 >=23,<24 内的最新版本。
要替换版本约束,请使用 uv tool install 重新安装工具:

uv tool install black>=24

同样,工具升级将保留在安装工具时提供的设置。例如,uv tool install black --prerelease allow 然后跟 uv tool upgrade black 将保留 --prerelease allow 设置。


注意:工具升级将重新安装工具的可执行文件,即使它们没有改变。
要在升级过程中重新安装软件包,请使用 --reinstall--reinstall-package 选项。
要在工具环境中重新安装所有包

uv tool upgrade black --reinstall

要在工具环境中重新安装单个包:

uv tool upgrade black --reinstall-package click

包含额外的依赖

在工具执行期间可以包含额外的包:

uvx --with <extra-package> <tool>

并且,在工具安装期间:

uv tool install --with <extra-package> <tool-package>

--with 选项可以多次提供以包含额外的包。
The --with 选项支持包规范,因此可以请求特定版本:

uvx --with <extra-package>==<version> <tool-package>

如果请求的版本与工具包的要求冲突,包解析将失败,并且命令将出错。


工具可执行文件

工具可执行文件包括由 Python 包提供的所有控制台入口点、脚本入口点和二进制脚本。在 Unix 上,工具可执行文件被链接到 bin 目录,在 Windows 上则被复制。


bin 目录

可执行文件按照 XDG 标准安装到用户 bin 目录中,例如,~/.local/bin。与 uv 中的其他目录方案不同,XDG 标准在 所有平台 上使用,特别是包括 Windows 和 macOS —— 在这些平台上没有明确的替代位置来放置可执行文件。安装目录由第一个可用的环境变量确定:

  • $UV_TOOL_BIN_DIR
  • $XDG_BIN_HOME
  • $XDG_DATA_HOME/../bin
  • $HOME/.local/bin

工具包依赖提供的可执行文件不会安装。


路径 (PATH)

bin 目录必须包含在 PATH 变量中,以便工具的可执行文件可以从 shell 中访问。如果它不在 PATH 中,将会显示一个警告。可以使用 uv tool update-shell 命令将 bin 目录添加到常见 shell 配置文件中的 PATH


覆盖可执行文件

安装工具不会覆盖 bin 目录中先前未由 uv 安装的可执行文件。例如,如果使用 pipx 安装了一个工具,则 uv tool install 将会失败。可以使用 --force 标志来覆盖此行为。


uv run 的关系

调用 uv tool run <name>(或 uvx <name>)几乎等同于:

uv run --no-project --with <name> -- <name>

然而,在使用uv的工具接口时,有一些值得注意的差异:

  • --with 选项不是必需的——所需的软件包将从命令名称中推断出来。
  • 临时环境缓存在一个专用位置。
  • --no-project 标志不需要——工具总是独立于项目运行。
  • 如果一个工具已经安装,uv tool run 将使用已安装的版本,但 uv run 不会。
    如果工具不应该与项目隔离,例如在运行 pytestmypy 时,则应使用 uv run 而不是 uv tool run

Python 版本

一个 Python 版本由一个 Python 解释器(即 python 可执行文件)、标准库和其他支持文件组成。


管理和系统 Python 安装

由于系统通常已经存在一个 Python 安装,uv 支持发现 Python 版本。然而,uv 也支持 安装 Python 版本 本身。为了区分这两种类型的 Python 安装,uv 将其安装的 Python 版本称为 管理型 Python 安装,而将所有其他 Python 安装称为 系统型 Python 安装。


注意:uv无法区分操作系统安装的Python版本和由其他工具安装和管理的Python版本。例如,如果使用pyenv管理Python安装,在uv中仍将其视为系统 Python版本。


请求特定版本

在大多数 uv 命令中,可以使用 --python 标志请求特定的 Python 版本。例如,在创建虚拟环境时:

uv venv --python 3.11.6

uv 将确保 Python 3.11.6 可用——如果需要,则会下载并安装它——然后使用它创建虚拟环境。
以下 Python 版本请求格式均受支持:

  • <version> (e.g., 3, 3.12, 3.12.3)
  • <version-specifier> (e.g., >=3.12,<3.13)
  • <implementation> (e.g., cpython or cp)
  • <implementation>@<version> (e.g., cpython@3.12)
  • <implementation><version> (e.g., cpython3.12 or cp312)
  • <implementation><version-specifier> (e.g., cpython>=3.12,<3.13)
  • <implementation>-<version>-<os>-<arch>-<libc> (e.g., cpython-3.12.3-macos-aarch64-none)

此外,可以使用以下命令请求特定的系统 Python 解释器:

  • <executable-path> (e.g., /opt/homebrew/bin/python3)
  • <executable-name> (e.g., mypython3)
  • <install-dir> (e.g., /some/environment/)

默认情况下,uv会在系统上找不到Python版本时自动下载。

此行为可以通过python-downloads选项禁用


Python 版本文件

.python-version 文件可用于创建默认的 Python 版本请求。uv 会在工作目录及其父目录中搜索 .python-version 文件。如果未找到,uv 将检查用户级配置目录。可以使用上述描述的任何请求格式,尽管推荐使用版本号以提高与其他工具的互操作性。

可以使用 uv python pin 命令在当前目录中创建 .python-version 文件。

可以使用 uv python pin --global 命令在用户配置目录中创建全局 .python-version 文件。

可以使用 --no-config 禁用 .python-version 文件的发现。

uv 不会在项目或工作空间边界之外搜索 .python-version 文件(用户配置目录除外)。


安装 Python 版本

uv 包含了一系列可供下载的 macOS、Linux 和 Windows 的 CPython 和 PyPy 分发版。

提示:默认情况下,Python 版本会在需要时自动下载,而不使用 uv python install

要安装特定版本的 Python:

uv python install 3.12.3

要安装最新补丁版本:

uv python install 3.12

要安装满足约束条件的版本:

uv python install '>=3.8,<3.10'

要安装多个版本:

uv python install 3.9 3.10 3.11

要安装特定实现:

uv python install pypy

所有 Python 版本请求 格式都受支持,除非是用于请求本地解释器的那种,例如文件路径。

默认情况下,uv python install 将会验证是否已安装受管理的 Python 版本,或者安装最新版本。

如果存在 .python-version 文件,uv 将会安装文件中列出的 Python 版本。

需要多个 Python 版本的项目可以定义一个 .python-versions 文件。

如果存在,uv 将会安装文件中列出的所有 Python 版本。


Important: Python 可用的版本在每个 uv 发布版中都是固定的。要安装新的 Python 版本,你可能需要升级 uv。


安装 Python 可执行文件


Important: 支持安装 Python 可执行文件目前处于 预览 状态,这意味着该行为是实验性的,并且可能会发生变化。

要将 Python 可执行文件安装到您的 PATH 中,请提供 --preview 选项:

uv python install 3.12 --preview

这将安装一个请求版本的 Python 可执行文件到 ~/.local/bin 中,例如,作为 python3.12
Tip
如果 ~/.local/bin 不在您的 PATH 中,您可以使用 uv tool update-shell 来添加它。
要安装 pythonpython3 可执行文件,请包含 --default 选项:

uv python install 3.12 --default --preview

在安装 Python 可执行文件时,uv 只有在可执行文件由 uv 管理的情况下才会覆盖现有的可执行文件——例如,如果 ~/.local/bin/python3.12 已存在,uv 不会在没有 --force 标志的情况下覆盖它。
uv 将更新它管理的可执行文件。然而,它默认会优先选择每个 Python 小版本的最新补丁版本。例如:

uv python install 3.12.7 --preview  # Adds `python3.12` to `~/.local/bin`
$ uv python install 3.12.6 --preview  # Does not update `python3.12`
$ uv python install 3.12.8 --preview  # Updates `python3.12` to point to 3.12.8

Python 项目版本

uv 将在项目命令调用期间尊重 pyproject.toml 文件中定义的 requires-python 的 Python 要求。除非有其他请求,例如通过 .python-version 文件或 --python 标志,否则将使用与要求兼容的第一个 Python 版本。


查看可用的 Python 版本

要列出已安装和可用的 Python 版本:

uv python list

默认情况下,其他平台和旧补丁版本的下载被隐藏。
要查看所有版本:

uv python list --all-versions

要查看其他平台的 Python 版本:

uv python list --all-platforms

要排除下载并仅显示已安装的 Python 版本:

uv python list --only-installed

查看uv python list参考以获取更多详细信息。


查找 Python 可执行文件

要查找 Python 可执行文件,请使用 uv python find 命令:

uv python find

默认情况下,这将显示第一个可用的 Python 可执行文件的路径。有关可执行文件如何发现的详细信息,请参阅发现规则
此接口也支持许多 请求格式,例如,要查找具有 3.11 或更高版本的 Python 可执行文件:

uv python find '>=3.11'

默认情况下,uv python find 将包括虚拟环境中的 Python 版本。如果在工作目录或任何父目录中找到 .venv 目录,或者设置了 VIRTUAL_ENV 环境变量,它将优先于 PATH 中任何 Python 可执行文件。
要忽略虚拟环境,请使用 --system 标志:

uv python find --system

Python 版本的发现

在搜索 Python 版本时,以下位置会被检查:

  • UV_PYTHON_INSTALL_DIR 中的管理 Python 安装。
  • 作为 pythonpython3python3.x(在 macOS 和 Linux 上)或 python.exe(在 Windows 上)的 PATH 上的 Python 解释器。
  • 在 Windows 上,Windows 注册表中的 Python 解释器和 Microsoft Store 中的 Python 解释器(参见 py --list-paths),这些解释器与请求的版本匹配。

在某些情况下,uv 允许使用来自虚拟环境的 Python 版本。在这种情况下,虚拟环境中的解释器会在上述搜索安装之前进行检查,以确保其与请求的兼容性。有关详细信息,请参阅 pip 兼容的虚拟环境发现 文档。

在执行发现时,将忽略非可执行文件。每个发现的可执行文件都会查询元数据以确保它满足 请求的 Python 版本。如果查询失败,则跳过该可执行文件。如果可执行文件满足请求,则使用它而无需检查其他可执行文件。

在搜索管理 Python 版本时,uv 将优先考虑较新版本。在搜索系统 Python 版本时,uv 将使用第一个兼容版本——而不是最新版本。

如果系统上找不到 Python 版本,uv 将检查兼容的管理 Python 版本下载。


Python 预发布版本

Python 预发布版本默认不会被选中。如果请求中没有其他可用的安装版本匹配,将使用 Python 预发布版本。例如,如果只有预发布版本可用,则将使用该版本,但否则将使用稳定发布版本。同样,如果提供了预发布 Python 可执行文件的路径,则没有其他 Python 版本与请求匹配,将使用预发布版本。

如果可用的预发布 Python 版本与请求匹配,uv 将不会下载稳定版本的 Python,而是使用预发布版本。


禁用自动 Python 下载

默认情况下,uv 将在需要时自动下载 Python 版本。

可以使用 python-downloads 选项 来禁用此行为。默认情况下,它设置为 automatic;设置为 manual 以仅允许在 uv python install 期间下载 Python。

提示:
python-downloads 设置可以在 持久性配置文件 中设置,以更改默认行为,或者可以将 --no-python-downloads 标志传递给任何 uv 命令。


需求或禁用托管 Python 版本

默认情况下,uv 将尝试使用系统上找到的 Python 版本,并且仅在必要时才下载托管 Python 版本。要忽略系统 Python 版本,并仅使用托管 Python 版本,请使用 --managed-python 标志:

uv python list --managed-python

同样,要忽略管理版Python版本,仅使用系统Python版本,请使用 --no-managed-python 标志:

uv python list --no-managed-python

要更改uv在配置文件中的默认行为,请使用python-preference设置


调整 Python 版本偏好

python-preference 设置确定是否优先使用系统上已存在的 Python 安装,还是使用 uv 下载和安装的 Python。

默认情况下,python-preference 被设置为 managed,这表示优先使用管理的 Python 安装,而不是系统 Python 安装。然而,系统 Python 安装仍然比下载管理的 Python 版本更受青睐。

以下可用的替代选项包括:

  • only-managed:仅使用管理的 Python 安装;从不使用系统 Python 安装。等同于 --managed-python
  • system:优先使用系统 Python 安装,而不是管理的 Python 安装。
  • only-system:仅使用系统 Python 安装;从不使用管理的 Python 安装。等同于 --no-managed-python

注意:可以在不更改首选项的情况下禁用自动 Python 版本下载 禁用


Python 实现支持

uv 支持 CPython、PyPy 和 GraalPy Python 实现。如果某个 Python 实现不受支持,uv 将无法发现其解释器。

可以使用长名或短名请求实现:

  • CPython: cpython, cp
  • PyPy: pypy, pp
  • GraalPy: graalpy, gp

实现名称请求不区分大小写。

有关支持的格式的更多详细信息,请参阅Python 版本请求文档。


管理Python发行版

uv支持下载和安装CPython和PyPy发行版。


CPython 发行版

由于 Python 不发布官方可分发的 CPython 二进制文件,uv 因此使用 Astral 项目中预先构建的发行版,即 python-build-standalone python-build-standalonepython-build-standalone 也被许多其他 Python 项目使用,例如 RyeMise,以及 bazelbuild/rules_python

uv 的 Python 发行版是自包含的,高度可移植且性能出色。虽然 Python 可以从源代码构建,就像 pyenv 这样的工具一样,但这样做需要预先安装的系统依赖项,并且创建优化、性能出色的构建(例如,启用 PGO 和 LTO)非常缓慢。

这些发行版存在一些行为上的奇怪之处,通常是由于可移植性造成的;并且,目前 uv 不支持在基于 musl 的 Linux 发行版(如 Alpine Linux)上安装它们。有关详细信息,请参阅 python-build-standalone 的奇怪之处 文档。




分辨率

https://docs.astral.sh/uv/concepts/resolution/

分辨率是将一系列需求转换为满足这些需求的包版本列表的过程。分辨率需要递归地搜索兼容的包版本,确保满足请求的需求,并且请求的包的需求是兼容的。


依赖项

大多数项目和软件包都有依赖项。依赖项是其他必要的软件包,以便当前软件包能够正常工作。一个软件包将其依赖项定义为 需求,大致是软件包名称和可接受版本的组合。当前项目定义的依赖项称为 直接依赖项。当前项目每个依赖项添加的依赖项称为 间接依赖项传递依赖项


注意:有关依赖项的详细信息,请参阅 Python 打包文档中的依赖项指定器页面


基本示例

为了帮助演示解决过程,考虑以下依赖关系:

  • 项目依赖于 foobar
  • foo 有一个版本,1.0.0:
    • foo 1.0.0 依赖于 lib>=1.0.0
  • bar 有一个版本,1.0.0:
    • bar 1.0.0 依赖于 lib>=2.0.0
  • lib 有两个版本,1.0.0 和 2.0.0。这两个版本都没有依赖关系。

在这个例子中,解析器必须找到一组满足项目要求的软件包版本。由于 foobar 都只有一个版本,所以将使用这些版本。解析还必须包括传递依赖项,因此必须选择一个 lib 的版本。foo 1.0.0 允许所有可用的 lib 版本,但 bar 1.0.0 需要 lib>=2.0.0,所以必须使用 lib 2.0.0
在某些决议中,可能会有多个有效解决方案。考虑以下依赖关系:

  • 该项目依赖于 foobar

  • foo 有两个版本,1.0.0 和 2.0.0:

  • foo 1.0.0 没有依赖项。

  • foo 2.0.0 依赖于 lib==2.0.0.

  • bar 有两个版本,1.0.0 和 2.0.0:

  • bar 1.0.0 没有依赖项。

  • bar 2.0.0 依赖于 lib==1.0.0

  • lib 有两个版本,1.0.0 和 2.0.0。这两个版本都没有依赖项。

在这个例子中,必须选择 foobar 的某个版本;然而,确定哪个版本需要考虑 foobar 每个版本的依赖关系。foo 2.0.0bar 2.0.0 不能一起安装,因为它们在所需的 lib 版本上存在冲突,所以解析器必须选择 foo 1.0.0(以及 bar 2.0.0)或 bar 1.0.0(以及 foo 1.0.0)。这两种解决方案都是有效的,不同的解析算法可能会产生任一结果。


平台标记

标记允许将一个表达式附加到要求中,以指示何时应使用依赖项。例如 bar ; python_version < "3.9" 表示 bar 只应安装在 Python 3.8 及更早版本上。

标记用于根据当前环境或平台调整包的依赖项。例如,可以使用标记根据操作系统、CPU 架构、Python 版本、Python 实现 等 修改依赖项。


注意:有关标记的更多详细信息,请参阅 Python 打包文档中的环境标记部分。
标记对于解析非常重要,因为它们的值会改变所需的依赖。通常,Python包解析器使用当前平台的标记来确定使用哪些依赖,因为包通常是在当前平台上安装的。然而,对于锁定依赖项来说,这是一个问题——锁定文件只为在创建锁定文件的同平台上使用的开发者工作。为了解决这个问题,存在平台无关的,或者称为“通用”的解析器。
uv 支持平台特定 平台特定通用 分辨率。


平台特定解析

默认情况下,uv 的 pip 接口,即 uv pip compile,生成的解析结果是平台特定的,类似于 pip-tools。在 uv 的项目接口中无法使用平台特定解析。

uv 还支持使用 --python-platform--python-version 选项解析特定、替代平台和 Python 版本。例如,如果在使用 macOS 上的 Python 3.12,可以使用 uv pip compile --python-platform linux --python-version 3.10 requirements.in 来生成针对 Linux 上 Python 3.10 的解析结果。与通用解析不同,在平台特定解析期间,提供的 --python-version 是要使用的确切 Python 版本,而不是下限。


注意:Python的环境标记比简单的--python-platform参数能暴露出更多关于当前机器的信息。例如,macOS上的platform_version标记包括内核构建的时间,这在理论上可以编码在包需求中。uv的解析器会尽力生成一个与在目标--python-platform上运行的任何机器兼容的解析,这对于大多数用例应该是足够的,但对于复杂的包和平台组合可能会丢失精度。


全局解析

uv 的锁文件 (uv.lock) 使用全局解析创建,可以在各个平台上移植。这确保了依赖项对所有参与项目工作的人都被锁定,无论操作系统、架构和 Python 版本如何。uv 锁文件由 uv lockuv syncuv add 等项目命令创建和修改。

全局解析也适用于 uv 的 pip 接口,即 uv pip compile,使用 --universal 标志。生成的需求文件将包含标记,指示每个依赖项相关的平台。

在全局解析过程中,如果针对不同的平台需要不同的版本,一个包可能会被列出多次,具有不同的版本或 URL。标记确定将使用哪个版本。全局解析通常比特定平台的解析更具约束性,因为我们需要考虑所有标记的需求。

在全局解析过程中,所有必需的包必须与 pyproject.toml 中声明的 requires-python 的整个范围兼容。例如,如果项目的 requires-python>=3.8,则如果所有给定依赖项的版本都需要 Python 3.9 或更高版本,解析将失败,因为该依赖项缺乏适用于(例如)Python 3.8(项目支持的最低版本)的可用版本。换句话说,项目的 requires-python 必须是其所有依赖项 requires-python 的子集。

在为给定依赖项选择兼容版本时,uv 将 (默认情况下) 尝试为每个支持的 Python 版本选择每个支持的 Python 版本的最新兼容版本。例如,如果项目的 requires-python>=3.8,并且一个依赖项的最新版本需要 Python 3.9 或更高版本,而所有之前的版本都支持 Python 3.8,则解析器将为运行 Python 3.9 或更高版本的用户选择最新版本,并为运行 Python 3.8 的用户选择之前的版本。

在评估依赖项的 requires-python 范围时,uv 只考虑下限并完全忽略上限。例如,>=3.8, <4 被视为 >=3.8。尊重 requires-python 的上限往往会导致形式上正确但实际不正确的解析,例如,解析器会回溯到第一个省略上限的已发布版本(参见:Requires-Python 上限)。


限制分辨率环境

默认情况下,通用解析器尝试解决所有平台和 Python 版本。

如果你的项目只支持有限的一组平台或 Python 版本,你可以通过 environments 设置来限制解析平台集,该设置接受一个 PEP 508 环境标记 列表。换句话说,你可以使用 environments 设置来 减少 支持的平台集。

例如,要将锁文件限制在 macOS 和 Linux 上,并避免为 Windows 解决:

pyproject.toml

[tool.uv]
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]

或者,为了避免为替代 Python 实现:
pyproject.toml

[tool.uv]
environments = [
    "implementation_name == 'cpython'"
]

环境设置中的条目必须是互斥的(即它们不能重叠)。例如,sys_platform == 'darwin'sys_platform == 'linux' 是互斥的,但 sys_platform == 'darwin'python_version >= '3.9' 不是,因为它们可能同时为真。


必需的环境

在 Python 生态系统中,软件包可以以源分布、构建分布(wheels)或两者兼有的方式发布;但安装一个软件包需要构建分布。如果一个软件包缺少构建分布,或者缺少针对当前平台或 Python 版本的分布(构建分布通常是特定平台的),uv 将尝试从源代码构建该软件包,然后安装生成的构建分布。

一些软件包(如 PyTorch)发布构建分布,但省略了源分布。这样的软件包 可以在提供构建分布的平台上进行安装。例如,如果一个软件包为 Linux 发布构建分布,但不为 macOS 或 Windows 发布,那么该软件包 可以在 Windows 上安装。

缺少源分布的软件包会导致通用解析出现问题,因为通常至少会有一个平台或 Python 版本,该软件包在这些平台上无法安装。

默认情况下,uv 要求每个这样的软件包至少包含一个与目标 Python 版本兼容的 wheel。可以使用 required-environments 设置来确保生成的解析包含特定平台的 wheels,或者在不可用的情况下失败。该设置接受一个 PEP 508 环境标记 列表。

虽然 environments 设置 限制 uv 在解析依赖关系时考虑的环境集,但 required-environments 扩展 uv 在解析依赖关系时必须支持的平台的集。

例如,environments = ["sys_platform == 'darwin'"] 将限制 uv 仅解决 macOS(并忽略 Linux 和 Windows)。另一方面,required-environments = ["sys_platform == 'darwin'"]要求 任何缺少源分布的软件包包含一个适用于 macOS 的 wheel 才能安装(如果不可用,则失败)。

在实践中,required-environments 可以用于声明对非最新平台的显式支持,因为这通常需要回溯到那些软件包的最新发布版本。例如,为了确保任何仅包含构建分布的软件包都包含对 Intel macOS 的支持:

pyproject.toml

[tool.uv]
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'"
]

依赖项偏好

如果存在解析输出文件,即 uv 锁文件 (uv.lock) 或需求输出文件 (requirements.txt),uv 将 优先 使用那里列出的依赖项版本。同样,如果在虚拟环境中安装包,uv 将优先使用已安装的版本(如果存在)。这意味着,除非请求了不兼容的版本或明确使用 --upgrade 请求升级,否则锁定或安装的版本不会更改。


解决方案策略

默认情况下,uv 尝试使用每个包的最新版本。例如,uv pip install flask>=2.0.0 将安装 Flask 的最新版本,例如 3.0.0。如果 flask>=2.0.0 是项目的依赖项,则只会使用 Flask 3.0.0。这很重要,例如,因为运行测试将不会检查项目是否实际上与其声明的 flask 2.0.0 的最低版本兼容。

使用 --resolution lowest,uv 将为所有依赖项安装最低可能的版本,包括直接和间接(传递性)依赖项。或者,--resolution lowest-direct 将使用所有直接依赖项的最低兼容版本,同时使用所有其他依赖项的最新兼容版本。uv 总是使用最新版本为构建依赖项。

例如,给定以下 requirements.in 文件:

requirements.in

flask>=2.0.0

运行 uv pip compile requirements.in 将生成以下 requirements.txt 文件:
requirements.txt

# This file was autogenerated by uv via the following command:
#    uv pip compile requirements.in
blinker==1.7.0
    # via flask
click==8.1.7
    # via flask
flask==3.0.0
itsdangerous==2.1.2
    # via flask
jinja2==3.1.2
    # via flask
markupsafe==2.1.3
    # via
    #   jinja2
    #   werkzeug
werkzeug==3.0.1
    # via flask

然而,uv pip compile --resolution lowest requirements.in 将会生成:
requirements.in

# This file was autogenerated by uv via the following command:
#    uv pip compile requirements.in --resolution lowest
click==7.1.2
    # via flask
flask==2.0.0
itsdangerous==2.0.0
    # via flask
jinja2==3.0.0
    # via flask
markupsafe==2.0.0
    # via jinja2
werkzeug==2.0.0
    # via flask

发布库时,建议在持续集成中单独运行带有 --resolution lowest--resolution lowest-direct 的测试,以确保与声明的较低界限兼容。


预发布版本处理

默认情况下,uv 在依赖项解析过程中会在两种情况下接受预发布版本:

  1. 如果包是一个直接依赖项,并且其版本指定符包括一个预发布指定符(例如,flask>=2.0.0rc1)。
  2. 如果 所有 发布的版本都是预发布版本。

如果由于传递性预发布版本导致依赖项解析失败,uv 将提示使用 --prerelease allow 以允许所有依赖项使用预发布版本。

或者,可以将传递性依赖项添加为 约束 或直接依赖项(即在 requirements.inpyproject.toml 中),并使用预发布版本指定符(例如,flask>=2.0.0rc1)来选择性地为该特定依赖项启用预发布支持。

预发布版本 众所周知很难 进行建模,并且是其他打包工具中频繁出现错误的原因。uv 的预发布处理是 有意 限制的,并且需要用户选择性地启用预发布版本以确保正确性。

有关更多详细信息,请参阅 预发布兼容性


多版本解析

在全局解析过程中,一个包可能在同一锁定文件中多次列出,具有不同的版本或URL,因为不同平台或Python版本可能需要不同的版本。

可以使用 --fork-strategy 设置来控制uv如何在(1)最小化所选版本数量和(2)为每个平台选择最新可能版本之间进行权衡。前者会导致跨平台的一致性更高,而后者则会导致尽可能使用较新的包版本。

默认情况下(--fork-strategy requires-python),uv将优化选择每个支持Python版本的每个包的最新版本,同时最小化跨平台所选版本的数量。

例如,当解析具有Python要求 >=3.8numpy 时,uv将选择以下版本:

numpy==1.24.4 ; python_version == "3.8"
numpy==2.0.2 ; python_version == "3.9"
numpy==2.2.0 ; python_version >= "3.10"

此决议反映了以下事实:NumPy 2.2.0 及更高版本至少需要 Python 3.10,而早期版本与 Python 3.8 和 3.9 兼容。
--fork-strategy fewest 下,uv 将会最小化每个包所选版本的数量,优先选择与更广泛的受支持 Python 版本或平台兼容的较旧版本。
例如,在上面的场景中,uv 会为所有 Python 版本选择 numpy==1.24.4,而不是将 Python 3.9 升级到 numpy==2.0.2,将 Python 3.10 及以后的版本升级到 numpy==2.2.0


依赖约束

与pip类似,uv支持约束文件(--constraint constraints.txt),这可以缩小给定包可接受版本的集合。约束文件类似于需求文件,但仅作为约束列出并不会导致包被包含在解决过程中。相反,只有当请求的包已经被作为直接或间接依赖项拉入时,约束才会生效。约束对于减少间接依赖项的可用版本范围很有用。它们还可以用于保持解决过程与其他一些已解决版本集同步,无论两个集合之间重叠的包是哪些。


依赖项覆盖

依赖项覆盖允许通过覆盖包声明的依赖项来绕过不成功或不理想的解析。覆盖在你知道某个依赖项与包的某个版本兼容,尽管元数据表明否则的情况下非常有用。

例如,如果一个传递依赖项声明了要求 pydantic>=1.0,<2.0,但确实与 pydantic>=2.0 一起工作,用户可以通过在覆盖中包含 pydantic>=1.0,<3 来覆盖声明的依赖项,从而允许解析器选择 pydantic 的新版本。

具体来说,如果 pydantic>=1.0,<3 被包含为覆盖项,uv 将忽略对 pydantic 的所有声明要求,用覆盖项替换它们。在上面的例子中,pydantic>=1.0,<2.0 要求将被完全忽略,并替换为 pydantic>=1.0,<3

虽然约束只能 减少 包可接受版本的集合,但覆盖可以 扩展 可接受版本的集合,为错误的上限版本提供逃生门。与约束一样,覆盖不会添加对包的依赖,并且仅在直接或传递依赖项请求包时才生效。

pyproject.toml 中,使用 tool.uv.override-dependencies 来定义覆盖项的列表。在兼容 pip 的接口中,可以使用 --override 选项传递与约束文件格式相同的文件。

如果为同一包提供了多个覆盖项,必须使用 标记 来区分它们。如果一个包有带有标记的依赖项,在使用覆盖时将无条件替换它——无论标记评估为真或假都无关紧要。


依赖元数据

在解析过程中,uv 需要解析它遇到的每个包的元数据,以确定其依赖项。此元数据通常作为包索引中的静态文件提供;然而,对于仅提供源分布的包,可能无法提前获得元数据。

在这种情况下,uv 必须构建该包以确定其元数据(例如,通过调用 setup.py)。这可能会在解析过程中引入性能惩罚。此外,它还要求该包可以在所有平台上构建,这可能并不成立。

例如,您可能有一个仅应在 Linux 上构建和安装的包,但在 macOS 或 Windows 上无法成功构建。虽然 uv 可以为这种情况构造一个完全有效的锁文件,但这样做需要构建该包,这将导致在非 Linux 平台上失败。

tool.uv.dependency-metadata 表可以用来提前提供此类依赖项的静态元数据,从而允许 uv 跳过构建步骤并使用提供的元数据。

例如,为了提前提供 chumpy 的元数据,请将其 dependency-metadata 包含在 pyproject.toml 中:

[[tool.uv.dependency-metadata]]
name = "chumpy"
version = "0.70"
requires-dist = ["numpy>=1.8.1", "scipy>=0.13.0", "six>=1.11.0"]

这些声明旨在用于那些在最初声明静态元数据的包的情况,尽管它们对于需要禁用构建隔离的包也很有用。在这种情况下,提前声明包元数据可能比在解决包之前创建自定义构建环境更容易。
例如,您可以为 flash-attn 声明元数据,这样 uv 就可以在不从源代码构建包的情况下进行解析(这本身需要安装 torch):

[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["flash-attn"]

[tool.uv.sources]
flash-attn = { git = "https://github.com/Dao-AILab/flash-attention", tag = "v2.6.3" }

[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]

与依赖覆盖类似,tool.uv.dependency-metadata 也可以用于处理包的元数据不正确或不完整,或者包在包索引中不可用的情况。虽然依赖覆盖允许全局覆盖包的允许版本,但元数据覆盖允许覆盖特定包声明的元数据。


注意:在 tool.uv.dependency-metadata 中的 version 字段对于基于注册表的依赖项是可选的(如果省略,uv 将假设元数据适用于该软件包的所有版本),但对于直接 URL 依赖项(如 Git 依赖项)则是必需的。
tool.uv.dependency-metadata 表中的条目遵循 Metadata 2.3 规范,尽管 uv 只读取 nameversionrequires-distrequires-pythonprovides-extraversion 字段也被认为是可选的。如果省略,则将使用指定软件包的所有版本的元数据。


下限

默认情况下,uv add 会为依赖项添加下限,并且当使用 uv 管理项目时,如果直接依赖项没有下限,uv 将会发出警告。

在下限不是关键路径的情况下,下限并不是必须的,但在存在依赖项冲突的情况下,它们非常重要。例如,考虑一个需要两个包的项目,并且这两个包有冲突的依赖项。解析器需要检查两个包的所有版本组合,如果所有版本都冲突,则会报告错误,因为依赖项无法满足。如果没有下限,解析器可以(并且通常会的)回溯到包的最老版本。这不仅因为它是慢的,老版本的包通常无法构建,或者解析器可能会选择一个足够旧的版本,以至于它不依赖于冲突的包,但也不与您的代码兼容,这也是一个问题。

当编写库时,下限尤为重要。声明您的库可以与之工作的每个依赖项的最低版本,并验证这些界限是否正确——可以通过测试 --resolution lowest--resolution lowest-direct(https://docs.astral.sh/uv/concepts/resolution/#resolution-strategy)来验证。否则,用户可能会收到您库的一个依赖项的老旧、不兼容版本,并且库会因意外错误而失败。


可复现的解决方案

uv 支持一个 --exclude-newer 选项,可以将解析限制在发布日期早于特定日期的分发版本上,从而允许在不考虑新包发布的情况下复现安装。日期可以指定为 RFC 3339 时间戳(例如,2006-12-02T02:07:43Z)或系统配置时区中的相同格式的本地日期(例如,2006-12-02)。

请注意,包索引必须支持在 PEP 700 中指定的 upload-time 字段。如果给定分发的字段不存在,则该分发将被视为不可用。PyPI 为所有包提供 upload-time

为了确保可复现性,不满足解析的消息将不会提及由于 --exclude-newer 标志而排除了分发——新的分发将被视为不存在。


注意:--exclude-newer 选项仅适用于从注册表(例如,与 Git 依赖项相对)中读取的软件包。此外,当使用 uv pip 接口时,uv 不会降级之前已安装的软件包,除非提供了 --reinstall 标志,在这种情况下,uv 将执行新的解析。


源代码分发

PEP 625 规定,软件包必须以 gzip tarball (.tar.gz) 归档文件的形式分发源代码分发。在此规范之前,其他需要为向后兼容性而支持的归档格式也被允许。uv 支持以下格式的归档文件的读取和提取:

  • gzip tarball (.tar.gz, .tgz)
  • bzip2 tarball (.tar.bz2, .tbz)
  • xz tarball (.tar.xz, .txz)
  • zstd tarball (.tar.zst)
  • lzip tarball (.tar.lz)
  • lzma tarball (.tar.lzma)
  • zip (.zip)

了解更多

有关解析器内部细节的更多信息,请参阅 解析器参考 文档。



缓存


依赖缓存

uv 使用积极的缓存策略来避免重新下载(和重新构建)之前运行中已访问过的依赖项。

uv 的缓存语义的具体细节取决于依赖项的性质:

  • 对于注册表依赖项(如从 PyPI 下载的依赖项),uv 尊重 HTTP 缓存头。
  • 对于直接 URL 依赖项,uv 尊重 HTTP 缓存头,并且根据 URL 本身进行缓存。
  • 对于 Git 依赖项,uv 根据完全解析的 Git 提交哈希进行缓存。因此,uv pip compile 将 Git 依赖项固定到特定的提交哈希,当写入解析后的依赖项集时。
  • 对于本地依赖项,uv 根据源存档的最后修改时间进行缓存(即本地的 .whl.tar.gz 文件)。对于目录,uv 根据最后一个修改的 pyproject.tomlsetup.pysetup.cfg 文件进行缓存。

如果您遇到缓存问题,uv 包含几个逃生门:

  • 要强制 uv 重新验证所有依赖项的缓存数据,向任何命令传递 --refresh(例如,uv sync --refreshuv pip install --refresh ...)。
  • 要强制 uv 重新验证特定依赖项的缓存数据,向任何命令传递 --refresh-package(例如,uv sync --refresh-package flaskuv pip install --refresh-package flask ...)。
  • 要强制 uv 忽略现有的已安装版本,向任何安装命令传递 --reinstall(例如,uv sync --reinstalluv pip install --reinstall ...)。

作为一个特殊情况,uv 将始终重新构建并重新安装命令行上明确传递的任何本地目录依赖项(例如,uv pip install .)。


动态元数据

默认情况下,uv 将仅在目录根目录中的 pyproject.tomlsetup.pysetup.cfg 文件发生变化,或者添加或删除了 src 目录时,才会重新构建和重新安装本地目录依赖项(例如,可编辑项)。这是一个启发式方法,在某些情况下可能会导致比期望的更少的重新安装。

为了将附加信息纳入特定软件包的缓存键中,您可以在 tool.uv.cache-keys 下添加缓存键条目,这涵盖了文件路径和 Git 提交哈希。设置 tool.uv.cache-keys 将替换默认值,因此任何必要的文件(如 pyproject.toml)仍应包含在用户定义的缓存键中。

例如,如果项目在 pyproject.toml 中指定了依赖项,但使用 setuptools-scm 来管理其版本,因此应该在提交哈希或依赖项发生变化时重新构建,您可以将以下内容添加到项目的 pyproject.toml 中:

pyproject.toml

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true } }]

如果您动态元数据包含来自Git标签集的信息,您可以将缓存密钥扩展以包含标签:
pyproject.toml

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { git = { commit = true, tags = true } }]

同样,如果一个项目从 requirements.txt 读取以填充其依赖项,你可以在项目的 pyproject.toml 中添加以下内容:
pyproject.toml

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }]

全局匹配符支持用于 file 键,遵循 glob crate 的语法 glob。例如,要使缓存失效,每次项目目录或其任何子目录中的 .toml 文件被修改时,请使用以下命令:
pyproject.toml

[tool.uv]
cache-keys = [{ file = "**/*.toml" }]

注意:使用通配符可能很昂贵,因为 uv 可能需要遍历文件系统以确定是否有任何文件已更改。这反过来又可能需要遍历大型或深度嵌套的目录。
同样,如果项目依赖于环境变量,您可以将以下内容添加到项目的 pyproject.toml 中,以便在环境变量更改时使缓存失效:
pyproject.toml

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { env = "MY_ENV_VAR" }]

最后,为了在创建或删除特定目录(如 src)时使项目失效,将以下内容添加到项目的 pyproject.toml 文件中:
pyproject.toml

[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { dir = "src" }]

请注意,dir 键只会跟踪目录本身的更改,而不会跟踪目录内的任意更改。
作为一个逃生口,如果一个项目使用 dynamic 元数据,且不被 tool.uv.cache-keys 覆盖,你可以通过将项目添加到 tool.uv.reinstall-package 列表中来指示 uv 始终 重建和重新安装它:
pyproject.toml

[tool.uv]
reinstall-package = ["my-package"]

这将强制 uv 在每次运行时重新构建和重新安装 my-package,无论该包的 pyproject.tomlsetup.pysetup.cfg 文件是否已更改。


缓存安全

可以安全地并发运行多个 uv 命令,即使是对同一个虚拟环境。uv 的缓存设计为线程安全且仅可追加,因此对多个并发读取者和写入者非常健壮。uv 在安装时会将对目标虚拟环境的文件锁定,以避免跨进程的并发修改。

请注意,当其他 uv 命令正在运行时,不安全修改 uv 缓存(例如,uv cache clean),并且绝对不安全直接修改缓存(例如,通过删除文件或目录)。


清除缓存

uv 提供了几种不同的机制来从缓存中删除条目:

  • uv cache clean 从缓存目录中删除 所有 缓存条目,将其完全清除。
  • uv cache clean ruff 删除 ruff 包的所有缓存条目,这对于使单个或有限集的包的缓存无效很有用。
  • uv cache prune 删除所有 未使用 的缓存条目。例如,缓存目录可能包含在之前的 uv 版本中创建的条目,这些条目现在不再必要,可以安全地删除。uv cache prune 可以定期运行,以保持缓存目录的清洁。

持续集成中的缓存

在持续集成环境中(如GitHub Actions或GitLab CI)缓存包安装工件是一种常见的做法,以加快后续运行的效率。

默认情况下,uv会缓存从源代码构建的wheel文件以及直接下载的预构建wheel文件,以实现高性能的包安装。

然而,在持续集成环境中,保留预构建的wheel文件可能并不理想。使用uv时,我们发现通常从缓存中省略预构建的wheel文件(并在每次运行时从注册表重新下载它们)会更快。另一方面,缓存从源代码构建的wheel文件通常是有价值的,因为wheel构建过程可能成本较高,尤其是对于扩展模块。

为了支持这种缓存策略,uv提供了一个uv cache prune --ci命令,该命令会从缓存中删除所有预构建的wheel文件和未解压的源代码分发,但保留任何从源代码构建的wheel文件。我们建议在您的持续集成作业结束时运行uv cache prune --ci,以确保最大的缓存效率。有关示例,请参阅GitHub集成指南


缓存目录

uv 根据以下顺序确定缓存目录:

  1. 如果请求了 --no-cache,则使用临时缓存目录。
  2. 通过 --cache-dirUV_CACHE_DIRtool.uv.cache-dir 指定的特定缓存目录。
  3. 系统适当的缓存目录,例如,在 Unix 上是 $XDG_CACHE_HOME/uv$HOME/.cache/uv,在 Windows 上是 %LOCALAPPDATA%\uv\cache

注意:uv 总是需要一个缓存目录。当请求 --no-cache 时,uv 仍然会使用一个临时缓存来在该单个调用内部共享数据。
在大多数情况下,应使用 --refresh 而不是 --no-cache ——因为它将更新后续操作的缓存,但不会从缓存中读取。
缓存目录应位于 uv 运行的 Python 环境所在的同一文件系统上,这对于性能非常重要。否则,uv 将无法将缓存中的文件链接到环境中,而需要回退到缓慢的复制操作。


2025-03-24(一)



网站公告

今日签到

点亮在社区的每一天
去签到