跳转至

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.tomluv.lock 的差异,确保你的虚拟环境中的依赖和锁文件一致。

  • 如果 uv.lock 存在,且没有变化,uv sync 会严格按照 uv.lock 中指定的版本安装。

  • 如果 uv.lock 不存在,或你手动修改了 pyproject.toml 后没有重新生成锁文件(uv.lock),那么 uv sync 会解析 pyproject.toml,拉取符合条件的最新版本,并生成新的 uv.lock 文件。


对于上面提到的这个场景:

  1. pyproject.toml 内容:
1
2
3
4
[project]
dependencies = [
    "mcp>=1.6.0"
]
  1. 当前环境已安装:
mcp==1.6.0
  1. 之后 mcp 发布了 1.7.0

  2. 如果你执行:

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 来进行项目管理

此时的项目目录结构如下

1
2
3
4
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 时会根据这个锁文件来同步包,确保团队之间开发环境一致性。

现在你应该知道文章开始时提出的那个问题的答案了吧?