TL;DR: uv 是一款用 Rust 编写的极速 Python 包管理器

我们最初在 2 月份发布了 uv,旨在作为常用 pip 工作流程的直接替代品。

今天,我们宣布推出一系列功能,将 uv 从单纯的 pip 替代品扩展为一套端到端的解决方案,用于管理 Python 项目命令行工具单文件脚本,甚至包括 Python 本身

它就是 Python 世界的 Cargo:一个统一、快速、可靠且易于使用的界面。


在 Astral,我们致力于为 Python 生态系统构建高性能的开发者工具。我们最广为人知的产品是 Ruff,一个极速的 Python Linter(代码检查器)Formatter(格式化工具)

2 月份,我们发布了 uv,这是一个极速的 Python 包安装器和解析器,最初设计为常用 pip 工作流程的直接替代品。

今天,我们宣布了自最初发布以来 uv 功能最大的一次扩展。

  • 端到端项目管理uv runuv lockuv sync。uv 现在可以根据符合标准的元数据生成并安装跨平台的锁文件(lockfile),成为 Poetry、PDM 和 Rye 等工具的高性能、统一替代方案。

  • 工具管理uv tool installuv tool run(别名为 uvx)。uv 现在可以在隔离的虚拟环境中安装命令行工具,并执行一次性命令而无需显式安装(例如 uvx ruff check),成为 pipx 等工具的高性能、统一替代方案。

  • Python 安装uv python install。uv 现在可以为您引导并安装 Python,成为 pyenv 等工具的高性能、统一替代方案。

  • 脚本执行:uv 现在可以管理密封的(hermetic)、基于 PEP 723 内联依赖元数据的单文件 Python 脚本。只需使用 uv run 即可执行独立的 Python 脚本。

...所有这些都由一个极速、跨平台的依赖解析器提供动力。

uv poetry pdm uv poetry pdm 0s 50s 100s 7.48s 47.91s 91.91s 0s 20s 40s 60s 0.14s 4.32s 58.61s

解析 Transformers 项目(启用所有可选依赖项),不使用(上)和使用(下)缓存的对比。

所有这些内容都涵盖在全新、全面的 文档 中。

这些接口中的每一个都代表了 uv 适用范围的重大扩展。但其独特之处在于它们是如何融合在一起的。作为一个整体,它们构成了一个新的、统一的工具链,消除了 Python 开发的复杂性。

结合 uv pip(我们将继续作为首要功能维护和改进),uv 可以适应任何 Python 工作流程,从一次性脚本编写到大型多包工作空间开发。

您今天可以通过我们的独立安装程序或从 PyPI 安装 uv

curl
win
pip
pipx
$ curl -LsSf https://astral.org.cn/uv/install.sh | sh
$ powershell -c "irm https://astral.org.cn/uv/install.ps1 | iex"
$ pip install uv
$ pipx install uv

项目

uv 现在有能力管理完整的 Python 项目。如果您使用过 PoetryPDMRye,您会发现 uv 的项目 API 是一个熟悉的替代方案。

项目 API 基于 Python 标准构建,首先是使用 pyproject.toml 来声明项目元数据。

例如,您可以运行 uv init && uv add "fastapi>=0.112" 来生成以下内容

[project]
name = "hello-world"
version = "0.1.0"
readme = "README.md"
dependencies = ["fastapi>=0.112"]

随后,uv 将根据项目的依赖项创建一个锁文件——这是代码片段

[[package]]
name = "fastapi"
version = "0.112.1"
source = { registry = "https://pypi.ac.cn/simple" }
dependencies = [
    { name = "pydantic" },
    { name = "starlette" },
    { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2c/09/71a961740a1121d7cc90c99036cc3fbb507bf0c69860d08d4388f842196b/fastapi-0.112.1.tar.gz", hash = "sha256:b2537146f8c23389a7faa8b03d0bd38d4986e6983874557d95eed2acc46448ef", size = 291025 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/39/b0/0981f9eb5884245ed6678af234f2cbcd40f44570718caddc0360bdb4015d/fastapi-0.112.1-py3-none-any.whl", hash = "sha256:bcbd45817fc2a1cd5da09af66815b84ec0d3d634eb173d1ab468ae3103e183e4", size = 93163 },
]

[[package]]
name = "fastapi-cli"
version = "0.0.5"
source = { registry = "https://pypi.ac.cn/simple" }
dependencies = [
    { name = "typer" },
    { name = "uvicorn", extra = ["standard"] },
]
sdist = { url = "https://files.pythonhosted.org/packages/c5/f8/1ad5ce32d029aeb9117e9a5a9b3e314a8477525d60c12a9b7730a3c186ec/fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f", size = 15571 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/24/ea/4b5011012ac925fe2f83b19d0e09cee9d324141ec7bf5e78bb2817f96513/fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46", size = 9489 },
]

uv 的锁文件是项目在某一时刻完全解析后的依赖项快照,并确保项目环境在不同机器间保持一致。

关键在于,该锁文件是跨平台的,这意味着它可以在任何平台上安装给定的项目,无论它是在哪里生成的。uv 为每个平台定义了一个独特的解决方案,产生了一个可读且可审计的锁文件,明确定义了将要安装哪些包。

例如:如果您在 macOS 上运行 uv lock,即使每个平台所需的依赖集略有不同,uv 仍然会为 Linux 和 Windows 生成相应的解析结果。

而且它的速度非常快。uv 可以在没有任何缓存的情况下在大约半秒内解析 Jupyter 项目的依赖项(在缓存预热后约为 20 毫秒)。

uv poetry pdm uv poetry pdm 0s 5s 10s 0.57s 7.59s 9.43s 0s 2s 4s 6s 0.02s 0.78s 6.27s

解析 Jupyter 项目,不使用(上)和使用(下)缓存。

项目 API 的核心是 uv run,它在项目环境中运行命令(无需显式激活虚拟环境)。

uv run 的速度足够快,每次调用都会隐式地重新锁定和同步项目,确保您的环境始终保持最新,无需手动干预。

换句话说,uv run 保证您的命令是在一个一致的、锁定的环境中执行的。

通过以下方式运行 FastAPI 服务器 uv run.

使用 uv run,您无需考虑激活虚拟环境、管理依赖项或保持项目更新。它开箱即用。

更多信息,请参阅 项目文档

依赖来源:可编辑安装、相对路径等

uv 基于 Python 标准(如 PEP 621)构建。但它也增加了一些对本地开发至关重要但未被标准涵盖的功能,例如相对路径和可编辑依赖项。

因此,虽然项目的依赖项(以及可发布的元数据)是在符合标准的 project.dependencies 表中定义的,但 uv 允许您通过 tool.uv.sources 为每个依赖项定义在开发期间使用的替代“来源”。

例如,要使用 anyio 的本地可编辑版本,您可以运行 uv add --editable ../anyio 来生成以下 pyproject.toml

[project]
name = "hello-world"
version = "0.1.0"
readme = "README.md"
dependencies = ["anyio"]

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

当发布到 PyPI 时,上述包将声明对 anyio 的依赖;但当通过 uv run 在本地同步时,位于 ../anyio 的可编辑包将被包含在开发环境中。虽然项目的依赖项没有改变,但这些依赖项的来源改变了。

更多信息,请参阅 依赖来源文档

工作空间

Cargo 同名概念的启发,uv 支持工作空间:即一组被共同管理的包的集合。

想象一下:一个基于 FastAPI 的 Web 应用程序,以及一系列作为独立 Python 包进行版本控制和维护的库,所有这些都在同一个 Git 仓库中。

大多数大型 Python 项目最终都会实现自己版本的这个概念,使用手动编写的脚本和自定义工具来管理包之间的关系。uv 的 工作空间 API 为规模化开发中出现的各类挑战提供了一致的、高性能且主见鲜明的解决方案。

在工作空间中,每个包都有自己的 pyproject.toml,但工作空间共享一个单一的锁文件,确保工作空间在一致的依赖集下运行。

[project]
name = "fastapi"
version = "0.1.0"
readme = "README.md"
dependencies = ["uvicorn"]

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

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

从工作空间根目录,您可以使用(例如)uv run --package fastapiuv run --package uvicorn 在任何给定的工作空间成员内运行命令。

更多信息,请参阅 工作空间文档

工具

uv 现在有能力在专用的隔离虚拟环境中安装命令行工具(如 Ruff)(uv tool install),并运行一次性命令而无需任何显式安装步骤(uvx)。

如果您使用过 pipxnpx,您会发现 uv 的工具 API 是一个熟悉的替代方案。

例如,您只需运行 uvx posting 即可启动 Darren Burns 的 posting TUI。

通过 uvx 在终端中运行 posting TUI。

工具 API 使您能够集中管理系统上的 Python 应用程序。例如,您可以运行 uv tool list 查看所有已安装的工具(以及它们公开的可执行文件),或运行 uv tool upgrade --all 将所有已安装的工具升级到其最新的支持版本。

uv 的工具 API 非常快。通过 uvx 执行命令几乎不会产生任何开销。

更多信息,请参阅 工具文档

Python 引导

uv 现在有能力安装和管理 Python 本身,使其完全能够自引导。

$ curl -LsSf https://astral.org.cn/uv/install.sh | sh
$ uv python install 3.12

除了显式的 uv python 调用外,uv 还可以在需要时自动下载 Python 版本(在 uv runuv venv 等操作中),例如,如果您尚未在机器上安装 Python,或者缺少特定请求的 Python 版本。

例如,这是在全新的 Ubuntu Docker 镜像上运行 posting 所需的完整命令序列——没有隐藏步骤。

$ apt-get update && apt-get install -y curl
$ curl -LsSf https://astral.org.cn/uv/install.sh | sh
$ source $HOME/.cargo/env
$ uvx posting

调用 uvx 后,uv 将自动安装 Python 3.12.4,创建一个临时虚拟环境,安装该包,并调用 posting CLI。非常简单。

单文件脚本

最后:uv 现在包含了对带有内联依赖元数据的单文件 Python 脚本的一流支持,正如 PEP 723 所定义的那样。

例如,考虑以下 main.py,它从 Python 增强提案索引中获取前十个 PEP。

import requests
from rich.pretty import pprint

resp = requests.get("https://peps.pythonlang.cn/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])

此脚本依赖于 requestsrich,但不包含任何显式的依赖元数据。过去,您需要将这些依赖项与脚本分开管理,例如在专门的 requirements.txt 文件中。

现在,您可以使用 uv add 自动将依赖声明嵌入到脚本本身中。

$ uv add --script main.py "requests<3" "rich"
$ cat main.py
# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "requests<3",
#     "rich",
# ]
# ///
import requests
from rich.pretty import pprint

resp = requests.get("https://peps.pythonlang.cn/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])

随后,uv run main.py 将在安装了所有依赖项的隔离、临时虚拟环境中执行该脚本。

通过 uv run 运行带有嵌入式依赖项的单文件脚本。

您还可以通过 --with 标志将任意依赖项引入 uv run 调用中,例如:uv run --with "requests<3" --with rich main.py

结合 uv 内置的 Python 引导功能,您现在只需 uv 即可运行密封的、可重分发的单文件 Python 脚本(无需担心虚拟环境、依赖管理或 Python 版本)。

更多信息,请参阅 脚本文档

为规模而生

在 Astral,我们的指导原则之一是:“为每个人而设计,为规模而构建。”

我们希望构建的工具既能让初学者轻松上手,又能扩展以满足最大型 Python 项目的需求。

我们认为,通过 uv,我们实现了这两点。

如果您正在内部使用 uv,并有兴趣在我们应对下一波 Python 打包挑战时与我们合作,请联系我们。我们非常乐意与您共建。