跳到主要内容

uv:Python 项目环境与依赖管理

对于依赖项均可通过 Python 包索引获取且拥有合适 wheel 包的常规仓库,推荐采用以下标准配置:

uv + pyproject.toml + uv.lock + 仓库本地 .venv

这并不意味着 Conda 被淘汰。uv 的核心职责是管理 Python 项目、Python 版本、依赖解析及命令执行;而 Conda 依然适用于原生库、非 Python 可执行文件及跨语言环境。每个环境必须有且仅有一个明确的管理者(Owner),严禁 pip、uv 和 Conda 在同一环境中交替修改,导致状态不可控。

基于边界的选择策略​

场景条件首选方案理由
应用、CLI、脚本或服务,依赖均有合适 wheeluv声明、锁定、环境与命令执行均封闭在项目内
Python 扩展已有目标平台 wheel先建立 uv 影子环境测试可安装性不代表运行时行为一致
必须从 Conda 获取 CUDA、BLAS、GDAL、GEOS、TA-Lib 等原生工具保留 Condauv 不替代系统级或跨语言依赖管理
生产自动化脚本指定了特定的 Conda 环境保留引用并并行验证迁移过程不得静默改变运行时路径
依赖来源、许可证或目标平台不明确暂缓迁移先建立资产清单和验收标准

冗长的 conda list 输出并非直接依赖列表,其中混杂了传递依赖、原生运行时及 Conda 基础设施。迁移时应从 pyproject.toml、requirements 文件、源码导入、入口点、测试及部署命令中重构真实的依赖意图。

项目模型​

pyproject.toml 定义预期的 Python 版本范围及直接依赖
uv.lock uv 解析出的精确依赖图
.python-version 可选的项目级 Python 版本指定
.venv/ 本地安装目录;应被 Git 忽略

uv.lock 必须提交至版本控制,但严禁手动编辑。锁定文件记录的是解析结果,而非对依赖安全性、许可证合规性或部署适配性的背书。

初始化项目​

uv python install 3.12
uv init --python 3.12 example-app
cd example-app
uv python pin 3.12

uv add requests
uv add --dev pytest
uv sync
uv run python --version
# 编写项目测试后,再运行:
# uv run python -m pytest

对于不打算打包安装的内部脚本集合,可配置如下:

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

[tool.uv]
package = false

package = false 仅改变安装行为,并不免除对测试、版本管理及依赖声明的要求。

接管现有仓库​

  1. 阅读现有的项目元数据、requirements、入口点、CI 配置及生产启动路径。
  2. 仅声明代码和运行时路径直接依赖的包,切勿直接复制整个已安装环境。
  3. 若仓库已存在 pyproject.toml,先执行 uv lock 和 uv sync;参照官方指南迁移 requirements。
  4. 保留旧环境,在仓库内建立 .venv 作为影子环境。
  5. 运行编译、单元/集成测试及代表性的只读工作负载。
  6. 对于数值或数据密集型负载,需对比结果、后端、线程模型及性能,而不仅仅是导入是否成功。
  7. 最后切换 CI、调度器、服务或编辑器,并设定明确的回滚目标。

切勿将环境管理器迁移与 Python 版本升级、大规模依赖刷新或应用重构混合进行,否则将导致故障原因无法隔离。

日常命令​

# 恢复并执行
uv sync
uv run python --version
uv run python script.py
uv run python -m unittest discover -s tests
uv pip check

# 有意识地变更声明
uv add pandas
uv add --dev pytest
uv remove pandas
uv tree

# 强制要求 lock 文件未变更
uv lock --check
uv sync --locked
uv run --locked python -m pytest

# 运行工具而不将其加入项目依赖
uvx ruff check .

默认情况下,uv sync 会根据项目元数据的需要更新 lock 文件;这一行为以及 --locked 与 --frozen 的区别,见官方锁定与同步文档。在 CI 和发布流程中应使用 --locked,以便在元数据过期时直接失败,而不是静默生成新的解析结果。--frozen 直接使用现有 lock 文件而不检查一致性,仅当明确需要此行为时使用。

优先使用 uv add/remove 而非手动向 .venv 安装包。环境是可丢弃的,pyproject.toml 和 uv.lock 才是项目状态的唯一事实来源。

与 Conda 共存​

共存应发生在仓库层面,而非让两个解析器共同管理同一环境:

  • 项目 A 使用 uv,项目 B 保留 Conda;
  • 同一项目可暂时保留 Conda 引用,并建立独立的 uv 影子环境;
  • 若 Conda 管理原生运行时,需文档化所有权及完整的命令路径;
  • uv sync 成功不代表可以删除 Conda 引用环境或修改生产配置。

预先定义切换标准:测试通过、代表性输出一致、依赖检查无误、目标平台安装成功、运行时行为验证完毕且回滚演练完成。

常见故障排查​

现象检查项
本地成功但 CI 重新解析是否提交了 uv.lock 并使用了 --locked
uv run 使用了意外的 Python 版本.python-version、requires-python 及 Shell 环境变量
安装成功但原生行为异常Wheel 后端、BLAS/CUDA、系统库及线程设置
仅手动激活环境后成功启动命令是否完整表达了环境上下文
Lock 文件过大正常现象;需区分直接声明与传递解析
私有索引认证失败使用受控凭据机制;严禁将 Token 写入文档、URL 或 Git

公开笔记的隐私边界​

公开示例仅使用 example-app、/path/to/repository 及占位服务。具体仓库名、内部域名、用户名、绝对目录、服务单元、迁移状态、测试数量及未公开依赖属于私有运维记录。公开的技术指南应保留可复用的决策逻辑与验证方法,而非泄露工作区资产清单。

探索关联打开关联网络