Python 项目的依赖已经锁定,为什么构建任务还要带上项目清单,甚至工作区里多个成员的配置文件?在容器构建和依赖分析中,这些额外输入会让流程更难拆分:有的任务只想安装外部依赖,有的只想生成一份依赖清单,却仍与完整项目布局绑定。
Astral 发布的 uv 0.12.23,为这类场景新增了 frozen-lockfile 预览能力。GitHub 记录的发布时间是 2026 年 10 月 3 日 17:34 UTC,即北京时间 10 月 4 日 01:34。同步、导出、查看依赖树和读取工作区元数据,现在可以在缺少工作区清单时发现并使用 uv.lock。
它让锁文件能承担更多构建输入的职责,但仍有版本和内容要求。本地包安装需要源码和构建元数据,某些配置也没有写进锁文件。真正值得尝试的,是把依赖准备、应用构建和清单分析拆成职责更清楚的步骤。
从依赖声明到安装计划,中间已有一次解析
在 uv 的项目流程里,pyproject.toml 保存项目元数据和依赖声明,uv.lock 保存解析后的依赖结果。锁定依赖与同步环境是两个不同的动作:前者决定版本和依赖关系,后者将选定的包安装到环境中。
uv 默认会自动锁定和同步。例如,运行项目命令或查看依赖树时,工具可能先检查并更新锁文件,以便与当前项目保持一致。这适合日常开发,却让只消费已有依赖结果的任务仍然需要项目清单。
0.12.23 的变化集中在冻结操作上。工具可以从已有锁文件读取必要信息,在工作区清单不在场的情况下继续处理。根据对应代码变更说明,如果清单仍然存在,工具依旧会读取其中的配置;独立锁文件模式提供的是额外的发现和执行路径。
四类任务可以围绕锁文件拆开
发布说明将这次新增能力全部列在 Preview features 下,涉及以下操作:
| 操作 | 缺少工作区清单时新增的能力 | 适合拆出的任务 |
|---|---|---|
uv sync --frozen |
从锁文件同步选定的环境依赖 | 容器中的依赖准备阶段 |
uv export --frozen |
从锁文件导出其他格式 | 与其他工具对接的依赖清单生成 |
uv tree --frozen |
从锁文件查看依赖树 | CI 中的依赖关系检查 |
uv workspace metadata --frozen |
从锁文件读取工作区元数据 | 工作区成员和环境信息分析 |
官方预览文档支持通过 --preview-features frozen-lockfile 明确启用这一项。相关变更说明还指出,某些冻结操作在没有显式启用时会输出预览警告。因此,给团队编写示例时,最好直接写出具体预览项,让读者知道使用的是哪项尚未稳定的能力。
在 uv 0.12.23、符合要求的锁文件和适当的依赖布局下,一个只准备外部依赖的示例是:
1 | uv sync --frozen \ |
这里显式跳过工作区成员的安装,并排除默认依赖组。它适合演示依赖层与应用层的分离;若项目还有额外的本地路径依赖,仍需提供那些包所需的文件。项目需要哪些依赖组,也应根据实际用途选择。
只查看依赖或导出清单,可以使用:
1 | uv tree --frozen --preview-features frozen-lockfile |
uv export 默认输出到标准输出。导出的 requirements.txt 是与其他工具对接的结果,不必再成为另一份独立维护的依赖来源。
冻结使用与检查新鲜度,需要安排在不同步骤
这次更新也让 --locked 和 --frozen 的差别更值得关注。
按照 uv 官方文档,--locked 会检查锁文件是否与项目元数据一致;发现需要更新时,工具报错,而非自动修改锁文件。--frozen 则使用已有锁文件,并跳过这项新鲜度检查。
在完整仓库中,可以先执行:
1 | uv lock --check |
这一步确认提交中的清单与锁文件一致。后续构建阶段再以冻结方式消费同一份锁文件,就能减少与完整项目布局的耦合。
如果项目声明已经改变,而构建阶段只收到旧的 uv.lock,冻结操作本身不会替前置步骤发现这一差异。因此,应把清单校验和锁文件生成留在能够读取完整仓库的任务里,再将通过检查的结果交给后续任务。
仅有锁文件时,仍要确认三个输入边界
首先是锁文件的修订号。同步、导出和工作区元数据相关变更说明要求独立锁文件操作使用 revision 5 或更高版本。这里的 revision 是锁文件内部格式信息,与 uv 的 0.12.23 版本号不同。旧锁文件应由合适版本的工具生成或更新,并审查差异,不能靠手工修改修订号补齐缺失的信息。
其次是本地包的源码和构建元数据。锁文件可以记录依赖关系与来源,但安装本地包仍需要其源码树和构建信息。--no-install-workspace 可以跳过工作区成员的安装,同时保留它们所需依赖的安装;它不会自动解决所有本地路径包缺失的问题。若要构建应用本身,后续阶段仍须加入应用源码及相应清单。
第三是没有被写入锁文件的配置。导出功能的变更说明明确指出,--emit-index-url 和 --emit-find-links 仍要求 pyproject.toml,因为相应配置没有记录在锁文件中。同步时,如果清单在场,工具也会利用其中的额外构建依赖来源配置。
因此,迁移现有流水线前,应列清楚它依赖哪些清单配置、包索引和本地文件。冻结安装仍可能下载包或执行构建,实际运行环境也需要具备相应网络和构建条件。
CI 和容器构建,可以先从依赖层试起
对以外部依赖为主的项目,这项能力提供了一种更直接的分层方式:在完整仓库里校验并生成锁文件,让依赖准备阶段消费它,随后再加入应用源码并完成应用构建。
当依赖层的输入保持不变时,业务代码修改有机会复用已有依赖层。实际缓存效果仍取决于构建文件、依赖来源和流水线布局,发布说明没有给出可直接套用到所有项目的加速比例。
可以先选一个代表性项目验证三个问题:新旧流程安装的依赖集合是否一致,选定的依赖组和 Python 要求是否正确,本地包与额外构建依赖是否仍能正常处理。对于多成员工作区,还应覆盖单独选择成员和组合选择成员的情况。
在这些检查通过后,再扩大使用范围,并固定 CI 使用的 uv 版本。预览能力仍可能调整,保留原有完整项目构建流程,也便于在出现兼容问题时定位和恢复。
结语
uv 0.12.23 让锁文件在依赖同步和分析中承担了更独立的角色。对构建流程的价值,是让已经解析好的依赖结果更容易交给后续任务使用,减少这些任务对完整项目布局的依赖。
使用时,应同时保留前置清单校验,并识别源码、构建元数据和未记录配置的边界。这样拆分出来的流水线,才既能利用锁文件的确定性,也能清楚说明每个阶段还需要哪些输入。
参考来源
- Astral:uv 0.12.23 发布说明,发布说明日期为 2026 年 10 月 3 日;GitHub 发布时间为北京时间 10 月 4 日 01:34。
- uv:冻结同步与缺少工作区清单的支持变更,包含锁文件修订号、本地包和构建元数据的限制。
- uv:冻结导出与缺少工作区清单的支持变更,包含导出所需配置的边界。
- uv:0.12.23 版本的锁定与同步文档,用于核对
--locked、--frozen、依赖组及部分安装选项。 - uv:0.12.23 版本的预览功能文档,用于核对预览项的启用方式。