使用 uv 管理 Python 依赖

我有一个运行了好几年的 Django 项目,之前一直在使用默认的 pip 管理和安装依赖,最近切换到了 uv,感觉还不错,在这儿记录一下。

什么是 uv

根据官网的介绍,uv 是一个 Python 包以及项目管理器,非常快,使用 Rust 开发。

安装和管理依赖只是它的功能之一,除此之外,它还可以创建虚拟环境,即可以取代 pip + virtualenv 的功能。

我测试了一下,uv 确实比 pip 快了很多。在使用相同的镜像源,且都是纯净的 docker 环境下,使用 pip 安装项目的依赖花了约 88 秒,但使用 uv 只用了 13 秒。

不过,安装依赖并不是一个高频操作,多花一点时间一般不是什么痛点,uv 更吸引人的是它简化了很多工作,比如内置了 Python 多版本安装以及虚拟环境管理,且能保证环境的可复现性,这就让 Python 项目的开发和发布工作简单了很多。

uv 的安装和初始化

在 macOS 或 Linux 上,可以使用以下命令安装 uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

Windows 上的命令如下:

# On Windows.
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

安装完成之后,可以使用以下命令初始化一个新项目:

uv init my-project

如果你的项目已经存在,也可以直接进入项目根目录,执行以下命令:

uv init

如果项目中已经有 requirements.txt,想改用 uv 进行管理,可以在项目根目录执行以下命令:

uv pip install -r requirements.txt

也可以直接执行:

uv sync

初始化后,uv 会在项目根目录下生成一个 pyproject.toml 文件,其中包含了项目的基本信息以及依赖项。

可以运行以下命令,锁定依赖项:

uv lock

这个命令将会在项目根目录下生成 uv.lock 文件,类似 Node.js 的 package-lock.json,其中包含了项目依赖的各个第三方库以及版本号,确保下次安装时安装的包相同。

虚拟环境

Python 默认是安装在系统中的,使用 pip 安装依赖时,默认也会全局安装,在很多情况下,尤其是需要维护多个项目时,这显然不是我们期望的,此时可以使用虚拟环境。

在 uv 中使用虚拟环境很简单。

首先,可以使用 uv 安装多个不同版本的 Python:

uv python install 3.10 3.11 3.12

然后,可以通过类似下面的命令安装虚拟环境:

uv venv --python 3.12.0

可以直接在项目根目录下执行这个命令,执行成功之后,项目根目录下会生成一个 .venv 文件夹,包含这个环境的所有信息,之后安装的包也会保存在这个文件夹下,记得将这个文件夹添加到 .gitignore 中。

如果你熟悉 Node.js,会发现这个 .venv 文件夹和 Node.js 的 node_modules 文件夹功能类似,且它更进一步,不仅包含依赖,还能包含当前项目所需的 Python 本身。

使用以下命令可以用虚拟环境中的 Python 执行指定脚本:

uv run example.py

如果你在终端中访问项目,可以使用以下命令激活当前 Python 虚拟环境:

source .venv/bin/activate

激活虚拟环境之后,可以直接用类似 python example.py 的方式来运行项目中的脚本。

使用现代 IDE(比如 PyCharm、VSCode 等)打开这个项目时,IDE 一般都能自动识别项目中的 .venv 虚拟环境。

安装依赖

配置好环境后,就可以使用类似下面的命令安装依赖了:

uv add django

这信命令会下载对应的包并安装在 .venv中,安装成功之后,会修改 pyproject.tomluv.lock 文件。

如果你刚将代码从仓库中拉到本地,项目中已经有了 pyproject.tomluv.lock,那么只需执行以下命令即可安装所有依赖:

uv sync

注意,这个命令会根据 pyproject.toml 解析和下载依赖,有可能会改进 uv.lock。如果是在生产环境,你希望严格按照 uv.lock 中的版本安装依赖,可以使用以下命令:

uv sync --frozen

在 docker 中使用 uv

如果你的项目需要使用 docker 发布,还有一些额外需要注意的事项。

如果你的服务器在国内,那么可能需要使用国内 pypi 镜像,uv 中要指定镜像很简单,设置相应的环境变量即可,例如下面设置使用了阿里云的镜像:

ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
ENV UV_TRUSTED_HOST=mirrors.aliyun.com

在 docker 中安装依赖时,大体上有两种方式,一种是使用 uv sync 命令,如下所示:

WORKDIR /code/
COPY pyproject.toml uv.lock /code/

# 安装依赖
RUN uv sync --frozen --no-dev

ENV PATH="/code/.venv/bin:$PATH"

这种方式会在当前目录下创建虚拟环境,所有依赖都将安装到 .venv 目录下,因此需要将对应的目录加入 PATH。这种方式安装的依赖将严格遵守 uv.lock 中的版本限制,最为可靠。

或者,也可以选择将依赖直接安装到系统环境中:

RUN uv pip install --no-cache-dir --system .

注意那个 --system 参数,这种方式会将各依赖包安装到全局目录,如果你的 docker 中只有这一个 Python 项目,且不想使用虚拟环境,也可以使用这种方式安装。不过,这种方式安装时虽然也会参考 uv.lock,但并不保证各依赖的版本和 uv.lock 中严格相同。

小结

Python 发布迄今已有三十余年,一开始并没有第三方包的安装和管理工具,这和 Node.js 一发布就自带 npm 不同。如果你使用 Python 的时间较早,可能还会记得曾经有一个叫 easy_install 的工具用于安装 Python 的第三方包。

约 2008 年,pip 发布,随后在 2014 年被 Python 官方集成到 3.4 版中(以及 2.7.9 中),Python 这才有了一个官方的依赖管理工具。不过 pip 并不完美,主要是依赖解析能力较弱,无法保证每次安装后的环境完全相同,同时安装速度也有一些慢,因此后续又出现了一些新的依赖管理工具,比如 poetry、uv 等。

目前,开发 Python 项目的最佳实践是为每个项目创建独立的虚拟环境,将项目所需的依赖安装在该环境中,并通过依赖管理文件记录依赖,以确保隔离、可复现和可移植性。这些工作都可以使用 uv 完成,如果你正在开发或维护一个 Python 项目,不妨试试 uv。

分类:编程标签:Python
富文本框架体验

相关文章:

评论:

暂无评论

发表评论: