介绍

基于0.7.3 官方文档

python的包和项目管理器,类似maven和npm。 可以取代pip,pyenv等常用工具,且速度非常快。

Note

整体感觉就是快,且非常方便,提供的API符合直觉。

安装

Tip

个人测试环境:linux基于zsh, windows基于pwsh

# install
curl -LsSf https://astral.sh/uv/install.sh | sh
 
# add the following content to .zshrc
# expand $PATH
. "$HOME/.local/bin/env"
# auto complete
eval "$(uv generate-shell-completion zsh)"
eval "$(uvx --generate-shell-completion zsh)"
# install
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
 
# add the following content to $PROFILE
# expand $PATH
$env:Path = "$env:USERPROFILE\.local\bin;" + $env:Path
# auto complete
(& uv generate-shell-completion powershell) | Out-String | Invoke-Expression
(& uvx --generate-shell-completion powershell) | Out-String | Invoke-Expression

更新

uv self update

卸载

  1. clean data
uv cache clean
rm -r "$(uv python dir)"
rm -r "$(uv tool dir)"
  1. remove uv && uvx binaries
rm ~/.local/bin/uv ~/.local/bin/uvx

使用

Tip

就算使用pip安装的uv,依然不建议使用python -m uv来调用,会增加启动开销。

安装python

uv能自动探测系统已安装的python版本,并能使用,无需额外的配置。 实际上并不需要提前准备python版本,uv会在需要时自动下载。

Tip

uv将它安装的称为托管版本,其他称为系统版本(pyenv安装的也是)

# the version format can be version | implementation | path of python binary
# can install multiple versions at the same time
uv python install [--reinstall] <version> [<version> ...] | <implementation> | <path of python binary>

指定python版本

  1. 大部分命令都可以使用--python来指定python版本

    uv venv --python 3.12
  2. .python-version指定了当前项目的python版本。可以通过uv python pin生成这个文件

    uv python pin 3.12
    # user global config
    uv python pin --global 3.12

    uv会在当前目录以及父目录中递归查找.python-version文件,直至项目根目录,如果没有找到则去找用户配置的global版本。

    Caution

    .python-version中的版本不要和命令行中的指定的版本冲突,uv并不会自动解决。

    --no-config可以忽略.python-version文件。

    s文件可以定义多个版本

    .python-version

    upgrade uv.

    The available Python versions are frozen for each uv release. To install new Python versions, you may need

安装全局版本

可以被安装为PATH。但是这是一个preview特性。

# the feature is experimental
# --defalut will install python and python3
uv python install 3.12 --default --preview

如果不想这样,又想达到全局安装的目的,可以:

  1. 将指定的venv/bin添加到PATH
  2. alias python=uv run python

find

uv python find显示的是uv python list第一个可用版本。

运行脚本

可以直接运行脚本,且支持临时依赖。

Important

When your script requires other packages, they must be installed into the environment that the script runs in. uv prefers to create these environments on-demand instead of using a long-lived virtual environment with manually managed dependencies.

uv run会调用当前的.venv环境,如果存在的话。

# run script file
uv run foo.py
# from stdin, just like normal linux command
echo 'print("hello world")' | uv run -
 
# run command
uv run <command> [<arg> ...]
# python command provides by uv
uv run python -c 'print("hello world")'
# presuming the project provides `example-cli`
uv run example-cli foo
# running a `bash` script that requires the project to be available(command must be existed outsite of the project)
uv run bash scripts/foo.sh

运行添加临时依赖:

# multiple dependencies can be requested by repeating with `--with` option
uv run --with rich foo.py
# specify version
uv run --with 'rich>12,<13' foo.py

inline script

这是python新支持的特性。

  1. 简单脚本可以直接使用--with引入依赖
  2. 更复杂点可以使用inline script,在单文件中定义依赖
  3. 使用常规的project模式,有完整的虚拟环境

创建inline script:

# init script and specified python version
uv init --script foo.py --python 3.12
# add dependencies
uv add --script foo.py 'requests<3' 'rich'

此时的foo.py:

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "requests<3",
#   "rich",
# ]
# ///
 
# your python code
type Point = tuple[float, float]
print(Point)
...

可以运行:

uv run foo.py

Important

inline script的环境是独立于项目的。

shebang mode

添加以下shebang即可:

#!/usr/bin/env -S uv run --script

Tool

tool也是python package,且一般提供了命令行接口,uv中可以快速调用工具。

运行tool

tool使用单独的环境运行(这也是uv的特点),除非使用install否则命令运行完后环境会被清理。

uv tool run <tool>
# alias
uvx <tool>

完整的写法: 只有当2个名字一样时,可以省略--from

uvx --from <tool_name> <command_name>

例子:

uvx ruff@0.3.0 check
uvx ruff@latest check
uvx --from 'ruff==0.3.0' ruff check
uvx --from 'ruff>0.2.0,<0.3.0' ruff check
# with extras [] feature
uvx --from 'mypy[faster-cache,reports]' mypy --xml-report mypy_report

还可以从github中直接获取tool运行,非常灵活了:

# default commit
uvx --from git+https://github.com/httpie/cli httpie
# last commit from specific branch
uvx --from git+https://github.com/httpie/cli@master httpie
# specific tag
uvx --from git+https://github.com/httpie/cli@3.2.4 httpie
# specific commit
uvx --from git+https://github.com/httpie/cli@2843b87 httpie

安装tool

运行tool本质是一种临时一次性的,对于常用的tool应该进行安装。

Note

安装的可能是python脚本(black)或者编译的二进制文件(ruff),取决于包是否提供了对应的版本。

uv tool install <tool_name>

安装完后uvx默认也会使用这个安装版本,例如:

uvx install ruff
# the following commands are equivalent
ruff --version
uvx ruff --version

install的本质是将tool的可执行文件放入XDG规范的bin目录下(通常是~/.local/bin),并且在PATH中添加这个目录,如果没有,可以使用uv tool update-shell更新PATH 对于已存在的命令,如果不是uv之前安装过的,不会被覆盖,可以使用--force来强制覆盖。

更新tool

对于installed tool,可以更新,更新不会破坏安装时的版本约束,并且会保留原来传递的设置,比如--prerelease allow,如果需要破坏,可以重新install

uv run的关系

实际上uv run --no-project --with <tool> <command>也能达到运行tool的效果 但是uv run侧重于在项目中运行,而uv tool run侧重于提供单独的tool。 实现不同,tool是可复用已安装的,但是uv run不会。

uv tool upgrade <tool_name> | --all

Note

另uv中几乎所有行为都可以用--python来指定版本。

可选依赖

类似uv run,tool runinstall中可以使用--with来引入额外的依赖,但要注意和tool package本身依赖之间的冲突。

在项目中使用

这也是最常见,最复杂的场景了。

关键概念

  1. pyproject.toml 为整个项目的metadata,包括基本信息,依赖,脚本等等,和package.json很像,特别是依赖同样是指定的范围,这也是为了方便小版本更新,比如bug修复

  2. lock and sync uv.lock文件记录了依赖的具体版本和python的版本约束,便于跨平台使用,以确保环境完全一致,同样类似package-lock.jsonuv.lock永远不要手动修改,应通过uv lock生成,uv lock本质是根据pyproject.toml来更新uv.lock文件,以确保uv.lock中的版本符合pyproject.toml中的约束。 如果希望更新package,直接uv lock是没用的,需要使用uv lock --upgrade-package <package>,此时才会更新uv.lock中的版本。

    uv lock | sync | run --upgrade-package <package>[=<version>] | --upgrade

    最后还需要uv sync刷新整个环境(根据lockfile文件更新.venv中的具体package),以确保一致。 实际上uv run的时候会先uv lockuv sync来确保环境up-to-date,最后才会去执行run

    Note

    uv中的locking和syncing是自动的。

    如果不想自动lock,可以使用--locked选项,这个选项仅仅是跳过uv lock,但是如果lockfile不是最新的,uv会报错(避免修改lockfile) 也就是只执行了检查:

    uv lock --check

    如果想完全跳过lockfile的检查:

    uv run --frozen

    如果想跳过sync

    uv run --no-sync

    sync时,uv会以--editable install这个project,如果project配置了build-system。

    Tip

    项目本身也是会被安装进项目的环境中的,如果配置了build-system。

    sync其他用法:

    • uv sync --inexact 不会删除多余的依赖,默认会清除
    • uv sync --extra <extra> | --all-extras 同步额外的依赖
    • uv sync --no-install-project 不安装project本身,只安装依赖
    • uv sync --no-install-workspace 不安装workspace的任何成员
    • uv sync --no-install-package <package> 不安装指定package
  3. export lockfile 为了便于和其他工具集成,可以导出lockfile文件:

    uv export --format requirements.txt | pylock.toml

    requirements.txt可以通过uv pip install -r requirements.txt一次性安装。

  4. .python-version 这里记录了python版本,可以视为--python

创建项目

基本用法:

uv init <target_dir>
# or use pwd
uv init
  1. Application projects init的默认target。适用于web服务等完整应用

  2. Packaged applications 通常是可以被执行的,比如ruff,black等

    uv init --package example-pkg
  3. Libraries 狭义上包,可以被import,一个lib总是需要被packaged,所以--lib也意味着--package,本质就是需要build

    uv init --lib example-lib

Tip

uv还支持maturinscikit-build-core构建系统,他们可以正确打包其他语言编写的模块。

简洁模式: uv init默认会创建很多文件,包括vcs比如git 可以使用--bare创建一个minimal project,仅包含pyproject.toml文件,且文件中只有最基本的信息。 当然依然可以使用--description,--author-from,--vcs之类的主动补充信息。

配置项目

python version

通过project.requires-python配置。 项目的依赖也要支持这个版本。

entry points

Tip

只针对定义了build-system的项目。

  • command-line interface 项目的命令行接口

    [project.scripts]
    hello = "example:hello"
    uv run hello # run example module's hello function
  • gui interface

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

    本质和comand line一样,只是由对应的gui程序启动

  • plugin entry points 可以将包注册为插件,被其他项目发现使用。

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

    在其他项目如果安装了这个插件,可以通过importlib.metadata加载这个插件:

    from importlib.metadata import entry_points
     
    for plugin in entry_points(group='example.plugins'):
        plugin.load()

    Note

    并不需要手动import插件,插件只要提供了entry-points,就可以动态加载。

build system

当前项目没有定义build-system,不会被build and install进项目环境(除非强制设置tool.uv.package=true), 但是外部包不管有没有定义build-system,都会被安装,没有则使用默认的setuptools.build_meta:__legacy__

project environment path

默认是.venv,可以通过修改UV_PROJECT_ENVIRONMENT环境变量来修改。

可以使用相对路径和绝对路径,相对路径是相对于项目根目录。 绝对路径的使用是非常危险的,因为多个项目会共用,后面的会覆盖前面的,所以一般只建议在docker中使用。

environments
[tool.uv]
# 支持运行的环境,不要和打包环境混淆
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]
# 需要这个环境下才能打包运行,这个只在发布built distribution才有效,对于source distribution无效
# 本质上二进制版都是有环境要求的,比如依赖平台库
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
build isolation

安装依赖时,每个依赖都会创建独立的build环境,有些特殊的package只能在项目环境中build,此时可以:

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

同时项目环境中需要提前安装好这个package的build dependencies。 比较好的实践方式是把对应的依赖配置到optional-dependencies中,使用sync --extra <extra>安装特定的依赖。 或者更原始一点,通过uv pip install提前安装即可。

build项目

build可以build 为source distribution(.tar.gz,.zip) and binaray distribution(wheel)

# --sdist limit to build source distribution
# --wheel limit to build binary distribution
# can both be specified
uv build [--sdist | --wheel] [<target>]

Note

uv build will first build a source distribution, and then build a binary distribution (wheel) from that source distribution in default.

uv有一个uv_build组件(experimental),作为build-backend,可以很方便的和uv集成,目前支持python code,不支持扩展模块。 可以直接配置,或者使用命令:

uv init --build-backend uv
build source distribution

构建的源码范围会包括include内容,再排除exclude内容,所以exclude优先级更高。

When building the source distribution, the following files and directories are included:

  • pyproject.toml
  • The module under tool.uv.build-backend.module-root, by default src//**.
  • project.license-files and project.readme.
  • All directories under tool.uv.build-backend.data.
  • All patterns from tool.uv.build-backend.source-include.

From these, tool.uv.build-backend.source-exclude and the default excludes are removed.

include语法:

  • <file> means include /
  • /**/ means recursively include all in /

exclude语法:

  • means exclude all directories named
  • / means exclude /

workspaces

Note

a collection of one or more packages, called workspace members, that are managed together

所谓工作空间,就是一个独立的目录,可以存放不同的项目,以便在同一个项目中开发多个应用。(vscode,idea等都是这个模式)

在project中使用uv init会创建workspace,并将这个project当作root project,同时会将创建的项目加入到workspace中,并修改root pyproject.toml中的tool.uv.workspace字段。 手动给某个project添加tool.uv.workspace,也会创建一个workspace root project.

Tip

root project也是workspace的一个member,和其他成员在这个维度是平级的。

workspace会统一管理lockfile和虚拟环境。也就是各个member的依赖只会存在于workspace的lockfile中,不会出现在项目的lockfile中。 workspace体现为root project。

uv run,uv sync等命令默认是以root project为环境,可以通过--package来指定package环境。

Caution

uv sync —package 只会同步这个package的依赖,意味着其他package的依赖可能会被删除。

例子:

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

成员之间的依赖关系可以通过tool.uv.sources来引用,例如:

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

tool.uv.sources中的定义会影响所有成员,比如tqdm,所有成员都会使用git来安装tqdm,除非在成员项目中覆写tool.uv.sources

并不是所有情况都使用使用workspace,比如多个项目依赖有冲突,python版本不同等等,都不宜用workspace。

管理依赖

依赖分类
  • dependencies 生产环境需要的依赖

    uv add <dependency>
    uv remove <dependency>

    对于requirements.txt管理的依赖,可以一次性添加:

    uv add -r requirements.txt
  • optional dependencies 可选依赖,有些库会剥离单独的feature供用户选择,这些feature有单独的package,用户指定了这些extra feature才会安装对应的package

    # install dependency with extra feature. dependency and extra must be quoted
    uv add "<dependency>\[<extra>,...\]"

    如果你需要在自己的项目提供可选的feature,且这些feature有单独的依赖:

    uv add <dependency> --optional <extra-feature>

    这些依赖会出现在[project.optional-dependencies],比如:

     [project.optional-dependencies]
     network = [
         "httpx>=0.28.1",
     ]

    本项目中可以使用uv sync --extra <extra>来安装这些依赖。 依赖这个项目的项目根据add中的extra会自动安装对应的可选依赖。

  • development dependencies 开发时依赖,一般只用于本地,也就是发布时不会被包括进去,常见的比如一些测试框架。

    uv add --dev <dependency>

    依赖会出现在[dependency-groups]dev下。 可以使用--dev,--only-dev,--no-dev控制这些依赖是否要包括或排除(同步环境时)。

    --only-dev flag can be used to install the dev group without the project and its dependencies. project can be builded and installed with build system defined in it's pyproject.toml.

    The

    实际上dev是一个特殊的group,用户也可以定义其他group:

    uv add --group <group> <dependency>

    使用--all-groups, --no-default-groups, --group, --only-group, --no-group进行控制,包括对dev的控制,实际上--no-group dev 等价于 --no-dev

    dev作为默认group,uv默认会管理它的依赖,比如sync,可以手动修改默认group

    [tool.uv]
    default-groups = ["dev", "foo"] # use "all" to enable all groups

    移除某个组的依赖:

    uv remove <dependency> --group <group>
  • build dependencies 构建时需要用的依赖。 配置在build-system.requires

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

就像软件包的安装源一样,uv也支持其他源,uv默认使用官方源pypi

依赖和源的关系被定义在tool.uv.sources:

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

可以添加4类源:

  • Index package index,就像pypi一样

    uv add <dependency> --index <index>=<url>

    第一次添加index时需要指定url,index被定义在[[tool.uv.index]] 比如:

    [project]
    dependencies = ["torch"]
     
    # the relationship between dependencies and sources
    [tool.uv.sources]
    torch = { index = "pytorch" }
     
    # index definition
    [[tool.uv.index]]
    name = "pytorch"
    url = "https://download.pytorch.org/whl/cpu"
    # this flag indicate that the index should only be used for packages that explicitly specify it in tool.uv.sources
    # otherwise, other packages may be resolved from the index, if not found elsewhere
    explicit = true
  • Git 可以直接使用git仓库中的包(这就非常灵活了)

    # git clone
    uv add git+<repository url>[#subdirectory=<subdirectory>] [ --tag <tag> | --branch <branch> | --rev <commitId> ]
  • URL 远程资源,资源可以是.wheel或者source distribution(就是源文件压缩包,比如.tar.gz,.zip等等)

    uv add <url> # url usual end with package name and version which will be treated as dependency name

    比如:

    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" }
  • PathURL基本一样,只是URL在远程,Path在本地 例:

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

    --editable来保持实时同步,将本地项目作为依赖时非常有用。

    可以使用

  • Workspace member 可以方便引用同一个工作区间的子项目。

    [project]
    dependencies = ["foo==0.1.0"]
     
    [tool.uv.sources]
    foo = { workspace = true }
     
    [tool.uv.workspace]
    # workspace members must be listed in workspace root project
    members = [
      "packages/foo"
    ]

源可以使用marker进行条件限定,可以做到满足条件才从这个源获取,否则从默认源(pypi)获取。

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

可以对一个依赖同时指定多个源,但是源marker要互斥,否则可能出现冲突。

[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'" },
]

使用uv lock --no-sources可以忽略所有的sources.

Important

所有类型的依赖都可以指定source

依赖语法

语法规范

依赖的定义有4个部分:

  • name
  • extra
  • version
  • marker 就是额外的条件,满足这些条件才会安装依赖,比如有些特殊版本的python下需要额外安装这个依赖,XX平台需要额外安装这个依赖 多个条件使用and,or关联

例子:

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

Important

所有定义依赖的地方都遵循同样的语法规范。

配置

设置

持久化配置uv有3种方式:

  • 项目级: projejct.toml下的tool.uv,uv.toml(同时存在,忽略project.toml)

    workspace,只会搜索root目录,忽略members的配置。

    对于

  • 用户级: ~/.config/uv/uv.toml

  • 系统级: /etc/uv/uv.toml

优先级从高到底,配置会被merge,比如string,bool,number类型的会使用高优先级的,array之类的会合并低优先级的。

还可以通过command和环境变量来配置,他们比配置文件的优先级更高。 命令行中甚至可以使用--no-config来忽略所有配置文件。 也可以使用--config <path>来指定一个uv.toml文件。

.env

环境变量可以export,也可以使用 .env文件。

指定文件:

  • 设置UV_ENV_FILE环境变量
  • --env-file <path>命令行参数

忽略.env文件:

  • UV_NO_ENV_FILE设置为1
  • --no-env-file命令行参数

同样的export拥有更高的优先级。

pip设置

tool.uv.pip只影响uv pip系列命令。在top-level中的配置,可以影响uv pip,但是可以在tool.uv.pip中覆写。

pip接口

uv pip可以用来平替pip,pip-tools,virtualenv,属于更低级别的接口,以支持更细致的自定义。

virtual environment

环境隔离是最好的实践方式,尤其是可以避免污染系统级python环境,所以uv默认使用虚拟环境。

pip namspaces下支持手动创建。

# default is .venv
uv venv [ <name> | <path> ] [ --python <version> ]
 
# if use default .venv, uv will automatically find and use it
uv pip install <package>

本质和python -m venv相同,所以完全可以activate,deactivate

如果设置了VIRTUAL_ENV环境变量,uv pip会使用这个环境。 或者可以直接指定:

# --system will ignore any interpreters that are in virtual environments, even if linked
# conversely, without --system will ignore any interpreters that are not in virtual environments
# --system means $(which python), typically used in containers
uv pip ( install | sync ) [ --python <path to python> | --system ] [ <package> ]

install packages

uv install基本一致,也可以使用其他源:

  • path
uv pip install "ruff @ ./projects/ruff"
  • git
uv pip install "git+https://github.com/astral-sh/ruff"
 
# Install a tag
uv pip install "git+https://github.com/astral-sh/ruff@v0.2.0"
 
# Install a commit
uv pip install "git+https://github.com/astral-sh/ruff@1fadefa67b26508cc59cf38e6130bde2243c929d"
 
# Install a branch
uv pip install "git+https://github.com/astral-sh/ruff@main"

还可以安装为editable:

# install current project as editable
uv pip install -e .
 
# install specific project as editable
uv pip install -e "ruff @ ./project/ruff"

从标准文件中安装:

uv pip install -r requirements.txt
 
uv pip install -r pyproject.toml [ --extra <extra> | --all-extras ]

inspect environments

list packages:

uv pip list
up pip list --format json
# list all packages in a requirements.txt format
uv pip freeze

inspect package:

uv pip show <package>

verify package:

uv pip check

lock dependencies

lock dependencies decalred in pyproject.toml to requirements.txt:

uv pip compile pyproject.toml -o requirements.txt

Note

compile command alse support compile requirements.ini,setup.cfg,setup.py

lock dependencies from stdin:

echo "uv-cli==0.0.1" | uv pip compile -

sync environment

# sync from requirements.txt
uv pip sync requirements.txt
# sync from pyproject.toml
uv pip sync pyproject.toml