让uv管理Python的一切

你有没有遇到过这种情况:拿到一个Python项目后,结果发现光是配置环境就让人抓狂。打开Redmi一看,这项目居然用了Python 3.13的新特性,赶紧去安装。有的人直接到官网下载,有的人会用apt或者yum,有的人用专门的版本管理工具PyInf。下载好了,为了避免依赖冲突,用Venv建立一个虚拟环境吧。诶等等,听说Virtualenv也不错。环境建立好了,用什么来安装依赖呢?Pip、Pipenv,还是Poetry?终于开始写代码了,用Ruff检查一下代码类型吧。诶,怎么系统仓库中没有?难道又得去官网下载?等等,我听说用Pipx管理Python工具更好。真是够了!为什么Python开发环境会如此分裂?难道就没有一个工具能把这些乱七八糟的东西全都管理起来吗?

有,它的名字就是UV。它集成了以上所有的功能,从安装Python到创建虚拟环境、管理依赖、安装工具,以及最终的打包发布。今天我们就从头到尾体验一下使用UV开发的完整流程。我这里预先写好了一个AI Agent来当做示例程序,它可以根据要求生成Shell命令。最终效果是这样的:直接在命令后输入需求,它就会请求AI生成对应的Shell命令;如果需求不合理,就会返回错误。由此可以看出,即便是AI也有做不到的事情,所以这里拜托大家了。

现在我们从一个新的环境中来运行一下这个脚本。不出所料,Python抛出了异常。要让一段程序运行,通常我们需要解决两个问题:第一个是确定Python的版本,第二个是解决依赖。我们先来解决Python的版本问题。我们可以使用uv python list打印出UV支持的所有Python版本,可以看到UV支持从Python 3.7到还在预发布阶段的Python 3.14中的所有官方版本,同时它还支持第三方的实现PyPy。如果我们想安装一个特定版本的Python,可以用uv python install后面接想要安装的版本,这样UV就会开始下载并安装对应的版本。

安装完成之后,如果我们想用刚刚安装的Python 3.12临时运行一个文件,可以用uv run -p后面加上想用的版本以及脚本名称。如果想使用交互界面,可以把脚本名称换成python,可以看到现在的版本号已经是3.12了。其实在使用uv run之前,并不需要特意执行uv python install。比如这里我把Python的版本换成PyPy,如果之前没有安装过PyPy,UV就会在这个时候开始安装,可以看到现在已经是PyPy的交互界面了。

Python的版本问题我们解决了,现在我们来解决第二个问题:依赖。首先我们需要给小程序创建一个UV工程,命令是uv init -p加上Python版本号。这个时候,UV会创建一系列文件。我们用VSCode打开这个目录,看得稍微清楚一点。目录下的hello.py是UV生成的示例代码,没什么用,直接删了就行。然后.python-version文件记录了Python的版本信息,如果想换版本,可以在这里直接修改。ai.py是我们的原代码,可以看到现在VSCode提示它找不到Pydantic库。

这个时候我们可以使用uv add后面加上库的名字Pydantic,把这个库安装到当前的工程中。UV不仅会下载库文件,还会为工程创建一个虚拟环境,也就是.venv目录。我们可以通过点击VSCode右下角的Python版本号来调整VSCode使用的Python解释器,让它使用我们的虚拟环境。确定之后,VSCode中的错误就会消失了。刚刚我们安装的工程依赖会被记录在pyproject.toml文件中。

依赖问题现在解决了,这个时候我们可以使用不带参数的uv run来使用当前的虚拟环境运行ai.py文件了。可以看到我们的工具现在已经可以正常运行了。如果想知道工程所有库之间的依赖关系,我们还可以使用uv tree命令,这个命令会打印出整个依赖树。

代码已经可以运行了,假如现在我想用Ruff工具来检查一下代码是否符合规范,但我们现在的环境中并没有安装Ruff。解决这个问题的方法有很多,最直接的是把想用的工具当做依赖引入进来。这里我加了一个--dev参数,避免在打包的时候把Ruff也一起打包进来。安装完依赖之后,我们就可以使用安装的工具了。但是有的人认为,即便用了Dev依赖,把Ruff放进来也不太合适,因为它本质上是一个工具,和代码不相关。而Dev依赖应该放的东西还是和代码有关的,比如单元测试用到的PyTest或者Mock等。

既然如此,我们使用uv remove命令把Ruff先从依赖中删除,然后使用uv tool install命令把想要安装的工具直接安装到系统中。这里我还是安装Ruff,这个时候的Ruff就是脱离当前工程独立运行的了。可以看到它的路径并不是当前的虚拟环境。用uv tool install安装的工具是整个系统都可用的,而且UV在安装工具的时候会为每个工具建立自己的虚拟环境,所以我们也不需要担心工具之间的冲突。如果想查看已经安装的工具,可以使用uv tool list,可以看到我现在的系统中安装了Ruff和ShellGPT两个工具。

我们的AI小程序开发完了,现在我们来把它打包成一个可以直接运行的脚本。在pyproject.toml文件中,我们需要新加入一个section叫做project.scripts,然后写上想要的脚本名称,比如这里我就取名叫做ai,后面加上想要运行的Python脚本和函数名。编辑好pyproject.toml文件之后,我们可以用uv build命令把整个工程打包成WHL文件。然后这个打包好的WHL文件就可以发布到Python的软件仓库,给全世界的人使用了。

发布之后,别人就可以使用之前介绍过的uv tool install或者uv add方法来使用我们的代码了。这里我用uv tool install本地安装一下试试看。因为刚刚我们已经在pyproject.toml文件中指定了要生成一个叫做ai的可执行脚本,所以现在我们就可以直接使用ai命令了。这个ai命令和其他使用uv tool install安装的工具一样,它是整个系统都可用的,并且拥有自己的虚拟环境,不依赖当前的开发环境。

最后我们再用uv tool list来看一下已经安装好的工具,可以看到我们自己写的工具也已经在这里了。好了,今天介绍UV的视频就到这里了。视频中用的示例代码我会放到视频简介之中,有兴趣的小伙伴可以去看看。这里是程序员老王,我们下期再见!

使用 Hugo 构建
主题 StackJimmy 设计