Skip to content

Commit

Permalink
Reduce ambiguity in conflicting extras example
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jan 22, 2025
1 parent 183fe40 commit 2582989
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 54 deletions.
48 changes: 22 additions & 26 deletions crates/uv-workspace/src/pyproject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,48 +504,44 @@ pub struct ToolUv {
)]
pub environments: Option<SupportedEnvironments>,

/// Conflicting extras or groups may be declared here.
/// Declare collections of extras or dependency groups that are conflicting
/// (i.e., mutually exclusive).
///
/// It's useful to declare conflicts when, for example, two or more extras
/// have mutually incompatible dependencies. Extra `foo` might depend
/// on `numpy==2.0.0` while extra `bar` might depend on `numpy==2.1.0`.
/// These extras cannot be activated at the same time. This usually isn't
/// a problem for pip-style workflows, but when using projects in uv that
/// support with universal resolution, it will try to produce a resolution
/// that satisfies both extras simultaneously.
/// It's useful to declare conflicts when two or more extras have mutually
/// incompatible dependencies. For example, extra `foo` might depend
/// on `numpy==2.0.0` while extra `bar` depends on `numpy==2.1.0`. While these
/// dependencies conflict, it may be the case that users are not expected to
/// activate both `foo` and `bar` at the same time, making it possible to
/// generate a universal resolution for the project despite the incompatibility.
///
/// When this happens, resolution will fail, because one cannot install
/// both `numpy 2.0.0` and `numpy 2.1.0` into the same environment.
///
/// To work around this, you may specify `foo` and `bar` as conflicting
/// extras (you can do the same with groups). When doing universal
/// resolution in project mode, these extras will get their own "forks"
/// distinct from one another in order to permit conflicting dependencies.
/// In exchange, if one tries to install from the lock file with both
/// conflicting extras activated, installation will fail.
/// By making such conflicts explicit, uv can generate a universal resolution
/// for a project, taking into account that certain combinations of extras and
/// groups are mutually exclusive. In exchange, installation will fail if a
/// user attempts to activate both conflicting extras.
#[cfg_attr(
feature = "schemars",
schemars(description = "A list sets of conflicting groups or extras.")
schemars(description = "A list of sets of conflicting groups or extras.")
)]
#[option(
default = r#"[]"#,
value_type = "list[list[dict]]",
example = r#"
# Require that `package[test1]` and `package[test2]`
# requirements are resolved in different forks so that they
# cannot conflict with one another.
# Require that `package[extra1]` and `package[extra2]` are resolved
# in different forks so that they cannot conflict with one another.
conflicts = [
[
{ extra = "test1" },
{ extra = "test2" },
{ extra = "extra1" },
{ extra = "extra2" },
]
]
# Or, to declare conflicting groups:
# Require that the dependency groups `group1` and `group2`
# are resolved in different forks so that they cannot conflict
# with one another.
conflicts = [
[
{ group = "test1" },
{ group = "test2" },
{ group = "group1" },
{ group = "group2" },
]
]
"#
Expand Down
50 changes: 23 additions & 27 deletions docs/reference/settings.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
## Project metadata
### [`conflicts`](#conflicts) {: #conflicts }

Conflicting extras or groups may be declared here.

It's useful to declare conflicts when, for example, two or more extras
have mutually incompatible dependencies. Extra `foo` might depend
on `numpy==2.0.0` while extra `bar` might depend on `numpy==2.1.0`.
These extras cannot be activated at the same time. This usually isn't
a problem for pip-style workflows, but when using projects in uv that
support with universal resolution, it will try to produce a resolution
that satisfies both extras simultaneously.

When this happens, resolution will fail, because one cannot install
both `numpy 2.0.0` and `numpy 2.1.0` into the same environment.

To work around this, you may specify `foo` and `bar` as conflicting
extras (you can do the same with groups). When doing universal
resolution in project mode, these extras will get their own "forks"
distinct from one another in order to permit conflicting dependencies.
In exchange, if one tries to install from the lock file with both
conflicting extras activated, installation will fail.
Declare collections of extras or dependency groups that are conflicting
(i.e., mutually exclusive).

It's useful to declare conflicts when two or more extras have mutually
incompatible dependencies. For example, extra `foo` might depend
on `numpy==2.0.0` while extra `bar` depends on `numpy==2.1.0`. While these
dependencies conflict, it may be the case that users are not expected to
activate both `foo` and `bar` at the same time, making it possible to
generate a universal resolution for the project despite the incompatibility.

By making such conflicts explicit, uv can generate a universal resolution
for a project, taking into account that certain combinations of extras and
groups are mutually exclusive. In exchange, installation will fail if a
user attempts to activate both conflicting extras.

**Default value**: `[]`

Expand All @@ -29,21 +24,22 @@ conflicting extras activated, installation will fail.

```toml title="pyproject.toml"
[tool.uv]
# Require that `package[test1]` and `package[test2]`
# requirements are resolved in different forks so that they
# cannot conflict with one another.
# Require that `package[extra1]` and `package[extra2]` are resolved
# in different forks so that they cannot conflict with one another.
conflicts = [
[
{ extra = "test1" },
{ extra = "test2" },
{ extra = "extra1" },
{ extra = "extra2" },
]
]

# Or, to declare conflicting groups:
# Require that the dependency groups `group1` and `group2`
# are resolved in different forks so that they cannot conflict
# with one another.
conflicts = [
[
{ group = "test1" },
{ group = "test2" },
{ group = "group1" },
{ group = "group2" },
]
]
```
Expand Down
2 changes: 1 addition & 1 deletion uv.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2582989

Please sign in to comment.