uv sync 下载包版本问题
今天我们来聊一个使用 uv 工具进行python 项目管理时会遇到的包版本的问题。
当我们从远程仓库下载以个新的项目时,有了uv 工具,可以使用 uv sync 来一键同步项目开发的python 环境和第三方库,但是我们想象一个问题,如果项目在最早开发或者首次开发时,如使用 uv add mcp 安装了当时的最新版,此时,在pyproject.toml 文件记录的包版本为 "mcp>=1.6.0" 之后过了好久,这个包在pypi 中也更新了,如更新到 "1.7.0",那么当再次使用 uv sync 时,是安装 1.6.0 版本还是 1.7.0 版本呢?
以往在使用 pip 安装管理第三方库时,会通过 pip freeze >requirements.txt 来生成包版本文件,这里记录的是此时这个python 虚拟环境所有包的准确版本,如 mcp==1.5.0, 那么使用pip install -r requirements.txt 会按照这个文件中记录的版本进行安装,所有在团队开发过程中,团队成员之间会用到相同的第三方库,避免了由于库版本不一致导致的bug。
那么 uv 工具是如何解决这个问题的呢?
关于上面的问题,我们先来一起看一下 uv sync 是如何工作的
根据 pyproject.toml 和 uv.lock 的差异,确保你的虚拟环境中的依赖和锁文件一致。
-
如果
uv.lock存在,且没有变化,uv sync会严格按照uv.lock中指定的版本安装。 -
如果
uv.lock不存在,或你手动修改了pyproject.toml后没有重新生成锁文件(uv.lock),那么uv sync会解析pyproject.toml,拉取符合条件的最新版本,并生成新的uv.lock文件。
对于上面提到的这个场景:
pyproject.toml内容:
[project]
dependencies = [
"mcp>=1.6.0"
]
- 当前环境已安装:
mcp==1.6.0
-
之后
mcp发布了1.7.0。 -
如果你执行:
uv sync
- 如果存在旧的
uv.lock,且没有改动: 会继续安装1.6.0(除非你删除uv.lock或用uv pip compile重新生成锁文件)。 - 如果没有
uv.lock,或者执行了:
uv pip compile
uv sync
则会安装 1.7.0,因为它符合 >=1.6.0 的条件,并且是最新的 release。
总结一下
| 场景 | uv sync 行为 | 版本 |
|---|---|---|
| 存在旧的 uv.lock | 安装锁定的版本 | 1.6.0 |
| 没有 uv.lock 或重新 compile | 安装满足条件的最新版本 | 1.7.0 |
最佳实践
- 如果希望固定版本,不希望自动升级,可以在pyproject.toml 写死版本,或者在使用
uv add命令时指定版本uv add mcp==1.6.0
mcp==1.6.0
- 如果希望锁住某次的版本,但允许之后手动升级:
uv pip compile
uv sync
- 如果要强制升级所有依赖:
uv pip compile --upgrade
uv sync
uv 依赖管理最佳实践(团队规范)
接下来我们来一起看一下团队之间如何更好的使用 uv 来进行项目管理
此时的项目目录结构如下
project/
├── pyproject.toml # 定义依赖 (宽松)
├── uv.lock # 锁定具体版本 (自动生成)
└── requirements.txt # 选填, 兼容性导出
依赖添加原则
| 场景 | 写法 | 说明 |
|---|---|---|
| 核心依赖 | mcp>=1.6.0,<2.0.0 | 允许小版本升级,防止破坏性变更 |
| 临时锁死版本 | mcp==1.6.0 | 明确只允许这个版本 |
推荐命令流程
1. 安装依赖
uv sync
如果已有 uv.lock,则安装锁定版本。保证环境可复现。
2. 新增依赖
uv add 新库名称
- uv 会自动更新 pyproject.toml 和 uv.lock。
强制写死版本:
uv add 库名==版本号
3. 更新所有依赖(定期做)
uv pip compile --upgrade
uv sync
- 拉取满足 pyproject.toml 的最新版本。
- 生成新 uv.lock。
- 提交 PR。
4. 导出 requirements.txt(兼容某些平台)
uv pip compile pyproject.toml -o requirements.txt
这种是为了兼容还在使用 pip 进行包管理的项目。
流程图(关键流程)
+------------------+
| 新增/修改依赖 |
+--------+---------+
|
uv add xxx
|
+--------v---------+
| 自动更新 toml 和 |
| 生成 uv.lock |
+--------+---------+
|
uv sync
|
+--------v---------+
| 开发/运行 |
+------------------+
团队建议
| 事项 | 说明 |
|---|---|
| 新增依赖 | 用uv add 或者 uv pip install,不要手改 pyproject.toml |
| 定期升级 | 每月或每季度升级依赖,测试通过后提交 PR |
| CI/CD | 检查 uv.lock 是否和 pyproject.toml 保持一致 |
| 代码 Review | 新增依赖时,Review 是否有必要加上 upper bound(防止踩雷) |
总结
uv.lock 文件是安装包是自动生成的,我们不要手动修改这个文件,有了这个锁文件,当再次使用 uv sync 时会根据这个锁文件来同步包,确保团队之间开发环境一致性。
现在你应该知道文章开始时提出的那个问题的答案了吧?
