uv 构建后端
构建后端将源代码树(即目录)转换为源代码分发包(sdist)或轮子文件(wheel)。
uv 支持所有构建后端(遵循 PEP 517 标准),同时也提供了一个原生构建后端 (uv_build)。它与 uv 深度集成,旨在提升性能和用户体验。
选择构建后端
uv 构建后端对于大多数 Python 项目来说都是一个极佳的选择。它提供了合理的默认配置,目标是让大多数用户无需进行任何配置;同时也提供了灵活的配置选项,以适配各种 Python 项目结构。它与 uv 紧密集成,以优化提示信息和用户体验。它会对项目元数据和结构进行校验,防止常见的错误。最重要的是,它的构建速度非常快。
uv 构建后端目前仅支持纯 Python 代码。如需构建包含扩展模块的库,则需要使用其他后端。
提示
虽然该后端支持多种选项来配置项目结构,但在需要构建脚本或更灵活的项目布局时,请考虑改用 hatchling 构建后端。
使用 uv 构建后端
要在现有项目中使用 uv 作为构建后端,请将 uv_build 添加到 pyproject.toml 中的 [build-system] 部分:
注意
uv 构建后端遵循与 uv 相同的版本策略。为 uv_build 设置上限版本号,可确保您的软件包在发布新版本时仍能正确构建。
要创建一个使用 uv 构建后端的新项目,请使用 uv init。
当构建项目时(例如使用 uv build),uv 构建后端将被用于创建源代码分发包和轮子文件。
内置构建后端
该构建后端作为一个独立的包 (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 的项目结构如下:
uv 会对包名进行标准化处理以确定默认模块名:将包名转换为小写,并将点号和连字符替换为下划线。例如,Foo-Bar 将被转换为 foo_bar。
src/ 目录是进行模块发现的默认目录。
这些默认值可以通过 module-name 和 module-root 设置进行更改。例如,若要使用根目录下的 FOO 模块,项目结构如下:
正确的构建配置应为:
命名空间包
命名空间包(Namespace packages)旨在用于多个包将模块写入共享命名空间的场景。
命名空间包模块通过 module-name 中的 . 来标识。例如,若要在共享命名空间 foo 中打包模块 bar,项目结构如下:
相应的 module-name 配置为:
重要
foo 中不包含 __init__.py 文件,因为它是一个共享命名空间模块。
也可以拥有包含多个根模块的复杂命名空间包,例如以下项目结构:
虽然我们不推荐这种结构(即你应该改为使用包含多个包的工作区),但可以通过将 module-name 设置为名称列表来支持它:
对于拥有许多模块或复杂命名空间的包,可以使用 namespace = true 选项来避免显式声明每个模块名称,例如:
警告
使用 namespace = true 会禁用安全检查。除非是遗留项目,否则强烈建议使用显式的模块名称列表。
namespace 选项也可以与 module-name 结合使用来显式声明根目录,例如针对以下项目结构:
推荐的配置如下:
存根(Stub)包
构建后端还支持构建类型存根(type stub)包,其标识方式是在包名或模块名后添加 -stubs 后缀,例如 foo-stubs。类型存根包的模块名必须以 -stubs 结尾,因此 uv 不会将 - 标准化为下划线。此外,uv 会查找 __init__.pyi 文件。例如,项目结构如下:
类型存根模块同样支持命名空间包。
文件包含与排除
构建后端负责确定源代码树中的哪些文件应被打包到分发文件中。
为了确定在源代码分发包中包含哪些文件,uv 首先添加包含的文件和目录,然后移除排除的文件和目录。这意味着排除规则始终优先于包含规则。
默认情况下,uv 会排除 __pycache__、*.pyc 和 *.pyo。
构建源代码分发包时,会包含以下文件和目录:
pyproject.tomltool.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 和默认排除项的项目。
构建轮子文件时,会包含以下文件和目录:
tool.uv.build-backend.module-root下的模块。project.license-files引用的文件,这些文件会被复制到.dist-info目录中。project.readme,它会被复制到项目元数据中。tool.uv.build-backend.data下的所有目录,这些目录会被复制到.data目录中。
从这些项目中,会移除 tool.uv.build-backend.source-exclude、tool.uv.build-backend.wheel-exclude 以及默认排除项。应用源代码分发包的排除项是为了防止“源代码树到轮子”的构建过程比“源代码树到源代码分发包再到轮子”的构建过程包含更多文件。
没有特定的轮子包含规则。必须只有一个顶层模块,且所有数据文件必须位于模块根目录下或相应的数据目录中。大多数包将小数据存储在模块根目录下的源代码旁边。
提示
当通过非 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 语法,并增加了可以使用反斜杠转义字符的功能。