从 pip 迁移到 uv 项目
本指南将讨论如何从以 requirements
文件为中心的 pip
和 pip-tools
工作流程转换为使用 pyproject.toml
和 uv.lock
文件的 uv 项目工作流程。
注意
如果您希望从 pip
和 pip-tools
迁移到 uv 的直接替代接口,或者从您已经使用 pyproject.toml
的现有工作流程迁移,那么这些指南尚未编写。请参阅 #5200 以跟踪进度。
我们将从概述使用 pip
进行开发开始,然后讨论迁移到 uv。
提示
如果您熟悉该生态系统,您可以跳到 requirements 文件导入 说明。
理解 pip 工作流程
项目依赖
当您想在项目中使用一个包时,您需要先安装它。pip
支持命令式地安装包,例如
这会将包安装到安装了 pip
的环境中。这可能是一个虚拟环境,或者您系统 Python 安装的全局环境。
然后,您可以运行一个需要该包的 Python 脚本
最佳实践是为每个项目创建一个虚拟环境,以避免它们之间混合包。例如
我们将在下面的 项目环境部分 中重新讨论这个话题。
Requirements 文件
与他人共享项目时,预先声明您需要的所有包非常有用。pip
支持从文件安装 requirements,例如
请注意,上面的 fastapi
没有“锁定”到特定版本 —— 每个参与项目的人可能安装了不同版本的 fastapi
。创建 pip-tools
就是为了改善这种体验。
使用 pip-tools
时,requirements 文件既指定了项目的依赖项,也锁定了特定版本的依赖项 —— 文件扩展名用于区分两者。例如,如果您需要 fastapi
和 pydantic
,您需要在 requirements.in
文件中指定它们
请注意,pydantic
上有一个版本约束 —— 这意味着只能使用 pydantic
的 2.0.0
之后的版本。相比之下,fastapi
没有版本约束 —— 可以使用任何版本。
这些依赖项可以编译成 requirements.txt
文件
annotated-types==0.7.0
# via pydantic
anyio==4.8.0
# via starlette
fastapi==0.115.11
# via -r requirements.in
idna==3.10
# via anyio
pydantic==2.10.6
# via
# -r requirements.in
# fastapi
pydantic-core==2.27.2
# via pydantic
sniffio==1.3.1
# via anyio
starlette==0.46.1
# via fastapi
typing-extensions==4.12.2
# via
# fastapi
# pydantic
# pydantic-core
在这里,所有版本约束都是精确的。只能使用每个包的单个版本。上面的例子是用 uv pip compile
生成的,但也可以用 pip-tools
的 pip-compile
生成。
虽然不太常见,但也可以使用 pip freeze
生成 requirements.txt
,方法是首先将输入依赖项安装到环境中,然后导出已安装的版本
annotated-types==0.7.0
anyio==4.8.0
fastapi==0.115.11
idna==3.10
pydantic==2.10.6
pydantic-core==2.27.2
sniffio==1.3.1
starlette==0.46.1
typing-extensions==4.12.2
在将依赖项编译成一组锁定的版本后,这些文件将被提交到版本控制并随项目一起分发。
然后,当有人想要使用该项目时,他们将从 requirements 文件安装
开发依赖
requirements 文件格式一次只能描述一组依赖项。这意味着如果您有额外的依赖项组,例如开发依赖项,它们需要单独的文件。例如,我们将创建一个 -dev
依赖文件
请注意,基本 requirements 包含在 -r requirements.in
中。这确保了您的开发环境同时考虑所有依赖项。-c requirements.txt
约束包版本,以确保 requirements-dev.txt
使用与 requirements.txt
相同的版本。
注意
通常直接使用 -r requirements.txt
而不是同时使用 -r requirements.in
和 -c requirements.txt
。最终的包版本没有区别,但是同时使用这两个文件会产生注释,允许您确定哪些依赖项是直接的(用 -r requirements.in
注释),哪些是间接的(仅用 -c requirements.txt
注释)。
编译后的开发依赖项如下所示
annotated-types==0.7.0
# via
# -c requirements.txt
# pydantic
anyio==4.8.0
# via
# -c requirements.txt
# starlette
fastapi==0.115.11
# via
# -c requirements.txt
# -r requirements.in
idna==3.10
# via
# -c requirements.txt
# anyio
iniconfig==2.0.0
# via pytest
packaging==24.2
# via pytest
pluggy==1.5.0
# via pytest
pydantic==2.10.6
# via
# -c requirements.txt
# -r requirements.in
# fastapi
pydantic-core==2.27.2
# via
# -c requirements.txt
# pydantic
pytest==8.3.5
# via -r requirements-dev.in
sniffio==1.3.1
# via
# -c requirements.txt
# anyio
starlette==0.46.1
# via
# -c requirements.txt
# fastapi
typing-extensions==4.12.2
# via
# -c requirements.txt
# fastapi
# pydantic
# pydantic-core
与基本依赖文件一样,这些文件被提交到版本控制并随项目一起分发。当有人想在这个项目上工作时,他们将从 requirements 文件安装
平台特定依赖
当使用 pip
或 pip-tools
编译依赖项时,结果只能在生成它的同一平台上使用。这给需要在多个平台上(例如 Windows 和 macOS)使用的项目带来了问题。
例如,假设有一个简单的依赖
在 Linux 上,这编译为
而在 Windows 上,这编译为
colorama
是 tqdm
的一个 Windows 专用依赖项。
当使用 pip
和 pip-tools
时,一个项目需要为每个受支持的平台声明一个 requirements 锁定文件。
注意
uv 的解析器可以一次为多个平台编译依赖项(参见 “通用解析”),允许您为所有平台使用单个 requirements.txt
colorama==0.4.6 ; sys_platform == 'win32'
# via tqdm
tqdm==4.67.1
# via -r requirements.in
这种解析模式也用于使用 pyproject.toml
和 uv.lock
时。
迁移到 uv 项目
pyproject.toml
pyproject.toml
是 Python 项目元数据的标准化文件。它取代了 requirements.in
文件,允许您表示任意的项目依赖项组。它还为您的项目的元数据提供了一个中心位置,例如构建系统或工具设置。
例如,上面的 requirements.in
和 requirements-dev.in
文件可以转换为 pyproject.toml
,如下所示
[project]
name = "example"
version = "0.0.1"
dependencies = [
"fastapi",
"pydantic>2"
]
[dependency-groups]
dev = ["pytest"]
我们将在下面讨论自动导入这些所需的命令。
uv lockfile
uv 使用一个锁定文件(uv.lock
)来锁定包版本。此文件的格式是 uv 特有的,允许 uv 支持高级功能。它取代了 requirements.txt
文件。
锁定文件将在添加依赖项时自动创建和填充,但是您可以使用 uv lock
显式创建它。
与 requirements.txt
文件不同,uv.lock
文件可以表示任意的依赖项组,因此不需要多个文件来锁定开发依赖项。
uv 锁定文件始终是 通用的,因此不需要多个文件来为 每个平台锁定依赖项。这确保了所有开发人员都使用一致的、锁定的依赖项版本,而不管他们的机器如何。
uv 锁定文件还支持诸如 将包固定到特定索引 之类的概念,这在 requirements.txt
文件中是无法表示的。
提示
如果您只需要锁定平台的一个子集,请使用 tool.uv.environments
设置来限制解析和锁定文件。
要了解更多信息,请参阅 锁定文件 文档。
导入 requirements 文件
首先,如果您还没有 pyproject.toml
,请创建一个
然后,导入 requirements 的最简单方法是使用 uv add
但是,这种转换有一些细微之处。请注意,我们使用了 requirements.in
文件,该文件没有固定到包的精确版本,因此 uv 将解决这些包的新版本。您可能希望继续使用 requirements.txt
中以前锁定的版本,因此,在切换到 uv 时,您的任何依赖项版本都不会更改。
解决方案是将您锁定的版本添加为约束。uv 支持在 add
上使用这些约束来保留锁定的版本
在生成 uv.lock
文件时,您现有的版本将被保留。
导入平台特定约束
如果您的平台特定依赖项已编译成单独的文件,您仍然可以过渡到通用锁定文件。但是,您不能只使用 -c
来指定来自您现有的平台特定 requirements.txt
文件的约束,因为它们不包括描述环境的标记,因此会发生冲突。
要添加必要的标记,请使用 uv pip compile
转换您现有的文件。例如,给定以下内容
可以使用以下命令添加标记
$ uv pip compile requirements.in -o requirements-win.txt --python-platform windows --no-strip-markers
请注意,生成的输出在 colorama
上包含一个 Windows 标记
colorama==0.4.6 ; sys_platform == 'win32'
# via tqdm
tqdm==4.67.1
# via -r requirements.in
当使用 -o
时,uv 将约束版本以匹配现有的输出文件(如果可以)。
可以通过更改每个需要导入的 requirements 文件的 --python-platform
和 -o
值来为其他平台添加标记,例如,更改为 linux
和 macos
。
一旦每个 requirements.txt
文件都被转换,依赖项就可以使用 uv add
导入到 pyproject.toml
和 uv.lock
导入开发依赖文件
如 开发依赖项 部分所述,通常有用于开发目的的依赖项组。
要导入开发依赖项,请在 uv add
期间使用 --dev
标志
如果 requirements-dev.in
通过 -r
包含父 requirements.in
,则需要将其剥离以避免将基本 requirements 添加到 dev
依赖项组。以下示例使用 sed
剥离以 -r
开头的行,然后将结果通过管道传递给 uv add
除了 dev
依赖项组之外,uv 还支持任意组名称。例如,如果您还有一个用于构建文档的专用依赖项集,则可以将这些依赖项导入到 docs
组
项目环境
与 pip
不同,uv 不以“活动”虚拟环境的概念为中心。相反,uv 为 .venv
目录中的每个项目使用专用的虚拟环境。此环境是自动管理的,因此当您运行命令(如 uv add
)时,该环境将与项目依赖项同步。
在环境中执行命令的首选方法是使用 uv run
,例如
在每次 uv run
调用之前,uv 将验证锁定文件是否与 pyproject.toml
保持最新,并且环境是否与锁定文件保持最新,使您的项目保持同步,而无需手动干预。uv run
保证您的命令在一致的、锁定的环境中运行。
也可以使用 uv sync
显式创建项目环境,例如,用于编辑器。
注意
在项目中,uv 默认情况下将首选项目目录中的 .venv
并忽略由 VIRTUAL_ENV
变量声明的活动环境。您可以使用 --active
标志选择使用活动环境。
要了解更多信息,请参阅 项目环境 文档。
下一步
现在您已经迁移到 uv,请查看 项目概念 页面,以获取有关 uv 项目的更多详细信息。