跳转至

配置项目

Python 版本要求

项目可以在 pyproject.tomlproject.requires-python 字段中声明项目支持的 Python 版本。 建议设置 requires-python 值:

pyproject.toml
[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.12"
Python 版本要求决定了项目中允许使用的 Python 语法,并影响依赖版本的选择(它们必须支持相同的 Python 版本范围)。

入口点

入口点 是已安装包用于公布接口的正式术语。其中包括: - 命令行接口 - 图形用户界面 - 插件入口点

Important

使用入口点表需要定义 构建系统

命令行接口

项目可以在 pyproject.toml[project.scripts] 表中为项目定义命令行接口(CLI)。 例如,要声明一个名为 hello 的命令,该命令调用 example 模块中的 hello 函数:

pyproject.toml
[project.scripts]
hello = "example:hello"
然后,可以从控制台运行该命令:
$ uv run hello

图形用户界面

项目可以在 pyproject.toml[project.gui-scripts] 表中为项目定义图形用户界面(Graphical User Interface,GUI)。

Important

这些仅在 Windows 上与命令行界面有所不同,在 Windows 上它们由 GUI 可执行文件包装,因此无需控制台即可启动。在其他平台上,它们的行为相同。

例如,要声明一个名为 hello 的命令,该命令调用 example 模块中的 app 函数:

pyproject.toml
[project.gui-scripts]
hello = "example:app"

插件入口点

项目可以在 pyproject.toml[project.entry-points] 表中定义用于插件发现的入口点。

例如,要将 example-plugin-a 包注册为 example 的插件:

pyproject.toml
[project.entry-points.'example.plugins']
a = "example_plugin_a"

然后,在 example 中,将使用以下方式加载插件:

example/__init__.py
from importlib.metadata import entry_points

for plugin in entry_points(group='example.plugins'):
    plugin.load()

Note

group 键可以是任意值,无需包含包名或 “plugins”。不过,建议通过包名对该键进行命名空间划分,以避免与其他包发生冲突。

构建系统

构建系统决定了项目应如何打包和安装。项目可以在 pyproject.toml[build-system] 表中声明并配置构建系统。

uv 通过判断是否存在构建系统,来确定项目是否包含应安装在项目虚拟环境中的包。如果未定义构建系统,uv 将不会尝试构建或安装项目本身,仅安装其依赖项。如果定义了构建系统,uv 将构建项目并将其安装到项目环境中。

可以在 uv init 中使用 --build-backend 选项,来创建具有适当布局的打包项目。也可以在 uv init 中使用 --package 选项,来创建具有默认构建系统的打包项目。

注意

虽然没有构建系统定义时,uv 不会构建和安装当前项目,但其他包并不一定需要存在 [build-system] 表。由于历史原因,如果未定义构建系统,则会使用 setuptools.build_meta:__legacy__ 来构建包。你所依赖的包可能不会显式声明其构建系统,但仍然可以安装。同样,如果你添加了对本地包的依赖,或使用 uv pip 安装它,uv 总会尝试构建并安装它。

构建系统选项

构建系统用于支持以下功能: - 在发行版中包含或排除文件 - 可编辑安装行为 - 动态项目元数据 - 本地代码编译 - 共享库嵌入

要配置这些功能,请参考你所选构建系统的文档。

项目打包

正如在构建系统中所讨论的,Python 项目必须经过构建才能安装。这个过程通常被称为 “打包”。

如果你想实现以下功能,可能就需要一个包: - 为项目添加命令 - 将项目分发给其他人 - 使用 srctest 布局 - 编写一个库

如果你属于以下情况,可能不需要一个包: - 编写脚本 - 构建一个简单的应用程序 - 使用平铺布局

虽然 uv 通常会根据构建系统的声明来确定是否应该对项目进行打包,但 uv 也允许使用tool.uv.package 设置来覆盖此行为。

设置 tool.uv.package = true 将强制构建项目并将其安装到项目环境中。如果未定义构建系统,uv 将使用 setuptools 旧版后端。

设置 tool.uv.package = false 将强制项目包构建和安装到项目环境中。uv 在与项目交互时将忽略已声明的构建系统;但是,uv 仍会响应显式构建项目的操作,例如调用 uv build

项目环境路径

UV_PROJECT_ENVIRONMENT 环境变量可用于配置项目虚拟环境路径(默认值为 .venv)。

如果提供的是相对路径,它将相对于工作区根目录进行解析。如果提供的是绝对路径,将直接使用该路径,即不会为环境创建子目录。如果指定路径下不存在环境,uv 将创建该环境。

此选项可用于写入系统 Python 环境,但不建议这样做。默认情况下,uv sync 会从环境中移除无关的软件包,因此可能会使系统处于损坏状态。

要以系统环境为目标,将 UV_PROJECT_ENVIRONMENT 设置为 Python 安装的前缀。例如,在基于 Debian 的系统上,通常是 /usr/local

$ python -c "import sysconfig; print(sysconfig.get_config_var('prefix'))"
/usr/local

要以该环境为目标,你需要导出 UV_PROJECT_ENVIRONMENT=/usr/local

重要

如果提供了绝对路径,并且该设置在多个项目中使用,每个项目的调用都会覆盖该环境。此设置仅建议在 CI 或 Docker 镜像中的单个项目中使用。

注意

默认情况下,uv 在项目操作期间不会读取 VIRTUAL_ENV 环境变量。如果 VIRTUAL_ENV 设置为与项目环境不同的路径,将显示警告。可以使用 --active 标志选择遵循 VIRTUAL_ENV。可以使用 --no-active 标志来消除警告。

有限解析环境

如果您的项目仅支持有限的平台或 Python 版本集,您可以通过 environments 设置来限制解析的平台集,该设置接受 PEP 508 环境标记列表。例如,将锁定文件限制在 macOS 和 Linux 平台,并排除 Windows:

pyproject.toml
[tool.uv]
environments = [
    "sys_platform == 'darwin'",
    "sys_platform == 'linux'",
]

更多信息请参阅 解析文档

必需环境

如果您的项目 必须 支持特定平台或 Python 版本,您可以通过 required-environments 设置将该平台标记为必需。例如,要求项目支持英特尔架构的 macOS:

pyproject.toml
[tool.uv]
required-environments = [
    "sys_platform == 'darwin' and platform_machine == 'x86_64'",
]

required-environments 设置仅适用于未发布源发行版的软件包(如 PyTorch),因为此类软件包 只能 安装在该软件包发布的预构建二进制发行版(wheel)所涵盖的环境中。

更多信息请参阅 解析文档

构建隔离

默认情况下,uv 会按照 PEP 517 在隔离的虚拟环境中构建所有软件包。有些软件包与构建隔离不兼容,这可能是有意为之(例如,由于使用了重量级的构建依赖项,最常见的是 PyTorch),也可能是无意的(例如,由于使用了旧版打包设置)。

要为特定依赖项禁用构建隔离,请将其添加到 pyproject.toml 中的 no-build-isolation-package 列表中:

pyproject.toml
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["cchardet"]

[tool.uv]
no-build-isolation-package = ["cchardet"]
在没有构建隔离的情况下安装软件包,要求在安装软件包本身之前,先在项目环境中安装该软件包的构建依赖项。这可以通过将构建依赖项和需要它们的软件包分离到不同的额外项中来实现。例如:
pyproject.toml
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[project.optional-dependencies]
build = ["setuptools", "cython"]
compile = ["cchardet"]

[tool.uv]
no-build-isolation-package = ["cchardet"]
基于上述配置,用户首先要同步 build 依赖项:
$ uv sync --extra build
 + cython==3.0.11
 + foo==0.1.0 (from file:///Users/crmarsh/workspace/uv/foo)
 + setuptools==73.0.1
然后同步 compile 依赖项:
$ uv sync --extra compile
 + cchardet==2.1.7
 - cython==3.0.11
 - setuptools==73.0.1
请注意,默认情况下,uv sync --extra compile 会卸载 cythonsetuptools 软件包。若要保留构建依赖项,可以在第二次调用 uv sync 时包含两个额外项:
$ uv sync --extra build
$ uv sync --extra build --extra compile
有些软件包,如上述的 cchardet,仅在 uv sync安装 阶段需要构建依赖项。而其他软件包,如 flash-attn,即使在 解析 阶段解析项目的锁定文件时,也需要其构建依赖项存在。

在这种情况下,必须在运行任何 uv lockuv sync 命令之前,使用较低级别的 uv pip API 安装构建依赖项。例如,给定:

pyproject.toml
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["flash-attn"]

[tool.uv]
no-build-isolation-package = ["flash-attn"]
你可以运行以下命令序列来同步 flash-attn
$ uv venv
$ uv pip install torch setuptools
$ uv sync
或者,你可以通过dependency-metadata 设置预先提供 flash-attn 元数据,从而无需在依赖项解析阶段构建该软件包。例如,要预先提供 flash-attn 元数据,在 pyproject.toml 中包含以下内容:
pyproject.toml
[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]

Tip

要确定像 flash-attn 这样的软件包的元数据,可以导航到相应的 Git 仓库,或者在 PyPI 上查找并下载该软件包的源发行版。软件包的需求通常可以在 setup.pysetup.cfg 文件中找到。

(如果软件包包含已构建的发行版,你可以解压它以找到 METADATA 文件;但是,已构建发行版的存在将消除预先提供元数据的必要性,因为 uv 已经可以获取到它。)

包含元数据后,你可以再次使用两步 uv sync 过程来安装构建依赖项。给定以下 pyproject.toml

pyproject.toml
[project]
name = "project"
version = "0.1.0"
description = "..."
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[project.optional-dependencies]
build = ["torch", "setuptools", "packaging"]
compile = ["flash-attn"]

[tool.uv]
no-build-isolation-package = ["flash-attn"]

[[tool.uv.dependency-metadata]]
name = "flash-attn"
version = "2.6.3"
requires-dist = ["torch", "einops"]
你可以运行以下命令序列来同步 flash-attn
$ uv sync --extra build
$ uv sync --extra build --extra compile

Note

tool.uv.dependency-metadata 中的 version 字段对于基于注册表的依赖项是可选的(省略时,uv 将假定元数据适用于该软件包的所有版本),但对于直接 URL 依赖项(如 Git 依赖项)是 必需的

可编辑模式

默认情况下,项目将以可编辑模式安装,这样对源代码的更改会立即反映在环境中。uv syncuv run 都接受 --no-editable 标志,该标志指示 uv 以非可编辑模式安装项目。--no-editable 适用于部署场景,例如构建 Docker 容器,在这种场景下,项目应包含在已部署的环境中,而不依赖于原始源代码。

冲突的依赖项

uv 要求项目声明的所有可选依赖项(“额外项”)相互兼容,并在创建锁定文件时一并解析所有可选依赖项。

如果一个额外项中声明的可选依赖项与另一个额外项中的不兼容,uv 将无法解析项目需求并报错。

为解决此问题,uv 支持声明冲突的额外项。例如,假设有两组相互冲突的可选依赖项:

pyproject.toml
[project.optional-dependencies]
extra1 = ["numpy==2.1.2"]
extra2 = ["numpy==2.0.0"]

如果使用上述依赖项运行 uv lock,解析将失败:

$ uv lock
  x 解析依赖项时未找到解决方案:
  `-> 因为 myproject[extra2] 依赖 numpy==2.0.0,而 myproject[extra1] 依赖 numpy==2.1.2,所以我们可以得出结论,myproject[extra1] 和
      myproject[extra2] 不兼容。
      又因为您的项目需要 myproject[extra1] 和 myproject[extra2],所以我们可以得出结论,您项目的需求无法满足。

但是,如果指定 extra1extra2 冲突,uv 将分别解析它们。在 tool.uv 部分指定冲突:

pyproject.toml
[tool.uv]
conflicts = [
    [
      { extra = "extra1" },
      { extra = "extra2" },
    ],
]

现在,运行 uv lock 将成功。不过请注意,现在不能同时安装 extra1extra2

$ uv sync --extra extra1 --extra extra2
在 14 毫秒内解析了 3 个包
错误:额外项 `extra1`、额外项 `extra2` 与声明的冲突项 {`myproject[extra1]`, `myproject[extra2]`} 不兼容

出现此错误是因为同时安装 extra1extra2 会导致将同一包的两个不同版本安装到同一环境中。

上述处理冲突额外项的策略同样适用于依赖组:

pyproject.toml
[dependency-groups]
group1 = ["numpy==2.1.2"]
group2 = ["numpy==2.0.0"]

[tool.uv]
conflicts = [
    [
      { group = "group1" },
      { group = "group2" },
    ],
]

与冲突额外项的唯一区别是,需要使用 group 而不是 extra