使用uv管理Python环境
哎UV!您吉祥!
uv是什么?
请看: https://docs.astral.sh/uv/
简单来说,uv
是一个Rust写的Python环境与包管理器,旨在取代pip
。
基本的uv安装配置
No! 我们的宝贵时间,不应该浪费在这种重复工作上!请直接参考官网教程。
对喜欢自己动手的人来说,安装也很简单:直接去Github
Release下载发行包,把uv
和uvx
丢进~/.local/bin
,确保这个目录在PATH里,然后往~/.bashrc
加两句:
1 | eval "$(uv generate-shell-completion bash)" |
开始使用
定义项目依赖
uv
当然可以像pip
那样使用,例如uv pip install numpy
。但这似乎不是最优雅的方法。
对于uv
来说,每个文件夹就可以被认为是一个Project。因此,推荐的做法是,在pyproject.toml
定义项目依赖的pip包,以及版本号要求等。例如:
1 | [project] |
这之后,只需要执行一句:
1 | uv sync |
uv
就会在当前目录.venv
下创建一个虚拟环境,并安装pyproject.toml
中定义的依赖项。
只需要等待处理完毕,然后source .venv/bin/activate
,即可激活使用环境。
配置pypi软件源
众所周知,配置软件仓库镜像站已成为配环境的必备之路。
配环境笑传之Configure仓必。
uv
默认不使用pip.conf
配置项。
如果希望镜像配置仅对当前项目生效,可以直接编辑pyproject.toml
,填入以下内容:
1 | [[tool.uv.index]] |
而对于一些使用独立软件源的包(如PyTorch),则需要定义额外的index
项目,并在sources
中显式要求这些包使用这些软件源:
1 | [tool.uv.sources] |
上述index
定义适用于提供index-url
,也就是符合PEP 503规范的软件源。
而对于find-links
的软件源,只需要在定义index
时加一句format = "flat"
即可。例如:
1 | pyg_lib = [ |
怎么判断需要用的软件源要不要加format = "flat"
一句呢?
很简单,看这个软件源提供的pip
安装示例代码。如果其通过-i/--index-url <url>
指定软件源,那就不需要加。反之,如果是通过-f/--find-links <url>
指定的,那就需要。
TOML语法
包括我在内,一定有人好奇,为啥上面的配置文件中,为啥[[tool.uv.index]]
中需要两对方括号[[]]
?
这是TOML中的Array of Tables语法,Table实际上就是字典。
具体到uv
配置文件,可以认为uv
的配置项目中存在一个index
数组,该数组包含了多条index信息字典。
例如:
1 | [[tool.uv.index]] |
等价到JSON中就是:
1 | { |
配置文件细节
uv
会从多个位置探测并加载可能的配置文件,按照大致的覆盖顺序为(后面的会覆盖先前的):
- System-Level Config
- Unix:
/etc/uv/uv.toml
和$XDG_CONFIG_DIRS/uv/uv.toml
- Windows:
%SYSTEMDRIVE%\ProgramData\uv\uv.toml
- Unix:
- Use-Level Config
- Unix:
~/.config/uv/uv.toml
和$XDG_CONFIG_HOME/uv/uv.toml
- Windows:
%APPDATA%\uv\uv.toml
- Unix:
- Project-Level Config
./pyproject.toml
./uv.toml
和pyproject.toml
不同,uv.toml
中的配置项不需要包含tool.uv
前缀。
例如,为了配置uv
使用的pypi镜像站,在pyproject.toml
中可以指定:
1 | [[tool.uv.index]] |
而在uv.toml
中,则需要写成:
1 | [[index]] |
管理Python版本
uv
还提供了管理Python版本的功能,可以像conda那样,安装指定版本的Python解释器。
例如,如果需要安装3.14版本的Python:
1 | uv python install 3.14 |
同时,如果希望为每个项目指定版本号,也可以在pyproject.toml
中指定requires-python
。例如:
1 | [project] |
然而,uv
使用的Python二进制包来自astral-sh/python-build-standalone项目,该项目是托管在Github上的,下载有时候并不顺畅。
一种解决思路是,在uv
配置中指定python-install-mirror
,指向你能访问到的最快的Github。例如,在pyproject.toml
中:
1 | [tool.uv] |
手动创建虚拟环境
是的,总有人喜欢掌控一切的感觉。
例如,如果就是不喜欢uv
默认在每个项目下创建.venv
的行为,就是喜欢创建一些集中式的虚拟环境,然后在其他项目中激活使用,那该怎么办呢?
很简单:
1 | uv venv /path/to/venv |
甚至还能指定一下Python版本号:
1 | uv venv ./venv -p 3.14 |
不过,在可能的时候,uv
会使用文件链接创建环境,多个环境内的相同依赖项会被复用。所以其实不太需要担心创建环境带来的磁盘重复开销问题。
但是,如果需要使用uv sync
安装软件包,uv sync
默认使用的环境是当前目录下的.venv
。如何让uv sync
使用任意虚拟环境呢?
也很简单,只需要先激活对应的环境,然后在uv sync
加上一个参数--active
即可。
1 | source /path/to/venv/bin/activate |
和Conda/Mamba一起使用
到目前为止,既然uv
已经能实现管理Python版本的功能,实话说已经想不太出Conda/Mamba的用武之地。
如果希望在Conda中创建环境,然后使用uv
管理软件包,那其实整体上和上面的手动创建虚拟环境是类似的。
不过,uv sync
可能会遇到问题,无法识别Conda创建的环境。这时候就需要使用uv pip install
安装包。
1 | mamba activate -n myvenv |
uv pip install
是最通用的包安装方法,-r pyproject.toml
表示从pyproject.toml
中读取依赖项并安装,该参数也可以是requirements.txt
。
链接模式
在安装软件包时,如果目标虚拟环境和uv
的缓存不在一个文件系统下,可能会弹出以下警告:
1 | warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance. |
在Windows和Linux下,uv
默认通过创建缓存到site-packages
的hardlink以安装软件包。(MacOS下是创建的CoW克隆,不过我没有Mac,不太清楚实现细节)
然而,众所周知,Hardlink不能跨文件系统创建,那难道就要像上面的说明一样,给环境文件都做个全量复制?
好奇宝宝们,就不好奇一下,有没有比较折中的方案——SymbolLink吗?
有的,兄弟,有的。不过要翻一翻手册才能明确。只需要在命令行中指定--link-mode symlink
:
1 | uv sync --link-mode symlink |