Skip to content

Commit b1812d1

Browse files
zaniebkonstin
andauthored
Edits to the build backend documentation (#14376)
Co-authored-by: konstin <[email protected]>
1 parent a3db9a9 commit b1812d1

File tree

1 file changed

+149
-59
lines changed

1 file changed

+149
-59
lines changed

docs/concepts/build-backend.md

Lines changed: 149 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,119 +7,209 @@
77
When preview mode is not enabled, uv uses [hatchling](https://pypi.org/project/hatchling/) as the default build backend.
88

99
A build backend transforms a source tree (i.e., a directory) into a source distribution or a wheel.
10-
While uv supports all build backends (as specified by PEP 517), it includes a `uv_build` backend
11-
that integrates tightly with uv to improve performance and user experience.
1210

13-
The uv build backend currently only supports Python code. An alternative backend is required if you
14-
want to create a
15-
[library with extension modules](../concepts/projects/init.md#projects-with-extension-modules).
11+
uv supports all build backends (as specified by [PEP 517](https://peps.python.org/pep-0517/)), but
12+
also provides a native build backend (`uv_build`) that integrates tightly with uv to improve
13+
performance and user experience.
1614

17-
To use the uv build backend as [build system](../concepts/projects/config.md#build-systems) in an
18-
existing project, add it to the `[build-system]` section in your `pyproject.toml`:
15+
## Using the uv build backend
1916

20-
```toml
17+
!!! important
18+
19+
The uv build backend currently **only supports pure Python code**. An alternative backend is to
20+
build a [library with extension modules](../concepts/projects/init.md#projects-with-extension-modules).
21+
22+
To use uv as a build backend in an existing project, add `uv_build` to the
23+
[`[build-system]`](../concepts/projects/config.md#build-systems) section in your `pyproject.toml`:
24+
25+
```toml title="pyproject.toml"
2126
[build-system]
2227
requires = ["uv_build>=0.7.17,<0.8.0"]
2328
build-backend = "uv_build"
2429
```
2530

26-
!!! important
31+
!!! note
2732

28-
The uv build backend follows the same [versioning policy](../reference/policies/versioning.md),
29-
setting an upper bound on the `uv_build` version ensures that the package continues to build in
30-
the future.
33+
The uv build backend follows the same [versioning policy](../reference/policies/versioning.md)
34+
as uv. Including an upper bound on the `uv_build` version ensures that your package continues to
35+
build correctly as new versions are released.
3136

32-
You can also create a new project that uses the uv build backend with `uv init`:
37+
To create a new project that uses the uv build backend, use `uv init`:
3338

34-
```shell
35-
uv init --build-backend uv
39+
```console
40+
$ uv init --build-backend uv
3641
```
3742

38-
`uv_build` is a separate package from uv, optimized for portability and small binary size. The `uv`
39-
command includes a copy of the build backend, so when running `uv build`, the same version will be
40-
used for the build backend as for the uv process. Other build frontends, such as `python -m build`,
41-
will choose the latest compatible `uv_build` version.
43+
When the project is built, e.g., with [`uv build`](../guides/package.md), the uv build backend will
44+
be used to create the source distribution and wheel.
45+
46+
## Bundled build backend
47+
48+
The build backend is published as a separate package (`uv_build`) that is optimized for portability
49+
and small binary size. However, the `uv` executable also includes a copy of the build backend, which
50+
will be used during builds performed by uv, e.g., during `uv build`, if its version is compatible
51+
with the `uv_build` requirement. If it's not compatible, a compatible version of the `uv_build`
52+
package will be used. Other build frontends, such as `python -m build`, will always use the
53+
`uv_build` package, typically choosing the latest compatible version.
4254

4355
## Modules
4456

45-
The default module name is the package name in lower case with dots and dashes replaced by
46-
underscores, and the default module location is under the `src` directory, i.e., the build backend
47-
expects to find `src/<package_name>/__init__.py`. These defaults can be changed with the
48-
`module-name` and `module-root` setting. The example below expects a module in the project root with
49-
`PIL/__init__.py` instead:
57+
Python packages are expected to contain one or more Python modules, which are directories containing
58+
an `__init__.py`. By default, a single root module is expected at `src/<package_name>/__init__.py`.
59+
60+
For example, the structure for a project named `foo` would be:
61+
62+
```text
63+
pyproject.toml
64+
src
65+
└── foo
66+
└── __init__.py
67+
```
68+
69+
uv normalizes the package name to determine the default module name: the package name is lowercased
70+
and dots and dashes are replaced with underscores, e.g., `Foo-Bar` would be converted to `foo_bar`.
71+
72+
The `src/` directory is the default directory for module discovery.
73+
74+
These defaults can be changed with the `module-name` and `module-root` settings. For example, to use
75+
a `FOO` module in the root directory, as in the project structure:
76+
77+
```text
78+
pyproject.toml
79+
FOO
80+
└── __init__.py
81+
```
82+
83+
The correct build configuration would be:
5084

51-
```toml
85+
```toml title="pyproject.toml"
5286
[tool.uv.build-backend]
53-
module-name = "PIL"
87+
module-name = "FOO"
5488
module-root = ""
5589
```
5690

57-
For a namespace packages, the path can be dotted. The example below expects to find a
58-
`src/cloud/db/schema/__init__.py`:
91+
## Namespace packages
5992

60-
```toml
93+
Namespace packages are intended for use-cases where multiple packages write modules into a shared
94+
namespace.
95+
96+
Namespace package modules are identified by a `.` in the `module-name`. For example, to package the
97+
module `bar` in the shared namespace `foo`, the project structure would be:
98+
99+
```text
100+
pyproject.toml
101+
src
102+
└── foo
103+
└── bar
104+
└── __init__.py
105+
```
106+
107+
And the `module-name` configuration would be:
108+
109+
```toml title="pyproject.toml"
61110
[tool.uv.build-backend]
62-
module-name = "cloud.db.schema"
111+
module-name = "foo.bar"
63112
```
64113

65-
Complex namespaces with more than one root module can be built by setting the `namespace` option,
66-
which allows more than one root `__init__.py`:
114+
!!! important
115+
116+
The `__init__.py` file is not included in `foo`, since it's the shared namespace module.
67117

68-
```toml
118+
It's also possible to have a complex namespace package with more than one root module, e.g., with
119+
the project structure:
120+
121+
```text
122+
pyproject.toml
123+
src
124+
├── foo
125+
│   └── __init__.py
126+
└── bar
127+
└── __init__.py
128+
```
129+
130+
While we do not recommend this structure (i.e., you should use a workspace with multiple packages
131+
instead), it is supported via the `namespace` option:
132+
133+
```toml title="pyproject.toml"
69134
[tool.uv.build-backend]
70135
namespace = true
71136
```
72137

73-
The build backend supports building stubs packages with a `-stubs` suffix on the package or module
74-
name, including for namespace packages.
138+
## Stub packages
139+
140+
The build backend also supports building type stub packages, which are identified by the `-stubs`
141+
suffix on the package or module name, e.g., `foo-stubs`. The module name for type stub packages must
142+
end in `-stubs`, so uv will not normalize the `-` to an underscore. Additionally, uv will search for
143+
a `__init__.pyi` file. For example, the project structure would be:
144+
145+
```text
146+
pyproject.toml
147+
src
148+
└── foo-stubs
149+
└── __init__.pyi
150+
```
151+
152+
Type stub modules are also supported for [namespace packages](#namespace-packages).
75153

76-
## Include and exclude configuration
154+
## File inclusion and exclusion
77155

78-
To select which files to include in the source distribution, uv first adds the included files and
156+
The build backend is responsible for determining which files in a source tree should be packaged
157+
into the distributions.
158+
159+
To determine which files to include in a source distribution, uv first adds the included files and
79160
directories, then removes the excluded files and directories. This means that exclusions always take
80161
precedence over inclusions.
81162

82-
When building the source distribution, the following files and directories are included:
163+
By default, uv excludes `__pycache__`, `*.pyc`, and `*.pyo`.
164+
165+
When building a source distribution, the following files and directories are included:
83166

84-
- `pyproject.toml`
85-
- The module under `tool.uv.build-backend.module-root`, by default
86-
`src/<module-name or project_name_with_underscores>/**`.
87-
- `project.license-files` and `project.readme`.
88-
- All directories under `tool.uv.build-backend.data`.
89-
- All patterns from `tool.uv.build-backend.source-include`.
167+
- The `pyproject.toml`
168+
- The [module](#modules) under
169+
[`tool.uv.build-backend.module-root`](../reference/settings.md#build-backend_module-root).
170+
- The files referenced by `project.license-files` and `project.readme`.
171+
- All directories under [`tool.uv.build-backend.data`](../reference/settings.md#build-backend_data).
172+
- All files matching patterns from
173+
[`tool.uv.build-backend.source-include`](../reference/settings.md#build-backend_source-include).
90174

91-
From these, `tool.uv.build-backend.source-exclude` and the default excludes are removed.
175+
From these, items matching
176+
[`tool.uv.build-backend.source-exclude`](../reference/settings.md#build-backend_source-exclude) and
177+
the [default excludes](../reference/settings.md#build-backend_default-excludes) are removed.
92178

93-
When building the wheel, the following files and directories are included:
179+
When building a wheel, the following files and directories are included:
94180

95-
- The module under `tool.uv.build-backend.module-root`, by default
96-
`src/<module-name or project_name_with_underscores>/**`.
97-
- `project.license-files` and `project.readme`, as part of the project metadata.
98-
- Each directory under `tool.uv.build-backend.data`, as data directories.
181+
- The [module](#modules) under
182+
[`tool.uv.build-backend.module-root`](../reference/settings.md#build-backend_module-root)
183+
- The files referenced by `project.license-files`, which are copied into the `.dist-info` directory.
184+
- The `project.readme`, which is copied into the project metadata.
185+
- All directories under [`tool.uv.build-backend.data`](../reference/settings.md#build-backend_data),
186+
which are copied into the `.data` directory.
99187

100-
From these, `tool.uv.build-backend.source-exclude`, `tool.uv.build-backend.wheel-exclude` and the
101-
default excludes are removed. The source dist excludes are applied to avoid source tree to wheel
188+
From these,
189+
[`tool.uv.build-backend.source-exclude`](../reference/settings.md#build-backend_source-exclude),
190+
[`tool.uv.build-backend.wheel-exclude`](../reference/settings.md#build-backend_wheel-exclude) and
191+
the default excludes are removed. The source dist excludes are applied to avoid source tree to wheel
102192
source builds including more files than source tree to source distribution to wheel build.
103193

104194
There are no specific wheel includes. There must only be one top level module, and all data files
105195
must either be under the module root or in the appropriate
106196
[data directory](../reference/settings.md#build-backend_data). Most packages store small data in the
107197
module root alongside the source code.
108198

109-
## Include and exclude syntax
199+
### Include and exclude syntax
110200

111-
Includes are anchored, which means that `pyproject.toml` includes only
112-
`<project root>/pyproject.toml`. For example, `assets/**/sample.csv` includes all `sample.csv` files
113-
in `<project root>/assets` or any child directory. To recursively include all files under a
114-
directory, use a `/**` suffix, e.g. `src/**`.
201+
Includes are anchored, which means that `pyproject.toml` includes only `<root>/pyproject.toml` and
202+
not `<root>/bar/pyproject.toml`. To recursively include all files under a directory, use a `/**`
203+
suffix, e.g. `src/**`. Recursive inclusions are also anchored, e.g., `assets/**/sample.csv` includes
204+
all `sample.csv` files in `<root>/assets` or any of its children.
115205

116206
!!! note
117207

118208
For performance and reproducibility, avoid patterns without an anchor such as `**/sample.csv`.
119209

120210
Excludes are not anchored, which means that `__pycache__` excludes all directories named
121-
`__pycache__` and its children anywhere. To anchor a directory, use a `/` prefix, e.g., `/dist` will
122-
exclude only `<project root>/dist`.
211+
`__pycache__` regardless of its parent directory. All children of an exclusion are excluded as well.
212+
To anchor a directory, use a `/` prefix, e.g., `/dist` will exclude only `<root>/dist`.
123213

124214
All fields accepting patterns use the reduced portable glob syntax from
125215
[PEP 639](https://peps.python.org/pep-0639/#add-license-FILES-key), with the addition that

0 commit comments

Comments
 (0)