3.8 uv 构建后端
5 分钟阅读
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] 段落:
| |
注意
uv 构建后端遵循与 uv 相同的版本策略。为
uv_build版本设置上界可以确保你的包在发布新版本时仍能正确构建。
要创建使用 uv 构建后端的新项目,请使用 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 的项目结构为:
| |
uv 会规范化包名以确定默认模块名:包名转为小写,并把点和短横线替换为下划线,例如 Foo-Bar 会转换为 foo_bar。
src/ 目录是模块发现的默认目录。
这些默认值可以通过 module-name 和 module-root 设置更改。例如,要在根目录中使用 FOO 模块,项目结构为:
| |
正确的构建配置应为:
| |
命名空间包
命名空间包适用于多个包把模块写入共享命名空间的场景。
命名空间包模块通过 module-name 中的 . 标识。例如,要把模块 bar 打包进共享命名空间 foo,项目结构为:
| |
而 module-name 配置为:
| |
重要
foo中不包含__init__.py文件,因为它是共享命名空间模块。
也可以有包含多个根模块的复杂命名空间包,例如项目结构为:
| |
虽然我们不推荐这种结构(即你应改用包含多个包的工作区),但可以通过把 module-name 设置为名称列表来支持它:
| |
对于模块数量很多或命名空间复杂的包,可以使用 namespace = true 选项来避免显式声明每个模块名,例如:
| |
警告
使用
namespace = true会禁用安全检查。除遗留项目外,强烈建议使用显式的模块名列表。
namespace 选项也可以与 module-name 一起使用以显式声明根,例如项目结构为:
| |
推荐的配置为:
| |
存根包
该构建后端也支持构建类型存根包,它们通过包名或模块名上的 -stubs 后缀标识,例如 foo-stubs。类型存根包的模块名必须以 -stubs 结尾,因此 uv 不会把 - 规范化为下划线。此外,uv 会搜索 __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.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 和默认排除项。应用源码分发排除项是为了避免“源码树到 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 语法,另外还支持用反斜杠转义字符。