Skip to content

Commit 3c40d90

Browse files
committed
Clarify requires-python requirement for dependencies
1 parent 4caa158 commit 3c40d90

File tree

1 file changed

+29
-25
lines changed

1 file changed

+29
-25
lines changed

docs/concepts/resolution.md

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ requirements of the requested packages are compatible.
77

88
## Dependencies
99

10-
Most projects and packages have dependencies. Dependencies are other packages that are needed in
10+
Most projects and packages have dependencies. Dependencies are other packages that are necessary in
1111
order for the current package to work. A package defines its dependencies as _requirements_, roughly
1212
a combination of a package name and acceptable versions. The dependencies defined by the current
13-
project are called _direct dependencies_. The requirements added by each dependency of the current
13+
project are called _direct dependencies_. The dependencies added by each dependency of the current
1414
project are called _indirect_ or _transitive dependencies_.
1515

1616
!!! note
@@ -34,10 +34,10 @@ To help demonstrate the resolution process, consider the following dependencies:
3434
In this example, the resolver must find a set of package versions which satisfies the project
3535
requirements. Since there is only one version of both `foo` and `bar`, those will be used. The
3636
resolution must also include the transitive dependencies, so a version of `lib` must be chosen.
37-
`foo 1.0.0` allows all of the available versions of `lib`, but `bar 1.0.0` requires `lib>=2.0.0` so
37+
`foo 1.0.0` allows all available versions of `lib`, but `bar 1.0.0` requires `lib>=2.0.0` so
3838
`lib 2.0.0` must be used.
3939

40-
In some resolutions, there is more than one solution. Consider the following dependencies:
40+
In some resolutions, there may be more than one valid solution. Consider the following dependencies:
4141

4242
<!-- prettier-ignore -->
4343
- The project depends on `foo` and `bar`.
@@ -49,21 +49,21 @@ In some resolutions, there is more than one solution. Consider the following dep
4949
- `bar 2.0.0` depends on `lib==1.0.0`
5050
- `lib` has two versions, 1.0.0 and 2.0.0. Both versions have no dependencies.
5151

52-
In this example, some version of both `foo` and `bar` must be picked, however, determining which
52+
In this example, some version of both `foo` and `bar` must be selected; however, determining which
5353
version requires considering the dependencies of each version of `foo` and `bar`. `foo 2.0.0` and
54-
`bar 2.0.0` cannot be installed together because they conflict on their required version of `lib`,
55-
so the resolver must select either `foo 1.0.0` or `bar 1.0.0`. Both are valid solutions, and
56-
different resolution algorithms may give either result.
54+
`bar 2.0.0` cannot be installed together as they conflict on their required version of `lib`, so the
55+
resolver must select either `foo 1.0.0` (along with `bar 2.0.0`) or `bar 1.0.0` (along with
56+
`foo 1.0.0`). Both are valid solutions, and different resolution algorithms may yield either result.
5757

5858
## Platform markers
5959

6060
Markers allow attaching an expression to requirements that indicate when the dependency should be
61-
used. For example `bar; python_version<"3.9"` can be used to only require `bar` on Python 3.8 and
62-
older.
61+
used. For example `bar ; python_version < "3.9"` indicates that `bar` should only be installed on
62+
Python 3.8 and earlier.
6363

64-
Markers are used to adjust a package's dependencies depending on the current environment or
65-
platform. For example, markers can be used to change dependencies based on the operating system, the
66-
CPU architecture, the Python version, the Python implementation, and more.
64+
Markers are used to adjust a package's dependencies based on the current environment or platform.
65+
For example, markers can be used to modify dependencies by operating system, CPU architecture,
66+
Python version, Python implementation, and more.
6767

6868
!!! note
6969

@@ -98,16 +98,20 @@ be used. A universal resolution is often more constrained than a platform-specif
9898
we need to take the requirements for all markers into account.
9999

100100
During universal resolution, a minimum Python version must be specified. Project commands read the
101-
minimum required version from `project.requires-python` in the `pyproject.toml`. When using the pip
102-
interface, provide a value with the `--python-version` option, otherwise the current Python version
103-
will be treated as a lower bound. For example, `--universal --python-version 3.9` writes a universal
104-
resolution for Python 3.9 and later.
101+
minimum required version from `project.requires-python` in the `pyproject.toml`. When using uv's pip
102+
interface, provide a value with the `--python-version` option; otherwise, the current Python version
103+
will be treated as a lower bound. For example, `--universal --python-version 3.9` performs a
104+
universal resolution for Python 3.9 and later.
105105

106-
Setting the minimum Python version is important because all package versions we select have to be
107-
compatible with the Python version range. For example, a universal resolution of `numpy<2` with
108-
`--python-version 3.8` resolves to `numpy==1.24.4`, while `--python-version 3.9` resolves to
109-
`numpy==1.26.4`, as `numpy` releases after 1.26.4 require at Python 3.9+. Note that we only consider
110-
the lower bound of any Python requirement, upper bounds are always ignored.
106+
During universal resolution, any selected package version must be compatible with the _entire_
107+
`requires-python` range declared in the `pyproject.toml`. For example, if a project's
108+
`requires-python` is `>=3.8`, then uv will not allow any dependency versions that support, e.g.,
109+
Python 3.9 and later, as they are not compatible with Python 3.8, the lower bound of the supported
110+
range. In other words, the project's `requires-python` must be a subset of the `requires-python` of
111+
all dependencies.
112+
113+
When evaluating `requires-python` ranges for dependencies, uv only considers lower bounds and
114+
ignores upper bounds entirely. For example, `>=3.8, <4` is treated as `>=3.8`.
111115

112116
## Platform-specific resolution
113117

@@ -237,9 +241,9 @@ resolved versions, regardless of which packages are overlapping between the two.
237241

238242
## Dependency overrides
239243

240-
Dependency overrides allow bypassing failing or undesirable resolutions by overriding a package's
241-
declared dependencies. Overrides are a useful last resort for cases in which you _know_ that a
242-
dependency is compatible with a certain version of a package, despite the metadata indicating
244+
Dependency overrides allow bypassing unsuccessful or undesirable resolutions by overriding a
245+
package's declared dependencies. Overrides are a useful last resort for cases in which you _know_
246+
that a dependency is compatible with a certain version of a package, despite the metadata indicating
243247
otherwise.
244248

245249
For example, if a transitive dependency declares the requirement `pydantic>=1.0,<2.0`, but _does_

0 commit comments

Comments
 (0)