Skip to content

Commit 8d6d067

Browse files
authored
Move "Conflicting dependencies" to the "Resolution" page (#14633)
1 parent 863e73a commit 8d6d067

File tree

2 files changed

+117
-83
lines changed

2 files changed

+117
-83
lines changed

docs/concepts/projects/config.md

Lines changed: 41 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -196,41 +196,6 @@ To target this environment, you'd export `UV_PROJECT_ENVIRONMENT=/usr/local`.
196196
environment. The `--active` flag can be used to opt-in to respecting `VIRTUAL_ENV`. The
197197
`--no-active` flag can be used to silence the warning.
198198

199-
## Limited resolution environments
200-
201-
If your project supports a more limited set of platforms or Python versions, you can constrain the
202-
set of solved platforms via the `environments` setting, which accepts a list of PEP 508 environment
203-
markers. For example, to constrain the lockfile to macOS and Linux, and exclude Windows:
204-
205-
```toml title="pyproject.toml"
206-
[tool.uv]
207-
environments = [
208-
"sys_platform == 'darwin'",
209-
"sys_platform == 'linux'",
210-
]
211-
```
212-
213-
See the [resolution documentation](../resolution.md#limited-resolution-environments) for more.
214-
215-
## Required environments
216-
217-
If your project _must_ support a specific platform or Python version, you can mark that platform as
218-
required via the `required-environments` setting. For example, to require that the project supports
219-
Intel macOS:
220-
221-
```toml title="pyproject.toml"
222-
[tool.uv]
223-
required-environments = [
224-
"sys_platform == 'darwin' and platform_machine == 'x86_64'",
225-
]
226-
```
227-
228-
The `required-environments` setting is only relevant for packages that do not publish a source
229-
distribution (like PyTorch), as such packages can _only_ be installed on environments covered by the
230-
set of pre-built binary distributions (wheels) published by that package.
231-
232-
See the [resolution documentation](../resolution.md#required-environments) for more.
233-
234199
## Build isolation
235200

236201
By default, uv builds all packages in isolated virtual environments, as per
@@ -401,70 +366,68 @@ in the deployed environment without a dependency on the originating source code.
401366

402367
## Conflicting dependencies
403368

404-
uv requires that all optional dependencies ("extras") declared by the project are compatible with
405-
each other and resolves all optional dependencies together when creating the lockfile.
369+
uv requires resolves all project dependencies together, including optional dependencies ("extras")
370+
and dependency groups. If dependencies declared in one section are not compatible with those in
371+
another section, uv will fail to resolve the requirements of the project with an error.
406372

407-
If optional dependencies declared in one extra are not compatible with those in another extra, uv
408-
will fail to resolve the requirements of the project with an error.
409-
410-
To work around this, uv supports declaring conflicting extras. For example, consider two sets of
411-
optional dependencies that conflict with one another:
373+
uv supports explicit declaration of conflicting dependency groups. For example, to declare that the
374+
`optional-dependency` groups `extra1` and `extra2` are incompatible:
412375

413376
```toml title="pyproject.toml"
414-
[project.optional-dependencies]
415-
extra1 = ["numpy==2.1.2"]
416-
extra2 = ["numpy==2.0.0"]
417-
```
418-
419-
If you run `uv lock` with the above dependencies, resolution will fail:
420-
421-
```console
422-
$ uv lock
423-
x No solution found when resolving dependencies:
424-
`-> 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
425-
myproject[extra2] are incompatible.
426-
And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.
377+
[tool.uv]
378+
conflicts = [
379+
[
380+
{ extra = "extra1" },
381+
{ extra = "extra2" },
382+
],
383+
]
427384
```
428385

429-
But if you specify that `extra1` and `extra2` are conflicting, uv will resolve them separately.
430-
Specify conflicts in the `tool.uv` section:
386+
Or, to declare the development dependency groups `group1` and `group2` incompatible:
431387

432388
```toml title="pyproject.toml"
433389
[tool.uv]
434390
conflicts = [
435391
[
436-
{ extra = "extra1" },
437-
{ extra = "extra2" },
392+
{ group = "group1" },
393+
{ group = "group2" },
438394
],
439395
]
440396
```
441397

442-
Now, running `uv lock` will succeed. Note though, that now you cannot install both `extra1` and
443-
`extra2` at the same time:
398+
See the [resolution documentation](../resolution.md#conflicting-dependencies) for more.
444399

445-
```console
446-
$ uv sync --extra extra1 --extra extra2
447-
Resolved 3 packages in 14ms
448-
error: extra `extra1`, extra `extra2` are incompatible with the declared conflicts: {`myproject[extra1]`, `myproject[extra2]`}
400+
## Limited resolution environments
401+
402+
If your project supports a more limited set of platforms or Python versions, you can constrain the
403+
set of solved platforms via the `environments` setting, which accepts a list of PEP 508 environment
404+
markers. For example, to constrain the lockfile to macOS and Linux, and exclude Windows:
405+
406+
```toml title="pyproject.toml"
407+
[tool.uv]
408+
environments = [
409+
"sys_platform == 'darwin'",
410+
"sys_platform == 'linux'",
411+
]
449412
```
450413

451-
This error occurs because installing both `extra1` and `extra2` would result in installing two
452-
different versions of a package into the same environment.
414+
See the [resolution documentation](../resolution.md#limited-resolution-environments) for more.
453415

454-
The above strategy for dealing with conflicting extras also works with dependency groups:
416+
## Required environments
455417

456-
```toml title="pyproject.toml"
457-
[dependency-groups]
458-
group1 = ["numpy==2.1.2"]
459-
group2 = ["numpy==2.0.0"]
418+
If your project _must_ support a specific platform or Python version, you can mark that platform as
419+
required via the `required-environments` setting. For example, to require that the project supports
420+
Intel macOS:
460421

422+
```toml title="pyproject.toml"
461423
[tool.uv]
462-
conflicts = [
463-
[
464-
{ group = "group1" },
465-
{ group = "group2" },
466-
],
424+
required-environments = [
425+
"sys_platform == 'darwin' and platform_machine == 'x86_64'",
467426
]
468427
```
469428

470-
The only difference with conflicting extras is that you need to use `group` instead of `extra`.
429+
The `required-environments` setting is only relevant for packages that do not publish a source
430+
distribution (like PyTorch), as such packages can _only_ be installed on environments covered by the
431+
set of pre-built binary distributions (wheels) published by that package.
432+
433+
See the [resolution documentation](../resolution.md#required-environments) for more.

docs/concepts/resolution.md

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,77 @@ though only `name`, `version`, `requires-dist`, `requires-python`, and `provides
453453
uv. The `version` field is also considered optional. If omitted, the metadata will be used for all
454454
versions of the specified package.
455455

456+
## Conflicting dependencies
457+
458+
uv requires that all optional dependencies ("extras") declared by the project are compatible with
459+
each other and resolves all optional dependencies together when creating the lockfile.
460+
461+
If optional dependencies declared in one extra are not compatible with those in another extra, uv
462+
will fail to resolve the requirements of the project with an error.
463+
464+
To work around this, uv supports declaring conflicting extras. For example, consider two sets of
465+
optional dependencies that conflict with one another:
466+
467+
```toml title="pyproject.toml"
468+
[project.optional-dependencies]
469+
extra1 = ["numpy==2.1.2"]
470+
extra2 = ["numpy==2.0.0"]
471+
```
472+
473+
If you run `uv lock` with the above dependencies, resolution will fail:
474+
475+
```console
476+
$ uv lock
477+
x No solution found when resolving dependencies:
478+
`-> 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
479+
myproject[extra2] are incompatible.
480+
And because your project requires myproject[extra1] and myproject[extra2], we can conclude that your projects's requirements are unsatisfiable.
481+
```
482+
483+
But if you specify that `extra1` and `extra2` are conflicting, uv will resolve them separately.
484+
Specify conflicts in the `tool.uv` section:
485+
486+
```toml title="pyproject.toml"
487+
[tool.uv]
488+
conflicts = [
489+
[
490+
{ extra = "extra1" },
491+
{ extra = "extra2" },
492+
],
493+
]
494+
```
495+
496+
Now, running `uv lock` will succeed. Note though, that now you cannot install both `extra1` and
497+
`extra2` at the same time:
498+
499+
```console
500+
$ uv sync --extra extra1 --extra extra2
501+
Resolved 3 packages in 14ms
502+
error: extra `extra1`, extra `extra2` are incompatible with the declared conflicts: {`myproject[extra1]`, `myproject[extra2]`}
503+
```
504+
505+
This error occurs because installing both `extra1` and `extra2` would result in installing two
506+
different versions of a package into the same environment.
507+
508+
The above strategy for dealing with conflicting extras also works with dependency groups:
509+
510+
```toml title="pyproject.toml"
511+
[dependency-groups]
512+
group1 = ["numpy==2.1.2"]
513+
group2 = ["numpy==2.0.0"]
514+
515+
[tool.uv]
516+
conflicts = [
517+
[
518+
{ group = "group1" },
519+
{ group = "group2" },
520+
],
521+
]
522+
```
523+
524+
The only difference from conflicting extras is that you need to use the `group` key instead of
525+
`extra`.
526+
456527
## Lower bounds
457528

458529
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:
513584
- lzma tarball (`.tar.lzma`)
514585
- zip (`.zip`)
515586

516-
## Learn more
517-
518-
For more details about the internals of the resolver, see the
519-
[resolver reference](../reference/resolver-internals.md) documentation.
520-
521587
## Lockfile versioning
522588

523589
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.
539605
The `revision` field of the lockfile is used to track backwards compatible changes to the lockfile.
540606
For example, adding a new field to distributions. Changes to the revision will not cause older
541607
versions of uv to error.
608+
609+
## Learn more
610+
611+
For more details about the internals of the resolver, see the
612+
[resolver reference](../reference/resolver-internals.md) documentation.

0 commit comments

Comments
 (0)