Skip to content

Commit d8aaa17

Browse files
Add documentation for required environments (#11542)
## Summary Right now, there's documentation in the settings reference. This adds some standalone prose.
1 parent 1bc7d93 commit d8aaa17

File tree

2 files changed

+106
-24
lines changed

2 files changed

+106
-24
lines changed

docs/concepts/projects/config.md

+14-7
Original file line numberDiff line numberDiff line change
@@ -209,19 +209,26 @@ environments = [
209209
]
210210
```
211211

212-
Or, to exclude alternative Python implementations:
212+
See the [resolution documentation](../resolution.md#limited-resolution-environments) for more.
213+
214+
## Required environments
215+
216+
If your project _must_ support a specific platform or Python version, you can mark that platform as
217+
required via the `required-environments` setting. For example, to require that the project supports
218+
Intel macOS:
213219

214220
```toml title="pyproject.toml"
215221
[tool.uv]
216-
environments = [
217-
"implementation_name == 'cpython'"
222+
required-environments = [
223+
"sys_platform == 'darwin' and platform.machine() == 'x86_64'",
218224
]
219225
```
220226

221-
Entries in the `environments` setting must be disjoint (i.e., they must not overlap). For example,
222-
`sys_platform == 'darwin'` and `sys_platform == 'linux'` are disjoint, but
223-
`sys_platform == 'darwin'` and `python_version >= '3.9'` are not, since both could be true at the
224-
same time.
227+
The `required-environments` setting is only relevant for packages that do not publish a source
228+
distribution (like PyTorch), as such packages can _only_ be installed on environments covered by the
229+
set of pre-built binary distributions (wheels) published by that package.
230+
231+
See the [resolution documentation](../resolution.md#required-environments) for more.
225232

226233
## Build isolation
227234

docs/concepts/resolution.md

+92-17
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,28 @@ the same platform the lockfile was created on. To solve this problem, platform-i
8181
uv supports both [platform-specific](#platform-specific-resolution) and
8282
[universal](#universal-resolution) resolution.
8383

84+
## Platform-specific resolution
85+
86+
By default, uv's pip interface, i.e., [`uv pip compile`](../pip/compile.md), produces a resolution
87+
that is platform-specific, like `pip-tools`. There is no way to use platform-specific resolution in
88+
the uv's project interface.
89+
90+
uv also supports resolving for specific, alternate platforms and Python versions with the
91+
`--python-platform` and `--python-version` options. For example, if using Python 3.12 on macOS,
92+
`uv pip compile --python-platform linux --python-version 3.10 requirements.in` can be used to
93+
produce a resolution for Python 3.10 on Linux instead. Unlike universal resolution, during
94+
platform-specific resolution, the provided `--python-version` is the exact python version to use,
95+
not a lower bound.
96+
97+
!!! note
98+
99+
Python's environment markers expose far more information about the current machine
100+
than can be expressed by a simple `--python-platform` argument. For example, the `platform_version` marker
101+
on macOS includes the time at which the kernel was built, which can (in theory) be encoded in
102+
package requirements. uv's resolver makes a best-effort attempt to generate a resolution that is
103+
compatible with any machine running on the target `--python-platform`, which should be sufficient for
104+
most use cases, but may lose fidelity for complex package and platform combinations.
105+
84106
## Universal resolution
85107

86108
uv's lockfile (`uv.lock`) is created with a universal resolution and is portable across platforms.
@@ -117,27 +139,80 @@ bounds on `requires-python` often leads to formally correct but practically inco
117139
as, e.g., resolvers will backtrack to the first published version that omits the upper bound (see:
118140
[`Requires-Python` upper limits](https://discuss.python.org/t/requires-python-upper-limits/12663)).
119141

120-
## Platform-specific resolution
142+
### Limited resolution environments
121143

122-
By default, uv's pip interface, i.e., [`uv pip compile`](../pip/compile.md), produces a resolution
123-
that is platform-specific, like `pip-tools`. There is no way to use platform-specific resolution in
124-
the uv's project interface.
144+
By default, the universal resolver attempts to solve for all platforms and Python versions.
125145

126-
uv also supports resolving for specific, alternate platforms and Python versions with the
127-
`--python-platform` and `--python-version` options. For example, if using Python 3.12 on macOS,
128-
`uv pip compile --python-platform linux --python-version 3.10 requirements.in` can be used to
129-
produce a resolution for Python 3.10 on Linux instead. Unlike universal resolution, during
130-
platform-specific resolution, the provided `--python-version` is the exact python version to use,
131-
not a lower bound.
146+
If your project supports only a limited set of platforms or Python versions, you can constrain the
147+
set of solved platforms via the `environments` setting, which accepts a list of PEP 508 environment
148+
markers. In other words, you can use the `environments` setting to _reduce_ the set of supported
149+
platforms.
132150

133-
!!! note
151+
For example, to constrain the lockfile to macOS and Linux, and avoid solving for Windows:
134152

135-
Python's environment markers expose far more information about the current machine
136-
than can be expressed by a simple `--python-platform` argument. For example, the `platform_version` marker
137-
on macOS includes the time at which the kernel was built, which can (in theory) be encoded in
138-
package requirements. uv's resolver makes a best-effort attempt to generate a resolution that is
139-
compatible with any machine running on the target `--python-platform`, which should be sufficient for
140-
most use cases, but may lose fidelity for complex package and platform combinations.
153+
```toml title="pyproject.toml"
154+
[tool.uv]
155+
environments = [
156+
"sys_platform == 'darwin'",
157+
"sys_platform == 'linux'",
158+
]
159+
```
160+
161+
Or, to avoid solving for alternative Python implementations:
162+
163+
```toml title="pyproject.toml"
164+
[tool.uv]
165+
environments = [
166+
"implementation_name == 'cpython'"
167+
]
168+
```
169+
170+
Entries in the `environments` setting must be disjoint (i.e., they must not overlap). For example,
171+
`sys_platform == 'darwin'` and `sys_platform == 'linux'` are disjoint, but
172+
`sys_platform == 'darwin'` and `python_version >= '3.9'` are not, since both could be true at the
173+
same time.
174+
175+
### Required environments
176+
177+
In the Python ecosystem, packages can be published as source distributions, built distributions
178+
(wheels), or both; but to install a package, a built distribution is required. If a package lacks a
179+
built distribution, or lacks a distribution for the current platform or Python version (built
180+
distributions are often platform-specific), uv will attempt to build the package from source, then
181+
install the resulting built distribution.
182+
183+
Some packages (like PyTorch) publish built distributions, but omit a source distribution. Such
184+
packages are _only_ installable on platforms for which a built distribution is available. For
185+
example, if a package publishes built distributions for Linux, but not macOS or Windows, then that
186+
package will _only_ be installable on Windows.
187+
188+
Packages that lack source distributions cause problems for universal resolution, since there will
189+
typically be at least one platform or Python version for which the package is not installable.
190+
191+
By default, uv requires each such package to include at least one wheel that is compatible with the
192+
target Python version. The `required-environments` setting can be used to ensure that the resulting
193+
resolution contains wheels for specific platforms, or fails if no such wheels are available.
194+
195+
While the `environments` setting _limits_ the set of environments that uv will consider when
196+
resolving dependencies, `required-environments` _expands_ the set of platforms that uv _must_
197+
support when resolving dependencies.
198+
199+
For example, `environments = ["sys_platform == 'darwin'"]` would limit uv to solving for macOS (and
200+
ignoring Linux and Windows). On the other hand,
201+
`required-environments = ["sys_platform == 'darwin'"]` would _require_ that any package without a
202+
source distribution include a wheel for macOS in order to be installable (and would fail if no such
203+
wheel is available).
204+
205+
In practice, `required-environments` can be useful for declaring explicit support for non-latest
206+
platforms, since this often requires backtracking past the latest published versions of those
207+
packages. For example, to guarantee that any built distribution-only packages includes support for
208+
Intel macOS:
209+
210+
```toml title="pyproject.toml"
211+
[tool.uv]
212+
required-environments = [
213+
"sys_platform == 'darwin' and platform_machine == 'x86_64'"
214+
]
215+
```
141216

142217
## Dependency preferences
143218

0 commit comments

Comments
 (0)