3.8 uv 构建后端

原文链接: https://docs.astral.sh/uv/concepts/build-backend/

3.8 uv 构建后端

构建后端把源码树(即一个目录)转换为源码分发或 wheel。

uv 支持所有构建后端(如 PEP 517 所规定),同时也提供了一个原生构建后端(uv_build),它与 uv 紧密集成以改善性能和用户体验。

选择构建后端

uv 构建后端对大多数 Python 项目来说都是很好的选择。它有合理的默认值,目标是对大多数用户实现零配置,同时提供灵活的配置以适配大多数 Python 项目结构。它与 uv 紧密集成,改善提示信息和用户体验。它会校验项目元数据和结构,防止常见错误。最后,它非常快。

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

提示

虽然该后端支持若干用于配置项目结构的选项,但当需要构建脚本或更灵活的项目布局时,可以考虑改用 hatchling 构建后端。

使用 uv 构建后端

要在已有项目中把 uv 用作构建后端,请把 uv_build 加入 pyproject.toml 的 [build-system] 段落:

1
2
3
4
# pyproject.toml
[build-system]
requires = ["uv_build>=0.12.19,<0.13"]
build-backend = "uv_build"

注意

uv 构建后端遵循与 uv 相同的版本策略。为 uv_build 版本设置上界可以确保你的包在发布新版本时仍能正确构建。

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

1
$ uv init

构建项目时(例如用 uv build),会使用 uv 构建后端创建源码分发和 wheel。

内置构建后端

构建后端作为单独的包(uv_build)发布,它针对可移植性和较小二进制体积做了优化。不过 uv 可执行文件中也包含一份构建后端副本;在 uv 执行构建期间(例如 uv build 期间),如果它的版本与 uv_build 要求兼容,就会使用这份副本。如果不兼容,则会使用兼容版本的 uv_build 包。其他构建前端(例如 python -m build)始终会使用 uv_build 包,通常选择最新的兼容版本。

模块

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

例如,名为 foo 的项目结构为:

1
2
3
4
pyproject.toml
src
└── foo
    └── __init__.py

uv 会规范化包名以确定默认模块名:包名转为小写,并把点和短横线替换为下划线,例如 Foo-Bar 会转换为 foo_bar。

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

这些默认值可以通过 module-name 和 module-root 设置更改。例如,要在根目录中使用 FOO 模块,项目结构为:

1
2
3
pyproject.toml
FOO
└── __init__.py

正确的构建配置应为:

1
2
3
4
# pyproject.toml
[tool.uv.build-backend]
module-name = "FOO"
module-root = ""

命名空间包

命名空间包适用于多个包把模块写入共享命名空间的场景。

命名空间包模块通过 module-name 中的 . 标识。例如,要把模块 bar 打包进共享命名空间 foo,项目结构为:

1
2
3
4
5
pyproject.toml
src
└── foo
    └── bar
        └── __init__.py

而 module-name 配置为:

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

重要

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

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

1
2
3
4
5
6
pyproject.toml
src
├── foo
│   └── __init__.py
└── bar
    └── __init__.py

虽然我们不推荐这种结构(即你应改用包含多个包的工作区),但可以通过把 module-name 设置为名称列表来支持它:

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

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

1
2
3
# pyproject.toml
[tool.uv.build-backend]
namespace = true

警告

使用 namespace = true 会禁用安全检查。除遗留项目外,强烈建议使用显式的模块名列表。

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

1
2
3
4
5
6
7
pyproject.toml
src
└── foo
    ├── bar
    │   └── __init__.py
    └── baz
        └── __init__.py

推荐的配置为:

1
2
3
4
# pyproject.toml
[tool.uv.build-backend]
module-name = "foo"
namespace = true

存根包

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

1
2
3
4
pyproject.toml
src
└── foo-stubs
    └── __init__.pyi

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

文件包含与排除

构建后端负责确定源码树中哪些文件应被打包进分发包。

为确定源码分发中要包含哪些文件,uv 先添加被包含的文件和目录,然后移除被排除的文件和目录。这意味着排除始终优先于包含。

默认情况下,uv 排除 __pycache__、*.pyc 和 *.pyo。

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

  • pyproject.toml。如果 uv 检测到仅 TOML 1.1 支持的语法,会发出警告并自动启用 toml-backwards-compatibility 预览特性:pyproject.toml 会被重新格式化以向后兼容,原始文件保留为 pyproject.toml.orig。传入 --preview-feature toml-backwards-compatibility 可显式启用该特性并消除警告。
  • tool.uv.build-backend.module-root 下的模块。
  • project.license-files 和 project.readme 引用的文件。
  • tool.uv.build-backend.data 下的所有目录。
  • 匹配 tool.uv.build-backend.source-include 中模式的所有文件。

之后会从中移除匹配 tool.uv.build-backend.source-exclude 和默认排除项的条目。

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

之后会从中移除 tool.uv.build-backend.source-exclude、tool.uv.build-backend.wheel-exclude 和默认排除项。应用源码分发排除项是为了避免“源码树到 wheel”的构建比“源码树到源码分发再到 wheel”的构建包含更多文件。

wheel 没有专门的包含项。只能有一个顶层模块,所有数据文件必须位于模块根下或相应的数据目录中。大多数包把小型数据与源代码一起存放在模块根中。

提示

当通过非 uv 的前端(例如 pip 或 python -m build)使用 uv 构建后端时,可以通过环境变量 RUST_LOG=uv=debug 或 RUST_LOG=uv=verbose 启用调试日志。通过 uv 使用时,uv 构建后端共享 uv 的详细程度级别。

包含与排除语法

包含项是锚定的,也就是说 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 语法,另外还支持用反斜杠转义字符。

最后修改 September 25, 2026: 更新 (221c74c33)