当前位置: 代码网 > it编程>前端脚本>Python > Python项目迁移到uv的完整流程步骤

Python项目迁移到uv的完整流程步骤

2026年09月08日 Python 我要评论
迁移前要确定的事python 版本区间:项目实际验证过的版本非默认来源:私有源地址、--extra-index-url、--trusted-host、裸 wheel url当前版本快照:pip fre

迁移前要确定的事

  1. python 版本区间:项目实际验证过的版本
  2. 非默认来源:私有源地址、--extra-index-url--trusted-host、裸 wheel url
  3. 当前版本快照:pip freeze > baseline-freeze.txt,迁移后拿它做对照,出问题时也能回滚
  4. 搞清楚两个容易混的概念:.python-versionrequires-python
    • .python-version:由 uv python pin 生成,决定 uv runuv sync 用哪个本地解释器
    • requires-python:写在 pyproject.toml 里,决定 uv lock 解析时覆盖的版本区间。区间越窄,锁文件越小

初始化 uv 项目

已有 pyproject.toml 则跳过 uv init

uv init --no-readme
uv python pin 3.12
[project]
requires-python = ">=3.12,<3.13"

最好把 .python-version 提交,用 git 管理。

一个容易踩的坑:uv pip install 不读 requires-python,只认当前激活环境或当前目录下的 .venv。所以用 uv pip 系列命令之前,先跑一遍 uv sync.venv 建好。

导入 requirements.txt

requirements.txt 中的关键包最好锁定精确版本:

# 不推荐
vlt-xxx-aws
# 推荐
vlt-xxx-aws==0.1.53

为什么要精确?一是私有源上的包往往没有严格的 semver 保证,版本号跳动的含义跟 pypi 上的包不是一回事;二是如果内部包跟 pypi 上某个公开包重名,不锁精确版本时解析器可能会取到完全没预料到的来源。这类问题排查起来很费时间,因为表现出来就是"依赖版本对不上",但根源是包来源搞错了。

导入命令:

uv add -r requirements.txt

uv add -r 会重写 pyproject.toml 并重新解析锁文件。uv sync 只按现有锁文件同步环境,不能替代迁移导入。

私有源踩过的坑

举一个真实场景。配好私有源之后,uv add 突然报这样的错:

no solution found when resolving dependencies:
`-> because there is no version of psutil==6.1.0 ...
    hint: `psutil` was found on http://xxxx-pip.xxxx.lan/simple, but not at the requested version
    a compatible version may be available on a subsequent index ...

第一反应往往是"这个包是不是被删了",但其实包还在,只是版本不全——原因出在 uv 默认的 index-strategy = "first-index" 策略上:uv 按索引顺序查找,包名一旦在某个索引里找到,就只从这个索引解析这个包,不会再去后面的索引找更全的版本。这里的坑是,内部镜像代理了 psutil,但只同步了部分版本,uv 找到包名就停手了,根本不会意识到后面还有一个版本更全的索引。

索引配置长这样:

[[tool.uv.index]]
name = "private"
url = "http://xxo-private-pip.xxxx.lan:9090/simple"
default = true

[[tool.uv.index]]
name = "internal-wheels"
url = "http://172.xx.xxx.229:8899/simple/"

[[tool.uv.index]]
name = "xxp"
url = "http://xxp-pip.xx.lan/simple"

[tool.uv]
allow-insecure-host = [
  "xxo-private-pip.xxxx.lan",
  "172.xx.xxx.229",
  "xxp-pip.xx.lan",
]

几点要注意:

  • default = true 会禁用 pypi,并把这个索引放到已配置索引里优先级最低的位置。
  • requirements.txt 里的 --trusted-host 对应的是 allow-insecure-host,不是索引配置里的 trusted 字段——这两个名字太像,很容易配错地方。
  • 能配出有效 tls 证书的话,优先修证书,allow-insecure-host 只应该是长期方案里的例外,不是常态。

解决刚才那个 psutil 问题,有两种思路:

一种是全局关闭 first-index 策略:

[tool.uv]
index-strategy = "unsafe-best-mxxxh"

这样会跨所有索引找最高版本,但风险也最大——只有当你配置的所有索引都完全可信时才应该这么做,否则相当于把供应链安全性拱手让出去。

更推荐的做法是单包 pin 来源,只解决出问题的那一个包:

[tool.uv.sources]
psutil = { index = "private" }

[[tool.uv.index]]
name = "private"
url = "http://xxxx-private-pip.xxxx.lan:9090/simple"

url 依赖

uv 不允许 url 依赖仅作为传递依赖存在,必须在 dependencies 中显式声明,并在 [tool.uv.sources] 里配置来源:

[project]
dependencies = ["xxx-engine-alarm"]

[tool.uv.sources]
xxx-engine-alarm = { url = "http://.../xxx_engine_alarm-0.0.3-py3-none-any.whl" }

如果第三方包内部也用 url 声明了同一个依赖,两边必须完全一致(版本、url、hash),否则会报类似这样的冲突:

error: requirements contain conflicting urls for package `xxx-engine-alarm`:
- http://.../xxx_engine_alarm-0.0.3-py3-none-any.whl
- http://.../xxx_engine_alarm-0.0.3-py3-none-any.whl (from a transitive dependency)

看着像是同一个 url,但差一个字符(比如内部包里写的是旧版本号,或者 hash 对不上)都会触发。遇到这种报错,先去翻第三方包自己声明的依赖来源,跟你项目里写的逐字比对。

过渡期兜底

如果时间紧,可以先用两条命令临时把依赖跑起来:

uv add -r requirements.txt --frozen       # 跳过锁文件更新,临时导入依赖声明
uv pip install -r requirements.txt        # 完全绕开项目解析

这两条本质上相同——都是"先让代码跑起来,锁文件的事后面再说"。--frozen 不会生成可信的 uv.lock;uv pip install 干脆不走项目解析这条路,执行前记得确认 .venv 已经建好。这两条命令用完之后,一定要回头补上正式的 uv lock

收尾验证

重新生成锁文件:

uv lock

干净环境复现:

# windows
remove-item -recurse -force .venv
# unix/macos
rm -rf .venv
uv sync
uv run python -c "import sys; print(sys.version)"

对照 baseline-freeze.txt 抽查关键包版本

在 ci 或另一台干净机器上再跑一次 uv sync,确认不依赖本机缓存。最终再执行一遍工程的测试或者服务,确保没有报错,这才是根本的。

如果要回滚

迁移过程中如果卡住,回滚比继续排查更划算的情况不少见。核心是保留住两样东西:baseline-freeze.txt 和原来的 requirements.txt

rm -rf .venv
python -m venv .venv
source .venv/bin/activate   # windows 用 .venv\scripts\activate
pip install -r requirements.txt

回滚不需要动 pyproject.tomluv.lock——留着它们,下次再迁移时可以从上次中断的地方继续。

uv.lock 体积过大

最常见的原因是 requires-python 区间过宽。修复方式是收窄区间后重新生成锁文件:

[project]
requires-python = ">=3.12,<3.13"
uv lock

另一个不那么明显的原因是索引配置太多:配置的源越多,解析器给每个包做候选校验时要跨的源就越多,锁文件里记录的候选信息也会跟着膨胀。如果收窄 requires-python 之后体积还是没降下来,可以回头看看 [[tool.uv.index]] 是不是配多了,有没有可以合并或去掉的。

注意 --python 3.12 只影响本次命令使用的解释器,不等同于把锁文件限制到 3.12——这是两回事,别用命令行参数当作长期配置的替代品。

迁移后的日常开发

迁移后,你的日常命令会变成这样,项目即环境,更加干净和高效:

场景旧命令 (pip/venv)新命令 (uv)作用
初始化python -m venv .venvuv init创建项目骨架和 pyproject.toml
添加依赖pip install requestsuv add requests安装并记录到 pyproject.toml 和 uv.lock
同步环境pip install -r requirements.txtuv sync一次性安装所有依赖,让环境与锁文件完美同步
运行脚本先激活环境,再 python script.pyuv run python script.py自动激活环境并运行脚本,一步到位
导出依赖pip freeze > requirements.txtuv export > requirements.txt将当前锁定依赖导出为旧格式,便于兼容

总结:拥抱更快的现代工作流

迁移到 uv 不只是换一个安装工具,更是切换到一套更高效、更统一的现代化 python 工作流。它将 python 版本管理、虚拟环境、依赖安装和项目管理整合在一个工具中,解决了传统工具链分散和依赖解析缓慢的问题。

以上就是python项目迁移到uv的完整流程步骤的详细内容,更多关于python项目迁移到uv的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com