更新日期:2026-10-18
一个 Python 项目在开发机上正常运行,换到 CI 或服务器却报错,常见原因是 Python 版本、依赖范围和实际安装结果没有一起管理。uv 可以帮助整理这些环节,但迁移时仍要分清依赖声明、锁文件与运行环境。
本文面向已有 requirements.txt 的普通 Python 应用,采用独立工作副本演练。命令依据 Astral 官方项目指南与同步文档核对,不要求替换系统 Python,也不建议把旧虚拟环境复制到生产机器。
三类文件各自负责什么
| 文件 | 作用 | 不能替代什么 |
|---|---|---|
| pyproject.toml | 项目元数据、Python 范围、直接依赖等 | 不等于完整解析结果 |
| uv.lock | uv 解析出的依赖锁定信息 | 不保证所有平台都能运行应用 |
| .python-version | 当前目录选择的 Python 版本 | 不替代 requires-python 兼容范围 |
一个项目可以声明支持若干 Python 版本,同时让本地开发固定使用其中一个版本。前者是兼容范围,后者是实际解释器选择。CI 还应记录 uv 版本、操作系统与架构。
迁移前先冻结现状
在现有项目中保存工作状态,记录原解释器、依赖与测试结果。如果 requirements.txt 是从一个长期使用的环境导出的,里面可能包含间接依赖和与项目无关的工具,不能直接视为精心维护的直接依赖列表。
python --version
python -m pip --version
python -m pip freeze
git status --short
命令需在原项目环境内执行。输出可能含私有依赖地址,归档时检查凭据。pip freeze 记录安装状态,不负责计算新的依赖锁定方案,这一点在官方说明中有明确区分。
路线一:先保留 requirements 工作流
如果暂时不想改项目结构,可以先用 uv 的 pip 接口建立新虚拟环境。这里选择 Python 3.12 仅用于示例,实际应使用项目已经验证的版本。
uv --version
uv venv --python 3.12
uv pip sync requirements.txt
uv pip check
在全新副本中执行,避免覆盖正在使用的 .venv。sync 会使环境与输入清单对齐;若输入只列直接依赖、并未包含完整依赖集合,应该先准备经过解析的完整清单,或选择合适的安装流程,不能假定它等价于任意 pip install -r 场景。
这种方式适合先验证工具与现有部署的配合,但它没有自动把项目转换为基于 pyproject.toml 和 uv.lock 的管理方式。
路线二:迁移到 uv 项目管理
在已有代码但还没有 pyproject.toml 的工作副本中,执行:
uv init --bare --python 3.12
uv python pin 3.12
uv add -r requirements.txt
uv sync --locked
--bare 建立最小项目配置,--python 3.12 避免初始化时根据本机较新的解释器生成不匹配的最低版本要求。随后固定解释器并导入依赖,会生成或更新锁定结果。若项目已经有 pyproject.toml,不要重新初始化,先检查原有构建后端、requires-python、依赖和工具配置,再决定如何整合。uv 项目指南
导入之后必须查看文件差异。特别留意被导出的间接依赖是否全部变成直接约束、平台专用包是否需要标记,以及 requirements 文件里的索引或本地路径是否能在其他机器上使用。
对已有约束文件,可以按官方支持的方式与导入配合;不要悄悄移除约束来“解决冲突”,因为它们可能来自真实兼容问题。
locked 与 frozen 不应混用
uv sync --locked 要求锁文件与项目声明保持一致,否则失败;--frozen 跳过锁文件是否需要更新的检查,按现有锁文件操作。CI 希望发现“改了声明却没更新锁文件”时,通常应使用前者。同步与锁定文档
不要为了让构建变绿,直接把 --locked 换成 --frozen。先确认声明和锁文件为何不同,修复后提交两者。
建议至少提交 pyproject.toml、uv.lock,以及项目采用的 Python 版本选择文件;虚拟环境本身不提交。部署机器根据这些文件重建环境,才能避免开发机中的绝对路径与原生扩展残留。
把测试和开发工具放到对应依赖组
例如项目使用 pytest,可以在确认需要后添加为开发依赖:
uv add --dev pytest
uv run --locked pytest
这条测试命令以项目已经有 pytest 测试为前提,没有测试文件时不会自动获得验证证据。实际应用还要执行构建、导入、启动与核心业务验收。
发布环境可根据项目结构选择不安装开发依赖,但运行所需的工具必须正确声明,不能碰巧依赖开发环境里存在的包。例如迁移命令若是发布步骤的一部分,就应明确它在哪个阶段、哪个环境运行。
CI 和部署需要固定的不止依赖
一份可复现记录还应包含 Python 版本、uv 版本、基础镜像或操作系统、CPU 架构,以及私有索引配置。涉及原生扩展时,编译器和系统库也会影响构建。
CI 的基本顺序是安装约定版本的工具、同步锁定依赖、运行测试、构建制品。秘密通过 CI 的凭据机制注入,不写进 pyproject.toml 或锁文件里的 URL。
上线前在与生产接近的环境重建一次,而不是重复使用开发机缓存。缓存可以提高速度,但不应该成为让构建成功的隐藏依赖。
出问题时如何退回
迁移初期保留原 requirements 文件、旧部署配置与上一版制品。若 uv 迁移出现问题,可以退回旧代码和部署方式,在新的虚拟环境按原流程安装;不要在已经同步过的环境里不断交替运行不同工具来猜测状态。
对数据库或业务状态的更改,应采用应用自己的兼容与回退方案。依赖环境回退不自动撤销数据库迁移。
验收至少包括:清洁环境重建成功、锁文件检查通过、测试通过、应用能够启动、主要业务动作完成。项目真正可维护的标志,是另一台机器根据记录能够重建,而不是本机安装速度变快了。
