357 lines
10 KiB
Markdown
357 lines
10 KiB
Markdown
---
|
||
tags: [uv, python, package-manager, virtualenv, dependency-management]
|
||
create time: 2026-05-05 15:30
|
||
---
|
||
|
||
# UV — Fast Python Package Manager
|
||
|
||
## 概述
|
||
|
||
UV 是 Astral(Ruff 的出品方)开发的极速 Python 包管理工具,用 Rust 编写。它同时承担 **包安装器**、**虚拟环境管理器** 和 **解析器** 三种角色,兼容 `pip`/`venv`/`virtualenv` 的工作流,但在性能上实现了数量级提升。
|
||
|
||
> [!tip] 为什么选择 UV?
|
||
> pip + venv + virtualenv + poetry 需要多个工具协作——每个工具职责不同、配置分散。UV 将安装包、管理虚拟环境、生成 lock 文件、管理多版本项目统一到一个 CLI 中。基准测试显示,`uv pip install` 比 pip 快 **10~100 倍**。
|
||
|
||
> [!question] 思考
|
||
> 一个包管理工具为什么要重写为 Rust?
|
||
> —— Python 生态的依赖解析和下载是 I/O 密集型任务。Rust 提供了零成本抽象和极低的运行时开销,配合并发下载能力,这正是 pip(单线程 CPython 实现)难以企及的。
|
||
|
||
## 核心概念
|
||
|
||
### UV 与 pip/venv/poetry 的关系
|
||
|
||
```mermaid
|
||
graph TD
|
||
subgraph Traditional["传统工具链"]
|
||
P[pip — 包安装]
|
||
V[venv/virtualenv — 虚拟环境]
|
||
PO[poetry/pip-tools — 依赖锁定]
|
||
end
|
||
|
||
subgraph UVChain["UV 工具链"]
|
||
A[uv pip — 包安装]
|
||
B[uv venv — 虚拟环境]
|
||
C[uv lock — 依赖锁定]
|
||
end
|
||
|
||
Traditional --> D["三个独立工具配置分散"]
|
||
UVChain --> E["单一二进制零依赖"]
|
||
|
||
classDef old fill:#fef3c7,color:#92400e
|
||
classDef new fill:#dcfce7,color:#166534
|
||
classDef diff fill:#dbeafe,color:#1e3a8a
|
||
class P,V,PO old
|
||
class A,B,C new
|
||
class D,E diff
|
||
```
|
||
|
||
### 兼容模式 vs 原生模式
|
||
|
||
UV 支持两种使用方式:
|
||
|
||
| 模式 | 核心命令 | 适用场景 |
|
||
|------|----------|----------|
|
||
| **`uv pip` 兼容模式** | `uv pip install` / `uv pip compile` | 从 pip 迁移,完全兼容 `requirements.txt` |
|
||
| **UV 原生模式** | `uv add` / `uv lock` / `uv run` | 新项目推荐,基于 `pyproject.toml` 现代化工作流 |
|
||
|
||
> [!note] `uv pip` 与原生命令的区别
|
||
> - `uv pip install` 安装到系统或虚拟环境中的 site-packages,行为与 pip 一致
|
||
> - `uv add` 直接修改 `pyproject.toml` 中的依赖声明,并自动更新 `uv.lock`,适合有明确项目结构的项目
|
||
> - 生产环境建议优先使用原生模式,因为 lock 文件确保所有开发者使用完全一致的依赖树
|
||
|
||
### pyproject.toml 中的 UV 配置
|
||
|
||
UV 使用标准 `pyproject.toml`,通过 `[tool.uv]` 表进行专属配置:
|
||
|
||
```toml
|
||
[project]
|
||
name = "my-project"
|
||
version = "0.1.0"
|
||
requires-python = ">=3.11"
|
||
dependencies = [
|
||
"fastapi>=0.110.0",
|
||
"httpx",
|
||
]
|
||
|
||
[tool.uv]
|
||
dev-dependencies = [
|
||
"pytest>=8.0",
|
||
"ruff>=0.4.0",
|
||
]
|
||
|
||
# 指定 Python 源
|
||
[[tool.uv.index]]
|
||
name = "pypi"
|
||
url = "https://pypi.org/simple/"
|
||
|
||
# 私有源(如需)
|
||
#[[tool.uv.sources]]
|
||
#my-private-pkg = { index = "internal" }
|
||
```
|
||
|
||
## 安装
|
||
|
||
### 操作系统安装命令
|
||
|
||
```bash
|
||
# 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"
|
||
|
||
# Homebrew / apt / scoop
|
||
brew install uv # macOS
|
||
apt install uv # Ubuntu(需先添加仓库)
|
||
scoop install uv # Windows
|
||
```
|
||
|
||
> [!tip] 验证安装
|
||
> 安装完成后运行 `uv --version`,确认版本 ≥ 0.5.0。首次运行时 UV 会自动下载所需的 Python 版本并缓存,后续启动无需等待。
|
||
|
||
## 虚拟环境管理
|
||
|
||
### 创建与管理虚拟环境
|
||
|
||
```bash
|
||
# 创建虚拟环境(默认使用 .venv 目录)
|
||
uv venv
|
||
|
||
# 指定 Python 版本(自动下载缺失版本)
|
||
uv venv --python 3.12
|
||
|
||
# 指定目标路径
|
||
uv venv ./.venv-prod
|
||
```
|
||
|
||
创建成功后,激活方式与传统 venv 一致:
|
||
|
||
```bash
|
||
# macOS / Linux
|
||
source .venv/bin/activate
|
||
|
||
# Windows PowerShell
|
||
.venv\Scripts\Activate.ps1
|
||
```
|
||
|
||
### uv run — 零激活执行
|
||
|
||
```bash
|
||
# 在虚拟环境中直接运行命令,无需手动激活
|
||
uv run python main.py
|
||
|
||
# 传递参数
|
||
uv run pytest tests/ -v
|
||
|
||
# 交互式 REPL
|
||
uv run python -i
|
||
```
|
||
|
||
> [!tip] 为什么推荐使用 `uv run`?
|
||
> 省去了 `source .venv/bin/activate` 和 `deactivate` 的手动步骤。CI/CD、脚本调用、编辑器集成都可以通过 `uv run` 一次性完成——它会自行查找 `.venv` 或使用 `pyproject.toml` 中声明的环境。
|
||
|
||
## 包管理与依赖
|
||
|
||
### 原生模式:`uv add` / `uv remove`
|
||
|
||
```bash
|
||
# 添加生产依赖(写入 pyproject.toml + 更新 uv.lock)
|
||
uv add fastapi httpx
|
||
|
||
# 添加开发依赖(写入 dev-dependencies)
|
||
uv add --dev pytest ruff mypy
|
||
|
||
# 指定精确版本或范围
|
||
uv add "requests>=2.31,<3"
|
||
uv add flask==3.0.0
|
||
|
||
# 从 Git 仓库安装
|
||
uv add git+https://github.com/user/repo.git@branch
|
||
|
||
# 移除依赖
|
||
uv remove httpx
|
||
```
|
||
|
||
### `pip` 兼容模式:`uv pip`
|
||
|
||
```bash
|
||
# 安装 requirements.txt(行为与 pip install -r 一致)
|
||
uv pip install -r requirements.txt
|
||
|
||
# 生成锁文件(类似 pip-compile)
|
||
uv pip compile requirements.in -o requirements.locked.txt
|
||
|
||
# 卸载包
|
||
uv pip uninstall requests
|
||
```
|
||
|
||
### 版本解析策略
|
||
|
||
UV 使用基于 **回溯** 的高性能依赖解析器(由 pubgrub 算法驱动),与 Poetry 的行为语义相同:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A["用户请求: fastapi>=0.110 + httpx"] --> B{"解析依赖树"}
|
||
B --> C["发现冲突: A 要求 urllib3>=2, B 要求 urllib3<2"]
|
||
C --> D["尝试替换 B 为兼容版本"]
|
||
D -->|"解决"| E["输出唯一可行解 → uv.lock"]
|
||
D -->|"无解"| F["报错: 不可解析"]
|
||
|
||
classDef ok fill:#dcfce7,color:#166534
|
||
classDef fail fill:#f99,color:#7f1d1d
|
||
class E ok
|
||
class F fail
|
||
```
|
||
|
||
## Lock 文件
|
||
|
||
### `uv.lock` 的作用
|
||
|
||
`uv.lock` 是 UV 的依赖锁文件,记录的是经过解析后 **每一个子依赖的确切版本号**(不仅是顶层依赖)。这确保了:
|
||
|
||
1. 不同机器、不同时间安装得到完全相同的依赖树
|
||
2. CI/CD 环境可复现构建结果
|
||
3. 避免 "在我机器上是好的" 问题
|
||
|
||
### 典型工作流
|
||
|
||
```bash
|
||
# 新增依赖(自动生成或更新 lock 文件)
|
||
uv add httpx
|
||
|
||
# 手动更新 lock 文件(不改变 pyproject.toml,只更新锁定版本到最新兼容版)
|
||
uv lock
|
||
|
||
# 安装 lock 文件中锁定的所有依赖
|
||
uv sync
|
||
|
||
# 同步但排除 dev 依赖(生产环境)
|
||
uv sync --no-dev
|
||
```
|
||
|
||
> [!info] uv sync vs pip install -r
|
||
> - `uv sync` 会严格对照 `uv.lock` 安装——移除多余的、更新过期的、安装缺失的
|
||
> - `pip install -r` 只看 `requirements.txt`,不会主动清理已安装但未声明的包
|
||
> - 推荐始终使用 `uv sync` 代替 `pip install -e .`
|
||
|
||
## 多项目工作区(Workspace)
|
||
|
||
UV 支持 Monorepo 风格的多项目组织:
|
||
|
||
```toml
|
||
# pyproject.toml at workspace root
|
||
[project]
|
||
name = "workspace-root"
|
||
version = "0.1.0"
|
||
requires-python = ">=3.11"
|
||
|
||
[tool.uv.workspace]
|
||
members = ["packages/*"]
|
||
optional-groups = ["docs"]
|
||
```
|
||
|
||
```toml
|
||
# packages/web/pyproject.toml
|
||
[project]
|
||
name = "web-service"
|
||
dependencies = ["shared-lib"] # 引用 workspace 内的其他项目
|
||
```
|
||
|
||
```toml
|
||
# packages/lib/pyproject.toml
|
||
[project]
|
||
name = "shared-lib"
|
||
```
|
||
|
||
```bash
|
||
# 在工作区根目录操作
|
||
uv lock # 解析整个工作区的依赖
|
||
uv sync # 安装所有成员包的依赖
|
||
uv add -p web-service fastapi # 只为特定成员添加依赖
|
||
```
|
||
|
||
## 实战示例
|
||
|
||
### 创建一个 FastAPI 项目
|
||
|
||
```bash
|
||
# ① 创建项目并初始化 venv
|
||
uv init my-api
|
||
cd my-api
|
||
uv venv --python 3.12
|
||
|
||
# ② 添加依赖
|
||
uv add fastapi uvicorn httpx
|
||
uv add --dev ruff pytest
|
||
|
||
# ③ 运行项目
|
||
uv run uvicorn main:app --reload
|
||
|
||
# ④ 运行测试
|
||
uv run pytest tests/ -v
|
||
```
|
||
|
||
### CI/CD 流水线集成
|
||
|
||
```yaml
|
||
# .github/workflows/ci.yml(简化版)
|
||
jobs:
|
||
test:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Install UV
|
||
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
||
|
||
- name: Sync dependencies
|
||
run: uv sync --all-extras --frozen
|
||
|
||
- name: Run tests
|
||
run: uv run pytest tests/ -v
|
||
|
||
- name: Lint
|
||
run: uv run ruff check .
|
||
```
|
||
|
||
> [!warning] `--frozen` 标志的含义
|
||
> 加上 `--frozen` 时,如果 `uv.lock` 不存在或与 `pyproject.toml` 不一致,命令会直接失败而非自动更新。这在 CI 中很重要——确保 lock 文件的变更必须经过代码审查提交。
|
||
|
||
## 常用命令速查
|
||
|
||
| 命令 | 说明 | 等价命令 |
|
||
|------|------|----------|
|
||
| `uv add <pkg>` | 添加依赖到 pyproject.toml | `uv pip install` |
|
||
| `uv remove <pkg>` | 从依赖中移除 | `uv pip uninstall` |
|
||
| `uv sync` | 按 lock 文件同步环境 | `pip install -e .` |
|
||
| `uv lock` | 生成/更新 lock 文件 | `poetry lock` |
|
||
| `uv run <cmd>` | 在环境内执行命令 | `source .venv/bin/activate && cmd` |
|
||
| `uv venv` | 创建虚拟环境 | `python -m venv .venv` |
|
||
| `uv python list` | 列出可安装的 Python 版本 | `pyenv versions` |
|
||
| `uv python install 3.12` | 下载并缓存指定 Python | `pyenv install 3.12` |
|
||
| `uv pin 3.11` | 锁定项目 Python 版本 | 设置 `.python-version` |
|
||
| `uv export` | 导出为 requirements.txt | `pip freeze > req.txt` |
|
||
|
||
## 与其他工具的对比
|
||
|
||
| 维度 | pip + venv | Poetry | uv |
|
||
|------|-----------|--------|-----|
|
||
| 语言 | Python | Python | Rust |
|
||
| 安装速度 | 慢(单线程) | 中等 | ⚡ 极快(并发) |
|
||
| 虚拟环境 | `venv` 独立命令 | `poetry env` | `uv venv` 内置 |
|
||
| Lock 文件 | 需 pip-compile | `poetry.lock` | `uv.lock` |
|
||
| pyproject.toml | 第三方支持 | ✅ 原生 | ✅ 原生 |
|
||
| 多项目/Workspace | ❌ | ✅ | ✅ |
|
||
| Python 版本管理 | ❌ 需 pyenv | ❌ 需 pyenv | ✅ `uv python install` |
|
||
| 依赖大小 | 无额外依赖 | 较重 | 单个二进制 ~15MB |
|
||
| 成熟度 | 事实标准 | 高 | 快速迭代中 |
|
||
|
||
> [!info] 迁移建议
|
||
> - **pip 用户** → 直接使用 `uv pip` 命令获得加速,零迁移成本
|
||
> - **Poetry 用户** → `uv` 的 `add/sync/lock` 工作流与 Poetry 高度相似,学习曲线平缓
|
||
> - **新项目** → 直接用 `uv` 原生命令 + `pyproject.toml` + `uv.lock`
|
||
|
||
## 关联笔记
|
||
|
||
- [[hzh/DEV/Husky]] — Git Hooks 管理(可与 uv run 结合在 pre-commit 中运行 lint)
|