Move "Conflicting dependencies" to the "Resolution" page (#14633)

This commit is contained in:
Zanie Blue 2025-07-15 16:47:43 -05:00 committed by GitHub
parent 863e73a841
commit 8d6d0678a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 118 additions and 84 deletions

View File

@ -196,41 +196,6 @@ To target this environment, you'd export `UV_PROJECT_ENVIRONMENT=/usr/local`.
environment. The `--active` flag can be used to opt-in to respecting `VIRTUAL_ENV`. The
`--no-active` flag can be used to silence the warning.
## Limited resolution environments
If your project supports a more limited set of platforms or Python versions, you can constrain the
set of solved platforms via the `environments` setting, which accepts a list of PEP 508 environment
markers. For example, to constrain the lockfile to macOS and Linux, and exclude Windows:
```toml title="pyproject.toml"
[tool.uv]
environments = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
]
```
See the [resolution documentation](../resolution.md#limited-resolution-environments) for more.
## Required environments
If your project _must_ support a specific platform or Python version, you can mark that platform as
required via the `required-environments` setting. For example, to require that the project supports
Intel macOS:
```toml title="pyproject.toml"
[tool.uv]
required-environments = [
"sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
```
The `required-environments` setting is only relevant for packages that do not publish a source
distribution (like PyTorch), as such packages can _only_ be installed on environments covered by the
set of pre-built binary distributions (wheels) published by that package.
See the [resolution documentation](../resolution.md#required-environments) for more.
## Build isolation
By default, uv builds all packages in isolated virtual environments, as per
@ -401,33 +366,12 @@ in the deployed environment without a dependency on the originating source code.
## Conflicting dependencies
uv requires that all optional dependencies ("extras") declared by the project are compatible with
each other and resolves all optional dependencies together when creating the lockfile.
uv requires resolves all project dependencies together, including optional dependencies ("extras")
and dependency groups. If dependencies declared in one section are not compatible with those in
another section, uv will fail to resolve the requirements of the project with an error.
If optional dependencies declared in one extra are not compatible with those in another extra, uv
will fail to resolve the requirements of the project with an error.
To work around this, uv supports declaring conflicting extras. For example, consider two sets of
optional dependencies that conflict with one another:
```toml title="pyproject.toml"
[project.optional-dependencies]
extra1 = ["numpy==2.1.2"]
extra2 = ["numpy==2.0.0"]
```
If you run `uv lock` with the above dependencies, resolution will fail:
```console
$ uv lock
x No solution found when resolving dependencies:
`-> Because myproject[extra2] depends on numpy==2.0.0 and myproject[extra1] depends on numpy==2.1.2, we can conclude that myproject[extra1] and
myproject[extra2] are incompatible.
And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.
```
But if you specify that `extra1` and `extra2` are conflicting, uv will resolve them separately.
Specify conflicts in the `tool.uv` section:
uv supports explicit declaration of conflicting dependency groups. For example, to declare that the
`optional-dependency` groups `extra1` and `extra2` are incompatible:
```toml title="pyproject.toml"
[tool.uv]
@ -439,25 +383,9 @@ conflicts = [
]
```
Now, running `uv lock` will succeed. Note though, that now you cannot install both `extra1` and
`extra2` at the same time:
```console
$ uv sync --extra extra1 --extra extra2
Resolved 3 packages in 14ms
error: extra `extra1`, extra `extra2` are incompatible with the declared conflicts: {`myproject[extra1]`, `myproject[extra2]`}
```
This error occurs because installing both `extra1` and `extra2` would result in installing two
different versions of a package into the same environment.
The above strategy for dealing with conflicting extras also works with dependency groups:
Or, to declare the development dependency groups `group1` and `group2` incompatible:
```toml title="pyproject.toml"
[dependency-groups]
group1 = ["numpy==2.1.2"]
group2 = ["numpy==2.0.0"]
[tool.uv]
conflicts = [
[
@ -467,4 +395,39 @@ conflicts = [
]
```
The only difference with conflicting extras is that you need to use `group` instead of `extra`.
See the [resolution documentation](../resolution.md#conflicting-dependencies) for more.
## Limited resolution environments
If your project supports a more limited set of platforms or Python versions, you can constrain the
set of solved platforms via the `environments` setting, which accepts a list of PEP 508 environment
markers. For example, to constrain the lockfile to macOS and Linux, and exclude Windows:
```toml title="pyproject.toml"
[tool.uv]
environments = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
]
```
See the [resolution documentation](../resolution.md#limited-resolution-environments) for more.
## Required environments
If your project _must_ support a specific platform or Python version, you can mark that platform as
required via the `required-environments` setting. For example, to require that the project supports
Intel macOS:
```toml title="pyproject.toml"
[tool.uv]
required-environments = [
"sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
```
The `required-environments` setting is only relevant for packages that do not publish a source
distribution (like PyTorch), as such packages can _only_ be installed on environments covered by the
set of pre-built binary distributions (wheels) published by that package.
See the [resolution documentation](../resolution.md#required-environments) for more.

View File

@ -453,6 +453,77 @@ though only `name`, `version`, `requires-dist`, `requires-python`, and `provides
uv. The `version` field is also considered optional. If omitted, the metadata will be used for all
versions of the specified package.
## Conflicting dependencies
uv requires that all optional dependencies ("extras") declared by the project are compatible with
each other and resolves all optional dependencies together when creating the lockfile.
If optional dependencies declared in one extra are not compatible with those in another extra, uv
will fail to resolve the requirements of the project with an error.
To work around this, uv supports declaring conflicting extras. For example, consider two sets of
optional dependencies that conflict with one another:
```toml title="pyproject.toml"
[project.optional-dependencies]
extra1 = ["numpy==2.1.2"]
extra2 = ["numpy==2.0.0"]
```
If you run `uv lock` with the above dependencies, resolution will fail:
```console
$ uv lock
x No solution found when resolving dependencies:
`-> Because myproject[extra2] depends on numpy==2.0.0 and myproject[extra1] depends on numpy==2.1.2, we can conclude that myproject[extra1] and
myproject[extra2] are incompatible.
And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.
```
But if you specify that `extra1` and `extra2` are conflicting, uv will resolve them separately.
Specify conflicts in the `tool.uv` section:
```toml title="pyproject.toml"
[tool.uv]
conflicts = [
[
{ extra = "extra1" },
{ extra = "extra2" },
],
]
```
Now, running `uv lock` will succeed. Note though, that now you cannot install both `extra1` and
`extra2` at the same time:
```console
$ uv sync --extra extra1 --extra extra2
Resolved 3 packages in 14ms
error: extra `extra1`, extra `extra2` are incompatible with the declared conflicts: {`myproject[extra1]`, `myproject[extra2]`}
```
This error occurs because installing both `extra1` and `extra2` would result in installing two
different versions of a package into the same environment.
The above strategy for dealing with conflicting extras also works with dependency groups:
```toml title="pyproject.toml"
[dependency-groups]
group1 = ["numpy==2.1.2"]
group2 = ["numpy==2.0.0"]
[tool.uv]
conflicts = [
[
{ group = "group1" },
{ group = "group2" },
],
]
```
The only difference from conflicting extras is that you need to use the `group` key instead of
`extra`.
## Lower bounds
By default, `uv add` adds lower bounds to dependencies and, when using uv to manage projects, uv
@ -513,11 +584,6 @@ reading and extracting archives in the following formats:
- lzma tarball (`.tar.lzma`)
- zip (`.zip`)
## Learn more
For more details about the internals of the resolver, see the
[resolver reference](../reference/resolver-internals.md) documentation.
## Lockfile versioning
The `uv.lock` file uses a versioned schema. The schema version is included in the `version` field of
@ -539,3 +605,8 @@ other words, lockfiles may only be rejected across minor releases.
The `revision` field of the lockfile is used to track backwards compatible changes to the lockfile.
For example, adding a new field to distributions. Changes to the revision will not cause older
versions of uv to error.
## Learn more
For more details about the internals of the resolver, see the
[resolver reference](../reference/resolver-internals.md) documentation.