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
内容:
- 当前环境已安装:
-
之后
mcp
发布了1.7.0
。 -
如果你执行:
- 如果存在旧的
uv.lock
,且没有改动: 会继续安装1.6.0
(除非你删除uv.lock
或用uv pip compile
重新生成锁文件)。 - 如果没有
uv.lock
,或者执行了:
则会安装 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
- 如果希望锁住某次的版本,但允许之后手动升级:
- 如果要强制升级所有依赖:
uv 依赖管理最佳实践(团队规范)¶
接下来我们来一起看一下团队之间如何更好的使用 uv 来进行项目管理
此时的项目目录结构如下
依赖添加原则¶
场景 | 写法 | 说明 |
---|---|---|
核心依赖 | mcp>=1.6.0,<2.0.0 | 允许小版本升级,防止破坏性变更 |
临时锁死版本 | mcp==1.6.0 | 明确只允许这个版本 |
推荐命令流程¶
1. 安装依赖¶
如果已有 uv.lock,则安装锁定版本。保证环境可复现。
2. 新增依赖¶
- uv 会自动更新 pyproject.toml 和 uv.lock。
强制写死版本:
3. 更新所有依赖(定期做)¶
- 拉取满足 pyproject.toml 的最新版本。
- 生成新 uv.lock。
- 提交 PR。
4. 导出 requirements.txt(兼容某些平台)¶
这种是为了兼容还在使用 pip 进行包管理的项目。
流程图(关键流程)¶
团队建议¶
事项 | 说明 |
---|---|
新增依赖 | 用uv add 或者 uv pip install,不要手改 pyproject.toml |
定期升级 | 每月或每季度升级依赖,测试通过后提交 PR |
CI/CD | 检查 uv.lock 是否和 pyproject.toml 保持一致 |
代码 Review | 新增依赖时,Review 是否有必要加上 upper bound(防止踩雷) |
总结¶
uv.lock 文件是安装包是自动生成的,我们不要手动修改这个文件,有了这个锁文件,当再次使用 uv sync 时会根据这个锁文件来同步包,确保团队之间开发环境一致性。
现在你应该知道文章开始时提出的那个问题的答案了吧?
