uv 完全指南
uv 是由 Astral(Ruff 的开发团队)用 Rust 编写的 Python 包管理器和项目管理工具。它将 pip、pip-tools、pipx、pyenv、virtualenv 的功能集成到一个工具中,速度比 pip 快 10-100 倍。 相关文档:Python包管理工具(/python-bao-guan-li-gong-ju/) | FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) | pytest完全指南(/pytest-wan-quan-zhi-nan/) uv 是一个"全能型"Python 工具链,可替代多
官方文档:https://docs.astral.sh/uv/
适用版本:uv 0.4+(2026-05-07 核实)
uv 是由 Astral(Ruff 的开发团队)用 Rust 编写的 Python 包管理器和项目管理工具。它将 pip、pip-tools、pipx、pyenv、virtualenv 的功能集成到一个工具中,速度比 pip 快 10-100 倍。
相关文档:Python包管理工具 | FastAPI完全指南 | pytest完全指南
基础概念
uv 的定位
uv 是一个"全能型"Python 工具链,可替代多个现有工具:
| 被替代的工具 | uv 对应功能 |
|---|---|
| pip | uv pip install / uv add |
| pip-tools | uv pip compile / uv lock |
| pipx | uv tool install / uvx |
| pyenv | uv python install |
| virtualenv / venv | uv venv |
| poetry / pdm | uv init + 项目管理命令 |
核心文件
| 文件 | 作用 | 是否提交版本控制 |
|---|---|---|
pyproject.toml |
项目元数据和依赖声明(人工维护) | 是 |
uv.lock |
精确锁定所有依赖版本(uv 自动维护) | 是 |
.python-version |
项目 Python 版本锁定 | 是 |
.venv/ |
虚拟环境目录 | 否 |
uv.toml |
uv 全局/工作区级配置 | 是 |
uv.lock 说明
uv.lock 是跨平台锁定文件,记录所有 Python 标记(操作系统、CPU 架构、Python 版本)下会安装的精确版本。格式为人类可读的 TOML,但不应手动编辑。
与 requirements.txt 的区别:uv.lock 包含所有平台的信息,而 requirements.txt 只记录当前平台的安装结果。
安装
安装方式
# macOS / Linux(推荐)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows(PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# 安装指定版本
curl -LsSf https://astral.sh/uv/0.6.0/install.sh | sh
# 通过 Homebrew(macOS/Linux)
brew install uv
# 通过 pip(不推荐,但可用)
pip install uv
# 通过 pipx
pipx install uv
自更新与卸载
# 更新到最新版本
uv self update
# 查看版本
uv --version
# 卸载(先清理缓存)
uv cache clean
# 然后删除二进制文件(通常在 ~/.cargo/bin/uv 或 ~/.local/bin/uv)
Shell 补全
# Bash
echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
# Zsh
echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc
# Fish
echo 'uv generate-shell-completion fish | source' >> ~/.config/fish/config.fish
# PowerShell
Add-Content $PROFILE '(& uv generate-shell-completion powershell) | Out-String | Invoke-Expression'
Python 版本管理
uv 内置 Python 版本管理,无需 pyenv 等额外工具。
uv python install
安装指定 Python 版本(来自 python-build-standalone 项目)。
uv python install [OPTIONS] [TARGETS]...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| TARGETS | str | - | 版本号,如 3.12、3.11.9、pypy3.10 |
| --reinstall / -r | flag | 关闭 | 重新安装已有版本 |
| --upgrade / -U | flag | 关闭 | 将已安装版本升级到最新补丁版本 |
| --force / -f | flag | 关闭 | 强制替换已有的 Python 可执行文件 |
| --default | flag | 关闭 | 将安装的版本设为默认 Python |
# 安装最新 Python 3.12
uv python install 3.12
# 安装多个版本
uv python install 3.11 3.12 3.13
# 安装 PyPy
uv python install pypy3.10
# 安装特定补丁版本
uv python install 3.12.3
uv python list
列出可用和已安装的 Python 版本。
uv python list [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --only-installed | flag | 关闭 | 只显示已安装的版本 |
| --all-versions | flag | 关闭 | 显示所有可用版本(含补丁) |
| --all-platforms | flag | 关闭 | 显示其他平台的版本 |
uv python list
uv python list --only-installed
uv python list --all-versions
uv python pin
固定项目使用的 Python 版本,写入 .python-version 文件。
uv python pin [OPTIONS] [REQUEST]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| REQUEST | str | - | 版本号,如 3.12 |
| --resolved | flag | 关闭 | 写入完整的解析版本号(如 3.12.3) |
| --global | flag | 关闭 | 写入全局配置而非项目目录 |
| --rm | flag | 关闭 | 删除 .python-version 文件中的版本锁定 |
| --no-project | flag | 关闭 | 不验证版本与项目的兼容性 |
uv python pin 3.12
uv python pin 3.12.3 --resolved
uv python find
查找匹配条件的 Python 解释器路径。
uv python find [REQUEST]
uv python find 3.12
# 输出:/home/user/.local/share/uv/python/cpython-3.12.3-.../bin/python3
uv python uninstall
卸载已安装的 Python 版本。
uv python uninstall [TARGETS]...
uv python uninstall 3.11
uv python uninstall --all # 卸载所有 uv 管理的 Python
uv python upgrade
升级已安装的 Python 到最新补丁版本。
uv python upgrade 3.12 # 升级 3.12.x 到最新补丁
uv python upgrade --all # 升级所有已安装版本
Python 版本解析优先级
uv 按以下顺序查找 Python:
--python命令行参数UV_PYTHON环境变量- 当前项目的
.python-version文件 pyproject.toml中的requires-python- 父目录的
.python-version文件 - 系统 PATH 中的 Python
项目管理
uv init
初始化新项目,创建 pyproject.toml 等基础文件。
uv init [OPTIONS] [PATH]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PATH | str | 当前目录 | 项目目录路径 |
| --name | str | 目录名 | 项目名称 |
| --python | str | - | 指定 Python 版本 |
| --app | flag | 默认 | 初始化为应用程序(不含 src 布局) |
| --lib | flag | 关闭 | 初始化为库(含 src/ 布局,有 __init__.py) |
| --package | flag | 关闭 | 初始化为可打包应用(含 src 布局,有构建系统) |
| --script | flag | 关闭 | 初始化为单文件脚本(含 PEP 723 内联元数据) |
| --bare | flag | 关闭 | 最小化初始化(不生成 README、.python-version、示例文件) |
| --build-backend | str | uv | 构建后端,可选 hatch、flit、pdm、setuptools、maturin、scikit |
| --vcs | str | git | 版本控制系统,none 禁用 |
| --no-readme | flag | 关闭 | 不生成 README.md |
| --no-pin-python | flag | 关闭 | 不生成 .python-version |
# 创建应用项目(默认)
uv init my-app
# 生成:pyproject.toml、README.md、.python-version、hello.py
# 创建库项目
uv init --lib my-library
# 生成:pyproject.toml、README.md、.python-version、src/my_library/__init__.py
# 创建可打包应用
uv init --package my-package
# 指定构建后端
uv init --lib --build-backend hatch my-library
# 最小化初始化(适合在已有目录中使用)
uv init --bare
# 在当前目录初始化(不创建子目录)
uv init
项目类型对比
| 项目类型 | 命令 | 目录结构 | 用途 |
|---|---|---|---|
| 应用 (app) | uv init --app |
根目录直接放 .py 文件 | 脚本、服务、CLI 应用 |
| 库 (lib) | uv init --lib |
src/包名/ 布局 | 发布到 PyPI 的库 |
| 可打包应用 | uv init --package |
src/ 布局 + 构建系统 | 需要打包分发的应用 |
| 脚本 | uv init --script |
单 .py 文件 | 单文件独立脚本 |
应用项目(--app,默认)没有构建系统,不能用 uv build 打包,适合部署到服务器或容器。
库项目(--lib)有构建系统,可以用 uv build 生成 wheel,适合发布到 PyPI。
依赖管理
uv add
添加依赖到 pyproject.toml 并更新 uv.lock,同时安装到虚拟环境。
uv add [OPTIONS] <PACKAGES>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | 必填 | 包名,支持 PEP 440 版本约束 |
| --dev / -d | flag | 关闭 | 添加到 dev 依赖组 |
| --group | str | - | 添加到指定依赖组,如 --group test |
| --optional | str | - | 添加为可选依赖(extras),如 --optional network |
| --editable / -e | flag | 关闭 | 以可编辑模式安装本地包 |
| --raw-sources | flag | 关闭 | 不将来源规范化到 tool.uv.sources |
| --no-sync | flag | 关闭 | 只修改 pyproject.toml,不安装到环境 |
| --frozen | flag | 关闭 | 不更新 uv.lock(也不重新锁定) |
| --locked | flag | 关闭 | 要求 uv.lock 不发生变化,否则报错 |
| --bounds | str | - | 版本约束方式:lower、major、minor、exact |
| --raw | flag | 关闭 | 按原样写入依赖字符串,不规范化来源到 tool.uv.sources |
| --branch | str | - | Git 分支(与 git+https://... 包名一起使用) |
| --tag | str | - | Git 标签(与 git+https://... 包名一起使用) |
| --rev | str | - | Git 提交哈希(与 git+https://... 包名一起使用) |
| --lfs | flag | 关闭 | 使用 Git LFS 拉取 Git 依赖 |
| --script | str | - | 将依赖添加到指定脚本文件(PEP 723) |
# 添加生产依赖
uv add requests
uv add "fastapi>=0.100.0"
uv add "sqlalchemy[asyncio]>=2.0"
# 同时添加多个包
uv add requests httpx aiohttp
# 添加开发依赖
uv add --dev pytest ruff mypy
# 添加到指定依赖组
uv add --group lint ruff pyflakes
uv add --group test pytest pytest-asyncio coverage
# 添加可选依赖(extras)
uv add --optional network httpx aiohttp
# 本地可编辑包
uv add --editable ./packages/my-utils
# Git 依赖(URL 直接写在包名位置,--branch/--tag/--rev 控制引用)
uv add "git+https://github.com/user/repo"
uv add "git+https://github.com/user/repo" --branch main
uv add "git+https://github.com/user/repo" --tag v1.0.0
uv add "git+https://github.com/user/repo" --rev abc1234
# 平台特定依赖(通过环境标记)
uv add "pywinpty; sys_platform == 'win32'"
uv add "uvloop; sys_platform != 'win32'"
# 版本约束方式
uv add fastapi --bounds major # >=0.115.5, <1
uv add fastapi --bounds minor # >=0.115.5, <0.116
uv add fastapi --bounds exact # ==0.115.5
uv add fastapi --bounds lower # >=0.115.5(只设下界)
# 为脚本添加依赖(PEP 723)
uv add --script my_script.py requests rich
uv remove
移除依赖,更新 pyproject.toml 和 uv.lock。
uv remove [OPTIONS] <PACKAGES>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | 必填 | 包名 |
| --dev | flag | 关闭 | 从 dev 组移除 |
| --group | str | - | 从指定组移除 |
| --optional | str | - | 从指定可选依赖移除 |
| --no-sync | flag | 关闭 | 只修改 pyproject.toml,不更新环境 |
| --script | str | - | 从脚本文件移除依赖 |
uv remove requests
uv remove --dev pytest
uv remove --group lint ruff
uv remove --optional network httpx
依赖类型说明
uv 支持四种依赖类型,对应不同的使用场景:
| 依赖类型 | pyproject.toml 字段 | 添加命令 | 是否发布 | 说明 |
|---|---|---|---|---|
| 生产依赖 | project.dependencies |
uv add |
是 | 运行时必须 |
| 可选依赖 | project.optional-dependencies |
uv add --optional |
是 | 按需安装的 extras |
| 依赖组 | dependency-groups |
uv add --group |
否 | 仅本地使用,不发布 |
| dev 依赖 | dependency-groups.dev |
uv add --dev |
否 | dev 组的简写 |
依赖源(tool.uv.sources)
在 pyproject.toml 中配置非 PyPI 的依赖来源:
[tool.uv.sources]
# 本地路径(可编辑)
my-utils = { path = "./packages/my-utils", editable = true }
# 本地路径(不可编辑)
my-lib = { path = "../my-lib" }
# Git 仓库
my-git-pkg = { git = "https://github.com/user/repo", branch = "main" }
my-tagged-pkg = { git = "https://github.com/user/repo", tag = "v1.0.0" }
my-rev-pkg = { git = "https://github.com/user/repo", rev = "abc1234" }
# 工作区成员
shared-lib = { workspace = true }
# 指定索引
torch = { index = "pytorch" }
tool.uv.index
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
锁定与同步
uv lock
创建或更新 uv.lock 锁定文件,解析所有依赖版本。
uv lock [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --upgrade | flag | 关闭 | 升级所有依赖到最新兼容版本 |
| --upgrade-package | str | - | 只升级指定包 |
| --check | flag | 关闭 | 检查锁定文件是否最新,否则报错(不写入) |
| --check-exists | flag | 关闭 | 只检查 uv.lock 是否存在,不验证内容 |
| --dry-run | flag | 关闭 | 显示将要变更的内容,不实际写入 |
| --python | str | - | 指定解析时使用的 Python 版本 |
| --index | str | - | 使用指定包索引 |
| --no-sources | flag | 关闭 | 忽略 tool.uv.sources 配置(生成可发布的锁定文件) |
| --script | str | - | 锁定指定 PEP 723 脚本而非项目 |
# 生成/更新锁定文件
uv lock
# 升级所有依赖
uv lock --upgrade
# 升级单个包
uv lock --upgrade-package requests
# 升级到指定版本
uv lock --upgrade-package "requests==2.32.0"
# 验证锁定文件是否最新(CI 中常用,不写入)
uv lock --check
# 只查看变化,不写入
uv lock --dry-run
uv sync
将虚拟环境与 uv.lock 同步,使环境与锁定文件完全一致。
uv sync [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --frozen | flag | 关闭 | 不更新 uv.lock,直接用现有锁定文件安装 |
| --locked | flag | 关闭 | 要求 uv.lock 是最新的,否则报错(不自动更新) |
| --no-sync | flag | 关闭 | 不同步环境(仅解析) |
| --exact | flag | 关闭 | 精确同步,移除锁定文件中没有的包 |
| --inexact | flag | 默认 | 不移除多余的包 |
| --dev / --no-dev | flag | dev | 是否安装 dev 依赖 |
| --only-dev | flag | 关闭 | 只安装 dev 依赖 |
| --group | str | - | 安装指定依赖组 |
| --all-groups | flag | 关闭 | 安装所有依赖组 |
| --no-group | str | - | 排除指定依赖组 |
| --extra | str | - | 安装指定可选依赖 |
| --all-extras | flag | 关闭 | 安装所有可选依赖 |
| --no-install-project | flag | 关闭 | 不安装项目本身(只安装依赖) |
| --no-install-workspace | flag | 关闭 | 不安装工作区成员 |
| --no-install-package | str | - | 不安装指定包 |
| --python | str | - | 指定 Python 版本 |
# 标准同步(安装所有依赖含 dev)
uv sync
# 仅同步生产依赖(适合部署)
uv sync --no-dev
# 安装所有可选依赖
uv sync --all-extras
# 安装指定可选依赖
uv sync --extra docs --extra test
# CI 环境(不更新锁定文件)
uv sync --frozen
# 生产部署(要求锁定文件最新且不自动更新)
uv sync --locked --no-dev
# 精确同步(移除多余包,适合生产环境)
uv sync --exact --no-dev
# 安装依赖但不安装项目本身(Docker 分层优化)
uv sync --no-install-project
自动锁定与同步
uv run、uv sync、uv add、uv remove 都会自动执行锁定和同步,无需手动调用 uv lock。
可以通过以下方式控制自动行为:
# 禁止自动更新锁定文件(如锁定文件过期则报错)
uv run --locked python main.py
# 禁止检查锁定文件(直接使用,不验证是否最新)
uv run --frozen python main.py
运行命令
uv run
在项目虚拟环境中执行命令,自动完成环境同步。
uv run [OPTIONS] [COMMAND]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| COMMAND | str | 必填 | 要执行的命令或脚本路径 |
| --with | str | - | 临时安装额外包(不写入项目依赖) |
| --with-editable | str | - | 临时以可编辑模式安装本地包 |
| --without | str | - | 临时排除指定包 |
| --python | str | - | 指定 Python 版本 |
| --frozen | flag | 关闭 | 不更新 uv.lock |
| --locked | flag | 关闭 | 要求 uv.lock 是最新的 |
| --no-sync | flag | 关闭 | 不同步环境 |
| --isolated | flag | 关闭 | 在隔离环境中运行(不使用项目依赖) |
| --env-file | str | - | 加载 .env 文件中的环境变量 |
| --no-project | flag | 关闭 | 不在项目上下文中运行 |
| --package | str | - | 在指定工作区成员的上下文中运行 |
| --group | str | - | 包含指定依赖组 |
| --all-groups | flag | 关闭 | 包含所有依赖组 |
| --extra | str | - | 包含指定可选依赖 |
| --script | flag | 关闭 | 将命令当作 PEP 723 脚本运行 |
# 运行 Python 脚本
uv run python main.py
uv run main.py # 也可以省略 python
# 运行项目中的工具
uv run pytest
uv run pytest tests/test_api.py -v
uv run ruff check .
uv run mypy src/
# 临时安装包运行(不污染项目依赖)
uv run --with rich python -c "import rich; rich.print('[bold]Hello[/bold]')"
uv run --with "httpx>=0.24" python fetch.py
# 使用 .env 文件
uv run --env-file .env python main.py
# 在工作区特定成员中运行
uv run --package api pytest tests/
# 带 frozen 标志(CI 环境,不更新锁定文件)
uv run --frozen pytest
脚本管理(PEP 723)
PEP 723 定义了在 Python 脚本中内联声明依赖的标准格式,uv 完整支持。
内联依赖声明
在脚本文件顶部添加元数据块:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "requests",
# "rich>=13.0",
# ]
# ///
import requests
from rich import print
response = requests.get("https://api.github.com")
print(response.json())
# 运行含内联依赖的脚本(uv 自动创建隔离环境并安装依赖)
uv run my_script.py
# 也可以显式指定
uv run --script my_script.py
为脚本添加/移除依赖
# 添加依赖到脚本(自动修改脚本文件的元数据块)
uv add --script my_script.py requests rich
# 移除脚本依赖
uv remove --script my_script.py requests
# 查看脚本依赖
uv run my_script.py --help
可执行脚本(Shebang)
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["requests"]
# ///
import requests
print(requests.get("https://httpbin.org/get").status_code)
chmod +x my_script.py
./my_script.py # 直接运行,uv 自动处理依赖
锁定脚本依赖
# 为脚本生成锁定文件(在脚本同目录创建 my_script.py.lock)
uv lock --script my_script.py
# 使用锁定文件运行(确保可重现)
uv run --locked my_script.py
工具管理
工具(tool)是安装到隔离环境并暴露可执行文件到 PATH 的命令行程序,不污染任何项目的依赖。
uvx(uv tool run)
临时运行工具,不永久安装。
uvx [OPTIONS] [COMMAND] [ARGS]...
# 等同于 uv tool run
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| COMMAND | str | 必填 | 工具名称或入口点 |
| --from | str | - | 指定包名(当工具名与包名不同时) |
| --with | str | - | 额外安装的包(如插件) |
| --python | str | - | 指定工具的 Python 版本 |
| --isolated | flag | 关闭 | 不使用缓存,创建全新隔离环境 |
# 临时运行工具
uvx ruff check .
uvx black --check .
uvx httpie GET https://httpbin.org/get
# 指定版本运行
uvx [email protected] check .
uvx --from "ruff==0.3.0" ruff check .
uvx --from "ruff>0.2.0,<0.4.0" ruff check .
# 带 extras 运行
uvx --from "mypy[faster-cache,reports]" mypy src/
# 带额外包运行(如 mkdocs 插件)
uvx --with mkdocs-material mkdocs serve
# 从 Git 运行
uvx --from "git+https://github.com/user/tool" tool-name
uv tool install
永久安装工具,添加到 PATH。
uv tool install [OPTIONS] <PACKAGE>
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGE | str | 必填 | 工具包名 |
| --python | str | - | 指定工具使用的 Python 版本 |
| --with | str | - | 同时安装额外包 |
| --force | flag | 关闭 | 强制重新安装(覆盖已有版本) |
| --editable / -e | flag | 关闭 | 可编辑安装 |
# 安装常用工具
uv tool install ruff
uv tool install mypy
uv tool install black
uv tool install cookiecutter
uv tool install httpie
# 安装特定版本
uv tool install "ruff==0.3.0"
# 安装带插件的工具
uv tool install mkdocs --with mkdocs-material --with mkdocs-minify-plugin
# 从 Git 安装
uv tool install "git+https://github.com/user/tool"
uv tool list
列出已安装的工具。
uv tool list [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --show-paths | flag | 关闭 | 显示工具安装路径 |
uv tool list
uv tool list --show-paths
uv tool upgrade
升级已安装的工具。
uv tool upgrade [OPTIONS] [NAMES]...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| NAMES | str | - | 工具名,省略则升级全部 |
| --all | flag | 关闭 | 升级所有工具 |
| --python | str | - | 指定 Python 版本 |
uv tool upgrade ruff
uv tool upgrade --all
uv tool uninstall
卸载工具。
uv tool uninstall [NAMES]...
uv tool uninstall ruff
uv tool uninstall --all
uv tool dir
查看工具安装目录。
uv tool dir # 输出工具的 bin 目录路径
虚拟环境管理
uv venv
创建虚拟环境(pip 工作流使用,项目模式下 uv 自动管理 .venv)。
uv venv [OPTIONS] [PATH]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PATH | str | .venv |
虚拟环境目录路径 |
| --python / -p | str | 系统 Python | 指定 Python 版本 |
| --seed | flag | 关闭 | 预安装 pip、setuptools、wheel |
| --system-site-packages | flag | 关闭 | 允许访问系统级 Python 包 |
| --no-project | flag | 关闭 | 不关联到项目(忽略 pyproject.toml) |
| --allow-existing | flag | 关闭 | 允许覆盖已有虚拟环境 |
| --relocatable | flag | 关闭 | 创建可迁移的虚拟环境 |
# 创建默认虚拟环境
uv venv
# 指定 Python 版本
uv venv --python 3.12
uv venv --python pypy3.10
# 指定路径
uv venv /path/to/myenv
uv venv .venv-py312
# 带 pip 的虚拟环境(传统工作流)
uv venv --seed
# 激活虚拟环境
source .venv/bin/activate # Linux/macOS
.venv\Scripts\activate # Windows CMD
.venv\Scripts\Activate.ps1 # Windows PowerShell
deactivate # 退出
pip 兼容接口
uv 提供与 pip、pip-tools、virtualenv 兼容的命令接口,便于迁移。
uv pip install
uv pip install [OPTIONS] <PACKAGES>...
# 基本安装
uv pip install requests
# 从 requirements.txt 安装
uv pip install -r requirements.txt
# 可编辑安装
uv pip install -e .
# 指定索引
uv pip install --index-url https://pypi.org/simple/ requests
# 不使用缓存
uv pip install --no-cache requests
uv pip compile
将依赖声明编译为精确锁定的 requirements.txt。
uv pip compile [OPTIONS] <SRC_FILE>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| SRC_FILE | str | 必填 | 输入文件(requirements.in 或 pyproject.toml) |
| --output-file / -o | str | stdout | 输出文件路径 |
| --upgrade / -U | flag | 关闭 | 升级所有包到最新版本 |
| --upgrade-package / -P | str | - | 升级指定包 |
| --generate-hashes | flag | 关闭 | 生成包哈希值(提高安全性) |
| --python | str | - | 指定目标 Python 版本 |
| --extra | str | - | 包含指定可选依赖 |
| --all-extras | flag | 关闭 | 包含所有可选依赖 |
| --no-annotate | flag | 关闭 | 不添加注释(包来源说明) |
# 编译 requirements.in -> requirements.txt
uv pip compile requirements.in -o requirements.txt
# 从 pyproject.toml 编译(生产依赖)
uv pip compile pyproject.toml -o requirements.txt
# 含开发依赖
uv pip compile pyproject.toml --extra dev -o requirements-dev.txt
# 升级并重新编译
uv pip compile requirements.in --upgrade -o requirements.txt
# 带哈希值(安全部署)
uv pip compile requirements.in --generate-hashes -o requirements.txt
uv pip sync
将环境精确同步到 requirements.txt 中指定的包(会移除多余的包)。
uv pip sync [OPTIONS] <SRC_FILE>...
uv pip sync requirements.txt
uv pip sync requirements.txt requirements-dev.txt
uv pip sync --frozen requirements.txt # 不验证哈希
uv pip list / show / check / tree
# 列出已安装的包
uv pip list
uv pip list --format json
# 显示包详情
uv pip show requests
# 检查依赖兼容性
uv pip check
# 显示依赖树
uv pip tree
uv pip tree --package requests # 只显示指定包的依赖树
uv pip uninstall
uv pip uninstall requests
uv pip uninstall -r requirements.txt
构建与发布
uv build
构建源代码分发包(sdist)和二进制分发包(wheel)。
uv build [OPTIONS] [SRC]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| SRC | str | 当前目录 | 要构建的项目路径 |
| --sdist | flag | 关闭 | 只构建源码分发包 |
| --wheel | flag | 关闭 | 只构建 wheel |
| --out-dir / -o | str | dist/ | 输出目录 |
| --no-sources | flag | 关闭 | 忽略 tool.uv.sources(确保与其他构建工具兼容) |
| --build-constraint | str | - | 约束构建依赖的版本 |
# 构建 wheel 和 sdist
uv build
# 只构建 wheel
uv build --wheel
# 只构建 sdist
uv build --sdist
# 指定输出目录
uv build -o ./dist
# 为发布构建(不含本地 sources 配置)
uv build --no-sources
uv version
查看或修改项目版本号。
uv version [OPTIONS] [VALUE]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| VALUE | str | - | 新版本号,省略则显示当前版本 |
| --bump | str | - | 语义化版本自动递增:major、minor、patch、stable、alpha、beta、rc、post、dev |
| --dry-run | flag | 关闭 | 只显示结果,不写入 |
| --output-format | str | text | 输出格式:text、json |
| --short | flag | 关闭 | 只输出版本号 |
# 查看当前版本
uv version
uv version --short # 只输出版本号
# 设置版本
uv version 1.2.3
# 自动递增
uv version --bump patch # 1.0.0 -> 1.0.1
uv version --bump minor # 1.0.0 -> 1.1.0
uv version --bump major # 1.0.0 -> 2.0.0
uv version --bump alpha # 1.0.0 -> 1.0.0a1
uv version --bump rc # 1.0.0a1 -> 1.0.0rc1
# 预览变化
uv version --bump minor --dry-run
uv publish
将构建产物发布到 PyPI 或其他包索引。
uv publish [OPTIONS] [FILES]...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| FILES | str | dist/* | 要发布的文件路径 |
| --publish-url | str | PyPI | 发布目标 URL |
| --token / -t | str | - | PyPI API token |
| --username / -u | str | - | 用户名(不推荐,PyPI 已不支持用户名密码) |
| --password / -p | str | - | 密码 |
| --check-url | str | - | 发布前检查的索引 URL(避免重复上传) |
| --trusted-publishing | str | - | 可信发布模式:always、automatic(GitHub Actions 推荐) |
# 发布到 PyPI(需先配置 token)
uv publish --token pypi-xxxx
# 通过环境变量(推荐)
UV_PUBLISH_TOKEN=pypi-xxxx uv publish
# 发布到私有仓库
uv publish --publish-url https://my.private.repo/upload/
# 发布指定文件
uv publish dist/my_package-1.0.0-py3-none-any.whl
完整发布流程
# 1. 更新版本
uv version --bump minor
# 2. 构建(不含本地 sources)
uv build --no-sources
# 3. 验证构建产物(可选,使用 twine check)
uvx twine check dist/*
# 4. 发布
UV_PUBLISH_TOKEN=pypi-xxxx uv publish
# 5. 验证安装
uv run --with my-package --no-project python -c "import my_package; print(my_package.__version__)"
工作区(Workspaces)
工作区将多个相关 Python 包组织在同一仓库中,共享一个 uv.lock 文件,适合 monorepo 架构。
核心概念
- 工作区根:包含
[tool.uv.workspace]的项目,也是一个工作区成员 - 工作区成员:工作区中的每个包,各自有独立的
pyproject.toml - 共享锁定文件:所有成员共享根目录的
uv.lock,确保依赖一致性 - 共享虚拟环境:所有成员安装到同一个
.venv
工作区结构
my-workspace/
├── pyproject.toml # 工作区根(含 [tool.uv.workspace])
├── uv.lock # 所有成员共享的锁定文件
├── .venv/ # 所有成员共享的虚拟环境
├── packages/
│ ├── core/
│ │ ├── pyproject.toml # 工作区成员
│ │ └── src/core/
│ ├── api/
│ │ ├── pyproject.toml # 工作区成员
│ │ └── src/api/
│ └── cli/
│ ├── pyproject.toml # 工作区成员
│ └── src/cli/
└── apps/
└── web/
├── pyproject.toml # 工作区成员
└── src/web/
配置工作区
工作区根的 pyproject.toml:
[project]
name = "my-workspace"
version = "0.1.0"
requires-python = ">=3.12"
[tool.uv.workspace]
members = ["packages/*", "apps/*"]
# exclude 用于排除匹配 members 的特定目录
exclude = ["packages/experimental"]
成员的 pyproject.toml:
[project]
name = "core"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
工作区成员间依赖
成员之间通过 tool.uv.sources 相互引用:
# packages/api/pyproject.toml
[project]
name = "api"
dependencies = ["core"]
[tool.uv.sources]
core = { workspace = true }
等同于可编辑安装,修改 core 的代码立即在 api 中生效,无需重新安装。
工作区命令
# 在工作区根执行:对所有成员操作
uv lock # 为整个工作区解析依赖
uv sync # 同步整个工作区的虚拟环境
# 针对特定成员
uv run --package api pytest tests/
uv sync --package core
uv add --package api fastapi
工作区限制
| 限制 | 说明 |
|---|---|
| 单一 requires-python | 工作区取所有成员 requires-python 的交集 |
| 不支持冲突依赖 | 成员间如有不兼容的依赖版本,无法使用工作区 |
| 不支持多虚拟环境 | 工作区只有一个 .venv,如需隔离请用路径依赖 |
| 根必须是成员 | 工作区根本身也是一个工作区成员(但可以是虚包) |
虚根(Virtual Workspace Root)
如果工作区根只是容器,不需要本身作为包,可以将其配置为虚包(不含 build-system):
# 工作区根 pyproject.toml(虚根)
[project]
name = "my-workspace"
version = "0.1.0"
# 不含 [build-system],是一个"非包"项目
[tool.uv.workspace]
members = ["packages/*"]
大型与复杂项目管理
单体仓库(Monorepo)最佳实践
推荐结构:
my-monorepo/
├── pyproject.toml # 工作区根(虚根)
├── uv.lock
├── .python-version # 统一 Python 版本
├── uv.toml # 全局 uv 配置
├── packages/
│ ├── shared/ # 共享工具库
│ ├── models/ # 数据模型
│ └── utils/ # 通用工具
├── services/
│ ├── api-service/ # FastAPI 服务
│ ├── worker-service/ # Celery Worker
│ └── admin-service/ # 管理后台
└── tools/
└── scripts/ # 运维脚本
工作区根配置:
[project]
name = "my-monorepo"
version = "0.1.0"
requires-python = ">=3.12"
[tool.uv.workspace]
members = ["packages/*", "services/*", "tools/*"]
[tool.uv]
# 全局约束(覆盖所有成员的相同包版本)
constraint-dependencies = [
"pydantic>=2.0",
]
依赖冲突解决
当成员之间有不兼容依赖时,通过 override-dependencies 强制统一:
# 工作区根 pyproject.toml
[tool.uv]
# 强制所有成员使用此版本(跳过成员自己的约束)
override-dependencies = [
"numpy==1.26.4",
]
通过 constraint-dependencies 添加约束而不覆盖:
[tool.uv]
# 在成员约束基础上额外添加约束
constraint-dependencies = [
"certifi>=2024.0",
]
依赖组嵌套(适合大型项目)
在复杂项目中,通过依赖组组合管理不同场景的依赖:
[dependency-groups]
# 基础开发工具
dev = ["ruff>=0.4", "mypy>=1.9"]
# 测试依赖
test = ["pytest>=8.0", "pytest-asyncio>=0.23", "coverage>=7.0"]
# 文档
docs = ["mkdocs>=1.5", "mkdocs-material>=9.0"]
# 完整开发环境(包含所有组)
full = [
{ include-group = "dev" },
{ include-group = "test" },
{ include-group = "docs" },
]
安装特定场景:
uv sync --group test # 只安装测试依赖
uv sync --group full # 安装完整开发环境
uv sync --no-dev --no-group docs # 只安装生产依赖,排除 docs 组
条件依赖(平台/版本特定)
[project]
dependencies = [
# Python 版本条件
"tomllib; python_version < '3.11'",
"importlib-metadata>=6.0; python_version < '3.12'",
# 平台条件
"pywin32>=306; sys_platform == 'win32'",
"uvloop>=0.19; sys_platform != 'win32'",
# CPU 架构条件
"nvidia-cuda-runtime-cu12; platform_machine == 'x86_64' and sys_platform == 'linux'",
]
多 Python 版本测试
# 为不同 Python 版本创建独立的虚拟环境(临时)
uv run --python 3.10 pytest
uv run --python 3.11 pytest
uv run --python 3.12 pytest
# 结合 tox 或 nox 进行矩阵测试
# noxfile.py 中配置
# nox.options.sessions = ["test-3.10", "test-3.11", "test-3.12"]
路径依赖 vs 工作区
| 特性 | 路径依赖 | 工作区成员 |
|---|---|---|
| 锁定文件 | 各项目独立的 uv.lock | 共享一个 uv.lock |
| 虚拟环境 | 各项目独立的 .venv | 共享一个 .venv |
| 冲突依赖 | 可以有不同版本 | 必须统一版本 |
| 适合场景 | 需要隔离的子项目 | 紧密耦合的包集合 |
# 路径依赖(各自独立的锁定文件和环境)
[project]
dependencies = ["my-utils"]
[tool.uv.sources]
my-utils = { path = "../my-utils", editable = true }
包索引配置
配置私有/镜像索引
在 pyproject.toml 或 uv.toml 中配置:
tool.uv.index
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple/"
tool.uv.index
name = "tencent"
url = "https://mirrors.cloud.tencent.com/pypi/simple/"
# 私有仓库
tool.uv.index
name = "private"
url = "https://private.company.com/simple/"
# 设为默认索引(替换 PyPI)
default = true
索引优先级:命令行 --index > 配置文件中靠前的索引 > PyPI(默认)。
索引搜索策略
[tool.uv]
# first-index(默认):找到包就停止,不继续搜索其他索引
index-strategy = "first-index"
# unsafe-first-match:选择第一个索引中找到的第一个兼容版本
index-strategy = "unsafe-first-match"
# unsafe-best-match:跨所有索引选择最佳版本
index-strategy = "unsafe-best-match"
将包固定到特定索引
防止依赖混淆攻击,将内部包固定到私有索引:
[tool.uv.sources]
my-internal-pkg = { index = "private" }
tool.uv.index
name = "private"
url = "https://private.company.com/simple/"
# 明确声明此包只能从 private 索引获取
explicit = true
索引认证
tool.uv.index
name = "private"
url = "https://private.company.com/simple/"
通过环境变量传递凭证(不要写入配置文件):
# 用户名密码
export UV_INDEX_PRIVATE_USERNAME=myuser
export UV_INDEX_PRIVATE_PASSWORD=mypassword
# 或者 token(作为密码传入)
export UV_INDEX_PRIVATE_PASSWORD=mytoken
也可以在 URL 中嵌入(不推荐提交到版本控制):
tool.uv.index
name = "private"
url = "https://${MY_USER}:${MY_TOKEN}@private.company.com/simple/"
缓存管理
缓存策略
uv 对不同来源的依赖使用不同缓存策略:
| 依赖类型 | 缓存方式 |
|---|---|
| PyPI 包 | 遵循 HTTP 缓存头(ETag / Last-Modified) |
| 直接 URL | HTTP 头 + URL 本身 |
| Git 依赖 | 按解析后的 commit hash 缓存 |
| 本地路径 | 按文件修改时间缓存 |
缓存是线程安全的、只追加的,支持多个 uv 进程并发使用同一缓存目录。
uv cache 命令
# 查看缓存占用大小
uv cache dir
du -sh $(uv cache dir)
# 清理所有缓存
uv cache clean
# 清理指定包的缓存
uv cache clean requests
# 删除未使用的缓存(精简)
uv cache prune
# CI 环境优化:删除预构建 wheel,保留从源码构建的 wheel
uv cache prune --ci
缓存强制刷新
# 重新验证所有包(忽略缓存)
uv sync --refresh
# 重新验证指定包
uv sync --refresh-package requests
# 完全不使用缓存
uv sync --no-cache
自定义缓存路径
# 通过环境变量
export UV_CACHE_DIR=/custom/cache/path
# 通过命令行
uv sync --cache-dir /custom/cache/path
自定义缓存键(动态依赖)
当项目依赖 C 扩展、Git 子模块或其他需要自定义缓存失效逻辑时:
[tool.uv]
cache-keys = [
{ file = "Cargo.toml" }, # Rust 扩展:Cargo.toml 变化时重建
{ file = "build.rs" },
{ git = true }, # Git commit 变化时重建
{ env = "MY_BUILD_FLAG" }, # 环境变量变化时重建
]
配置文件
uv.toml vs pyproject.toml
| 配置文件 | 作用范围 | 适合场景 |
|---|---|---|
pyproject.toml 中的 [tool.uv] |
单个项目 | 项目特定配置 |
uv.toml |
项目级或全局级 | 单独管理 uv 配置,不混入 pyproject.toml |
~/.config/uv/uv.toml |
全局(用户级) | 个人偏好设置 |
uv.toml 中不能包含 [project]、[tool.uv.workspace]、[tool.uv.sources] 等项目相关字段,这些必须在 pyproject.toml 中。
常用配置项
# uv.toml 或 pyproject.toml 中的 [tool.uv]
[tool.uv]
# Python 版本
python-preference = "managed" # 优先使用 uv 管理的 Python
python-downloads = "automatic" # 自动下载缺失的 Python 版本
# 可选:"manual"(手动下载)、"never"(不自动下载)
# 解析策略
resolution = "highest" # 默认:选择最高兼容版本
# "lowest":选择最低兼容版本(用于检查依赖下限)
# "lowest-direct":直接依赖用最低,传递依赖用最高
# 链接模式(影响安装速度和磁盘使用)
link-mode = "clone" # 默认:COW 克隆(支持的文件系统)
# "copy":完整复制(兼容性最好,但最慢)
# "hardlink":硬链接(快,但跨磁盘无效)
# "symlink":符号链接
# 预发布处理
prerelease = "disallow" # 默认:不使用预发布版本
# "allow":允许预发布
# "if-necessary":仅在无稳定版时使用
# 构建隔离
no-build-isolation = false # 默认隔离构建环境
# 并发限制
concurrent-downloads = 50 # 并发下载数
concurrent-builds = 16 # 并发构建数
concurrent-installs = 8 # 并发安装数
配置项查找优先级
命令行参数 > 环境变量 > 项目 pyproject.toml [tool.uv] >
项目 uv.toml > 父目录 uv.toml > 用户 ~/.config/uv/uv.toml
环境变量参考
常用环境变量:
| 环境变量 | 说明 |
|---|---|
UV_PYTHON |
指定 Python 版本或路径 |
UV_PYTHON_DOWNLOADS |
控制自动下载:automatic、manual、never |
UV_PYTHON_INSTALL_DIR |
Python 安装目录 |
UV_PROJECT_ENVIRONMENT |
虚拟环境路径(相对或绝对) |
UV_INDEX_URL |
主索引 URL(替换 PyPI) |
UV_EXTRA_INDEX_URL |
额外索引 URL |
UV_DEFAULT_INDEX |
默认索引名称 |
UV_INDEX_{NAME}_USERNAME |
指定索引的用户名 |
UV_INDEX_{NAME}_PASSWORD |
指定索引的密码/token |
UV_CACHE_DIR |
缓存目录路径 |
UV_NO_CACHE |
设为 1 禁用缓存 |
UV_FROZEN |
设为 1 相当于 --frozen |
UV_LOCKED |
设为 1 相当于 --locked |
UV_NO_SYNC |
设为 1 相当于 --no-sync |
UV_DEV |
设为 1 相当于 --dev |
UV_NO_DEV |
设为 1 相当于 --no-dev |
UV_PUBLISH_TOKEN |
PyPI 发布 token |
UV_PUBLISH_URL |
发布目标 URL |
UV_LINK_MODE |
安装链接模式 |
UV_COMPILE_BYTECODE |
设为 1 安装时编译 .pyc 文件 |
UV_BREAK_SYSTEM_PACKAGES |
设为 1 允许修改系统 Python(CI/容器用) |
UV_SYSTEM_PYTHON |
设为 1 允许使用系统 Python |
UV_TOOL_DIR |
工具安装目录 |
UV_TOOL_BIN_DIR |
工具二进制文件目录 |
uv export
将 uv.lock 导出为其他格式(如 requirements.txt)。
uv export [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --format | str | requirements-txt | 导出格式 |
| --output-file / -o | str | stdout | 输出文件 |
| --no-dev | flag | 关闭 | 不包含开发依赖 |
| --extra | str | - | 包含指定可选依赖 |
| --all-extras | flag | 关闭 | 包含所有可选依赖 |
| --no-emit-project | flag | 关闭 | 不包含项目本身 |
| --no-hashes | flag | 关闭 | 不生成哈希值 |
| --frozen | flag | 关闭 | 不更新锁定文件 |
# 导出生产依赖(含哈希,安全部署)
uv export --no-dev -o requirements.txt
# 导出所有依赖(含开发)
uv export -o requirements-dev.txt
# 不含哈希
uv export --no-dev --no-hashes -o requirements.txt
# 导出可选依赖
uv export --extra docs -o requirements-docs.txt
Docker 集成
基础 Dockerfile
FROM python:3.12-slim
# 安装 uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# 设置工作目录
WORKDIR /app
# 先复制依赖声明文件(利用 Docker 层缓存)
COPY pyproject.toml uv.lock ./
# 安装依赖(不安装项目本身,充分利用层缓存)
RUN uv sync --frozen --no-install-project --no-dev
# 再复制项目代码
COPY . .
# 安装项目
RUN uv sync --frozen --no-dev
# 运行
CMD ["uv", "run", "python", "-m", "myapp"]
优化的多阶段 Dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
WORKDIR /app
# 编译字节码(减少运行时启动时间)
ENV UV_COMPILE_BYTECODE=1
# 使用 copy 链接模式(容器跨文件系统)
ENV UV_LINK_MODE=copy
# 安装依赖(分层,利用 Docker 缓存)
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project --no-dev
# 复制代码并安装项目
COPY . .
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
FROM python:3.12-slim AS runtime
WORKDIR /app
# 从 builder 复制虚拟环境
COPY --from=builder /app/.venv /app/.venv
# 复制项目代码
COPY --from=builder /app /app
# 将虚拟环境加入 PATH
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "myapp"]
.dockerignore
.venv
.git
__pycache__
*.pyc
*.egg-info
dist/
.pytest_cache/
.mypy_cache/
.ruff_cache/
安全审计
# 扫描依赖的已知漏洞(查询 OSV 数据库)
uv audit
# 只审计指定依赖组
uv audit --only-group test
# 排除 dev 依赖
uv audit --no-dev
# 审计指定 PEP 723 脚本
uv audit --script my_script.py
# 不更新锁定文件(CI 中使用)
uv audit --frozen
最佳实践
新项目启动
# 1. 初始化项目
uv init --lib my-project # 库
uv init --app my-app # 应用
cd my-project
# 2. 指定 Python 版本
uv python pin 3.12
# 3. 添加依赖
uv add fastapi pydantic sqlalchemy
uv add --dev pytest ruff mypy
# 4. 运行
uv run python -m myapp
uv run pytest
CI/CD 配置
# GitHub Actions 示例
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"
enable-cache: true
- name: Install dependencies
run: uv sync --frozen --all-extras
- name: Run tests
run: uv run pytest --cov
- name: Type check
run: uv run mypy src/
- name: Lint
run: uv run ruff check .
关键原则:
- CI 中始终使用
--frozen,确保使用锁定文件中的精确版本 - 使用
astral-sh/setup-uvaction 可以自动利用 GitHub Actions 缓存 uv.lock必须提交到版本控制
生产部署
# 只安装生产依赖,精确同步
uv sync --frozen --no-dev --exact
# 或导出 requirements.txt 供部署使用
uv export --frozen --no-dev --no-hashes -o requirements.txt
pip install -r requirements.txt # 在目标环境中
迁移现有 pip 项目
# 1. 初始化
uv init --bare # 在已有项目目录
# 2. 从 requirements.txt 导入依赖
uv add $(cat requirements.txt | grep -v "^#" | tr "\n" " ")
# 或者保留 requirements.txt 格式
uv pip compile requirements.in -o requirements.txt
# 3. 验证
uv run python -c "import mymodule; print('OK')"
常见场景命令速查
| 场景 | 命令 |
|---|---|
| 初始化应用 | uv init --app |
| 初始化库 | uv init --lib |
| 添加依赖 | uv add requests |
| 添加开发依赖 | uv add --dev pytest |
| 删除依赖 | uv remove requests |
| 安装环境 | uv sync |
| CI 安装 | uv sync --frozen |
| 升级所有依赖 | uv lock --upgrade |
| 运行脚本 | uv run python main.py |
| 临时运行工具 | uvx ruff check . |
| 安装全局工具 | uv tool install ruff |
| 安装 Python | uv python install 3.12 |
| 导出 requirements | uv export --no-dev -o requirements.txt |
| 构建包 | uv build |
| 发布包 | uv publish --token pypi-xxx |
| 清理缓存 | uv cache clean |
踩坑与注意事项
1. uv.lock 不应手动编辑
uv.lock 是 uv 自动维护的文件,手动修改会导致解析状态不一致。需要修改依赖时,始终通过 uv add、uv remove、uv lock --upgrade-package 操作。
2. 工作区的 requires-python 取交集
工作区所有成员的 requires-python 取交集,如果某个成员要求 >=3.9,另一个要求 >=3.12,工作区的有效范围是 >=3.12。应在工作区根的 pyproject.toml 中声明最终的交集范围。
3. tool.uv.sources 不影响发布的包
[tool.uv.sources] 中的来源配置只在本地生效,发布到 PyPI 时会被忽略(这是预期行为)。发布前用 uv build --no-sources 构建以验证。
4. --frozen 和 --locked 的区别
--frozen:完全不更新uv.lock,直接用现有版本安装。即使pyproject.toml有变化也忽略。--locked:检查uv.lock是否与pyproject.toml一致,不一致则报错(不自动更新)。
CI 中推荐 --frozen,本地开发时如果不希望无意中更新锁定文件可用 --locked。
5. dev 依赖组 vs optional-dependencies
| 特性 | [dependency-groups] (--dev/--group) |
[project.optional-dependencies] (--optional) |
|---|---|---|
| 是否发布到 PyPI | 否 | 是(随包分发) |
| 用途 | 本地开发、CI | 可选功能供用户安装 |
| 安装命令 | uv sync --group test |
uv sync --extra test |
6. editable 安装的行为
工作区成员间依赖默认是可编辑的(editable)。路径依赖如果指定 editable = true,修改源码后无需重新安装即可生效。非可编辑的路径依赖修改后需要重新运行 uv sync。
7. Python 版本自动下载
默认情况下(python-downloads = "automatic"),uv 会在需要时自动下载 Python 版本。如果在离线环境或不希望自动下载,设置:
export UV_PYTHON_DOWNLOADS=never
# 或
uv sync --no-managed-python
8. 依赖解析失败排查
# 查看详细解析过程
uv lock --verbose
# 查看依赖树
uv pip tree
# 检查特定包的依赖原因
uv pip tree --package requests
# 尝试最低版本解析(检查下界是否正确)
uv lock --resolution lowest
最佳实践
始终提交 uv.lock:lock 文件保证团队和 CI 使用完全相同的依赖版本树。将其纳入版本控制,并在 PR 中一并更新。
使用 uv add 而非手动编辑 pyproject.toml:uv add 会同步更新 pyproject.toml 和 uv.lock,手动编辑后必须运行 uv lock 才能同步锁文件,容易遗漏。
# 正确
uv add httpx
# 错误:手动改 pyproject.toml 后忘记 uv lock,导致 lock 文件与声明不一致
# 手动编辑 pyproject.toml...
# uv sync # lock 文件未更新,与 pyproject 不一致
在 [tool.uv] 中固定 Python 版本:避免不同环境使用不同 Python 版本导致行为差异。
[tool.uv]
python = "3.12"
CI 中使用 uv sync --frozen:--frozen 禁止 lock 文件更新,确保 CI 使用锁定版本,lock 文件若与 pyproject.toml 不一致则报错退出。
- name: Install deps
run: uv sync --frozen
用 uvx 运行一次性工具,不污染项目依赖:对于 black、ruff、mypy 等仅在开发时使用的工具,用 uvx 直接运行而无需安装到项目虚拟环境。
uvx ruff check .
uvx black --check .
开发依赖用 uv add --dev:将测试、格式化、类型检查等工具声明为开发依赖,生产环境用 uv sync --no-dev 跳过安装。
uv add --dev pytest ruff mypy
# 生产部署
uv sync --no-dev
常见陷阱
陷阱:修改 pyproject.toml 后未重新生成 lock 文件
现象: uv sync 报错 "lock file is not consistent with pyproject.toml",或安装的版本与 pyproject.toml 声明不符。
原因: 手动编辑 pyproject.toml 不会自动更新 uv.lock,两者产生不一致。
解决: 使用 uv add / uv remove 修改依赖,或修改后立即运行 uv lock。
# 修改 pyproject.toml 后必须执行
uv lock
uv sync
陷阱:缓存导致安装到旧版本
现象: 更新了版本约束,但 uv sync 后包版本未变化;或明明发布了新版本,uv 仍安装旧版本。
原因: uv 默认使用本地缓存(~/.cache/uv),缓存命中时不会重新下载。
解决: 清除缓存后重新同步。
uv cache clean
uv sync
陷阱:Workspace 中子包依赖解析冲突
现象: Workspace 根目录 uv lock 失败,提示某个子包要求的版本与其他子包冲突。
原因: Workspace 使用统一的 lock 文件,所有成员必须能共享同一个解析结果;子包之间的上界/下界约束互斥时无法解析。
解决: 放宽冲突包的版本约束,或在 [tool.uv] 中用 constraint-dependencies 固定中间版本。
# pyproject.toml (workspace root)
[tool.uv]
constraint-dependencies = ["pydantic>=2.0,<3"]