跳到内容

uv 构建后端

构建后端将源代码树(即目录)转换为源代码分发或 wheel 包。

uv 支持所有构建后端(如 PEP 517 所指定的),但也提供了一个原生构建后端 (uv_build),该后端与 uv 紧密集成,以提高性能和用户体验。

选择构建后端

uv 构建后端是大多数 Python 项目的绝佳选择。它具有合理的默认值,目标是让大多数用户无需配置,但提供灵活的配置以适应大多数 Python 项目结构。它与 uv 紧密集成,以改善消息传递和用户体验。它验证项目元数据和结构,防止常见错误。而且,它非常快。

uv 构建后端目前仅支持纯 Python 代码。构建带有扩展模块的库需要替代后端。

提示

虽然后端支持许多用于配置项目结构的选项,但当需要构建脚本或更灵活的项目布局时,请考虑使用 hatchling 构建后端。

使用 uv 构建后端

要在现有项目中使用 uv 作为构建后端,请将 uv_build 添加到 pyproject.toml 中的 [build-system] 部分

pyproject.toml
[build-system]
requires = ["uv_build>=0.8.0,<0.9.0"]
build-backend = "uv_build"

注意

uv 构建后端遵循与 uv 相同的 版本控制策略。包括 uv_build 版本的上限可确保您的软件包在新版本发布时继续正确构建。

要创建一个使用 uv 构建后端的新项目,请使用 uv init

$ uv init

构建项目时,例如使用 uv build,将使用 uv 构建后端来创建源代码分发和 wheel 包。

捆绑构建后端

构建后端作为单独的包 (uv_build) 发布,该包针对可移植性和小二进制大小进行了优化。但是,uv 可执行文件还包括构建后端的副本,如果其版本与 uv_build 要求兼容,则该副本将在 uv 执行的构建期间使用,例如,在 uv build 期间。如果不兼容,将使用 uv_build 包的兼容版本。其他构建前端,例如 python -m build,将始终使用 uv_build 包,通常选择最新的兼容版本。

模块

Python 包应包含一个或多个 Python 模块,这些模块是包含 __init__.py 的目录。默认情况下,预期在 src/<package_name>/__init__.py 处有一个根模块。

例如,名为 foo 的项目的结构将是

pyproject.toml
src
└── foo
    └── __init__.py

uv 会规范化包名称以确定默认模块名称:包名称转换为小写,点和破折号替换为下划线,例如,Foo-Bar 将转换为 foo_bar

src/ 目录是模块发现的默认目录。

可以使用 module-namemodule-root 设置更改这些默认值。例如,要在根目录中使用 FOO 模块,如项目结构中所示

pyproject.toml
FOO
└── __init__.py

正确的构建配置将是

pyproject.toml
[tool.uv.build-backend]
module-name = "FOO"
module-root = ""

命名空间包

命名空间包旨在用于多个包将模块写入共享命名空间的情况。

命名空间包模块由 module-name 中的 . 标识。例如,要在共享命名空间 foo 中打包模块 bar,项目结构将是

pyproject.toml
src
└── foo
    └── bar
        └── __init__.py

并且 module-name 配置将是

pyproject.toml
[tool.uv.build-backend]
module-name = "foo.bar"

重要

__init__.py 文件不包含在 foo 中,因为它是一个共享命名空间模块。

也可以有具有多个根模块的复杂命名空间包,例如,项目结构如下

pyproject.toml
src
├── foo
│   └── __init__.py
└── bar
    └── __init__.py

虽然我们不推荐这种结构(即,您应该使用具有多个包的工作区),但通过将 module-name 设置为名称列表来支持它

pyproject.toml
[tool.uv.build-backend]
module-name = ["foo", "bar"]

对于具有多个模块或复杂命名空间的包,可以使用 namespace = true 选项来避免显式声明每个模块名称,例如

pyproject.toml
[tool.uv.build-backend]
namespace = true

警告

使用 namespace = true 会禁用安全检查。强烈建议在传统项目之外使用显式模块名称列表。

namespace 选项也可以与 module-name 一起使用以显式声明根,例如,对于项目结构

pyproject.toml
src
└── foo
    ├── bar
    │   └── __init__.py
    └── baz
        └── __init__.py

建议的配置是

pyproject.toml
[tool.uv.build-backend]
module-name = "foo"
namespace = true

存根包

构建后端还支持构建类型存根包,这些包通过包或模块名称上的 -stubs 后缀来标识,例如 foo-stubs。类型存根包的模块名称必须以 -stubs 结尾,因此 uv 不会将 - 规范化为下划线。此外,uv 将搜索 __init__.pyi 文件。例如,项目结构将是

pyproject.toml
src
└── foo-stubs
    └── __init__.pyi

类型存根模块也支持命名空间包

文件包含和排除

构建后端负责确定应将源树中的哪些文件打包到分发包中。

要确定要包含在源代码分发包中的文件,uv 首先添加包含的文件和目录,然后删除排除的文件和目录。这意味着排除始终优先于包含。

默认情况下,uv 会排除 __pycache__*.pyc*.pyo

构建源代码分发包时,包含以下文件和目录

从这些文件中,将删除匹配 tool.uv.build-backend.source-exclude默认排除项的项目。

构建 wheel 包时,包含以下文件和目录

从这些文件中,删除 tool.uv.build-backend.source-excludetool.uv.build-backend.wheel-exclude 和默认排除项。应用源代码分发排除项是为了避免从源代码树到 wheel 包的源构建包含比从源代码树到源代码分发包到 wheel 包的构建更多的文件。

没有特定的 wheel 包含项。必须只有一个顶级模块,并且所有数据文件必须位于模块根目录下或在相应的数据目录中。大多数包将少量数据存储在模块根目录中,与源代码一起。

包含和排除语法

包含是锚定的,这意味着 pyproject.toml 仅包含 <root>/pyproject.toml,而不包含 <root>/bar/pyproject.toml。要递归包含目录下的所有文件,请使用 /** 后缀,例如 src/**。递归包含也是锚定的,例如,assets/**/sample.csv 包含 <root>/assets 或其任何子级中的所有 sample.csv 文件。

注意

为了性能和可重现性,请避免使用没有锚点的模式,例如 **/sample.csv

排除项未锚定,这意味着 __pycache__ 排除所有名为 __pycache__ 的目录,而与其父目录无关。排除项的所有子项也被排除。要锚定目录,请使用 / 前缀,例如,/dist 将仅排除 <root>/dist

所有接受模式的字段都使用来自 PEP 639 的缩减的便携式 glob 语法,并添加了可以使用反斜杠转义字符。