mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-17 18:57:30 +00:00
Collapse redundant Python version incompatibilities in resolver error message (#9957)
Part of https://github.com/astral-sh/uv/issues/9886 Technically could affect other redundant clauses, but that does not appear to be the case in practice.
This commit is contained in:
parent
654ff8015a
commit
052c1a6fd1
3 changed files with 84 additions and 10 deletions
|
|
@ -338,6 +338,10 @@ impl std::fmt::Display for NoSolutionError {
|
||||||
|
|
||||||
simplify_derivation_tree_ranges(&mut tree, &self.available_versions);
|
simplify_derivation_tree_ranges(&mut tree, &self.available_versions);
|
||||||
|
|
||||||
|
while collapse_redundant_no_versions_tree(&mut tree) {
|
||||||
|
// Continue collapsing until no more redundant nodes are found
|
||||||
|
}
|
||||||
|
|
||||||
if should_display_tree {
|
if should_display_tree {
|
||||||
display_tree(&tree, "Resolver derivation tree after reduction");
|
display_tree(&tree, "Resolver derivation tree after reduction");
|
||||||
}
|
}
|
||||||
|
|
@ -486,6 +490,81 @@ fn collapse_redundant_no_versions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a [`DerivationTree`], collapse any derived trees with two `NoVersions` nodes for the same
|
||||||
|
/// package. For example, if we have a tree like:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// term Python>=3.7.9
|
||||||
|
/// no versions of Python>=3.7.9, <3.8
|
||||||
|
/// no versions of Python>=3.8
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// We can simplify this to:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// no versions of Python>=3.7.9
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This function returns a `bool` indicating if a change was made. This allows for repeated calls,
|
||||||
|
/// e.g., the following tree contains nested redundant trees:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// term Python>=3.10
|
||||||
|
/// no versions of Python>=3.11, <3.12
|
||||||
|
/// term Python>=3.10, <3.11 | >=3.12
|
||||||
|
/// no versions of Python>=3.12
|
||||||
|
/// no versions of Python>=3.10, <3.11
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// We can simplify this to:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// no versions of Python>=3.10
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This appears to be common with the way the resolver currently models Python version
|
||||||
|
/// incompatibilities.
|
||||||
|
fn collapse_redundant_no_versions_tree(
|
||||||
|
tree: &mut DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>,
|
||||||
|
) -> bool {
|
||||||
|
match tree {
|
||||||
|
DerivationTree::External(_) => false,
|
||||||
|
DerivationTree::Derived(derived) => {
|
||||||
|
match (
|
||||||
|
Arc::make_mut(&mut derived.cause1),
|
||||||
|
Arc::make_mut(&mut derived.cause2),
|
||||||
|
) {
|
||||||
|
// If we have a tree with two `NoVersions` nodes for the same package...
|
||||||
|
(
|
||||||
|
DerivationTree::External(External::NoVersions(package, versions)),
|
||||||
|
DerivationTree::External(External::NoVersions(other_package, other_versions)),
|
||||||
|
) if package == other_package => {
|
||||||
|
// Retrieve the terms from the parent.
|
||||||
|
let Some(Term::Positive(term)) = derived.terms.get(package) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If they're both subsets of the term, then drop this node in favor of the term
|
||||||
|
if versions.subset_of(term) && other_versions.subset_of(term) {
|
||||||
|
*tree = DerivationTree::External(External::NoVersions(
|
||||||
|
package.clone(),
|
||||||
|
term.clone(),
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// If not, just recurse
|
||||||
|
_ => {
|
||||||
|
collapse_redundant_no_versions_tree(Arc::make_mut(&mut derived.cause1))
|
||||||
|
|| collapse_redundant_no_versions_tree(Arc::make_mut(&mut derived.cause2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a [`DerivationTree`], collapse any `NoVersion` incompatibilities for workspace members
|
/// Given a [`DerivationTree`], collapse any `NoVersion` incompatibilities for workspace members
|
||||||
/// to avoid saying things like "only <workspace-member>==0.1.0 is available".
|
/// to avoid saying things like "only <workspace-member>==0.1.0 is available".
|
||||||
fn collapse_no_versions_of_workspace_members(
|
fn collapse_no_versions_of_workspace_members(
|
||||||
|
|
|
||||||
|
|
@ -3232,8 +3232,8 @@ fn lock_requires_python() -> Result<()> {
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
× No solution found when resolving dependencies for split (python_full_version >= '3.7' and python_full_version < '3.7.9'):
|
× No solution found when resolving dependencies for split (python_full_version >= '3.7' and python_full_version < '3.7.9'):
|
||||||
╰─▶ Because the requested Python version (>=3.7) does not satisfy Python>=3.8 and the requested Python version (>=3.7) does not satisfy Python>=3.7.9,<3.8, we can conclude that Python>=3.7.9 cannot be used.
|
╰─▶ Because the requested Python version (>=3.7) does not satisfy Python>=3.7.9 and pygls>=1.1.0,<=1.2.1 depends on Python>=3.7.9,<4, we can conclude that pygls>=1.1.0,<=1.2.1 cannot be used.
|
||||||
And because pygls>=1.1.0,<=1.2.1 depends on Python>=3.7.9,<4 and only pygls<=1.3.0 is available, we can conclude that all of:
|
And because only pygls<=1.3.0 is available, we can conclude that all of:
|
||||||
pygls>=1.1.0,<1.3.0
|
pygls>=1.1.0,<1.3.0
|
||||||
pygls>1.3.0
|
pygls>1.3.0
|
||||||
cannot be used. (1)
|
cannot be used. (1)
|
||||||
|
|
|
||||||
|
|
@ -3722,19 +3722,14 @@ fn python_greater_than_current_excluded() {
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
× No solution found when resolving dependencies:
|
× No solution found when resolving dependencies:
|
||||||
╰─▶ Because the current Python version (3.9.[X]) does not satisfy Python>=3.10,<3.11 and the current Python version (3.9.[X]) does not satisfy Python>=3.12, we can conclude that all of:
|
╰─▶ Because the current Python version (3.9.[X]) does not satisfy Python>=3.10 and package-a==2.0.0 depends on Python>=3.10, we can conclude that package-a==2.0.0 cannot be used.
|
||||||
Python>=3.10,<3.11
|
And because only the following versions of package-a are available:
|
||||||
Python>=3.12
|
|
||||||
cannot be used.
|
|
||||||
And because the current Python version (3.9.[X]) does not satisfy Python>=3.11,<3.12, we can conclude that Python>=3.10 cannot be used.
|
|
||||||
And because package-a==2.0.0 depends on Python>=3.10 and only the following versions of package-a are available:
|
|
||||||
package-a<=2.0.0
|
package-a<=2.0.0
|
||||||
package-a==3.0.0
|
package-a==3.0.0
|
||||||
package-a==4.0.0
|
package-a==4.0.0
|
||||||
we can conclude that package-a>=2.0.0,<3.0.0 cannot be used. (1)
|
we can conclude that package-a>=2.0.0,<3.0.0 cannot be used. (1)
|
||||||
|
|
||||||
Because the current Python version (3.9.[X]) does not satisfy Python>=3.11,<3.12 and the current Python version (3.9.[X]) does not satisfy Python>=3.12, we can conclude that Python>=3.11 cannot be used.
|
Because the current Python version (3.9.[X]) does not satisfy Python>=3.11 and package-a==3.0.0 depends on Python>=3.11, we can conclude that package-a==3.0.0 cannot be used.
|
||||||
And because package-a==3.0.0 depends on Python>=3.11, we can conclude that package-a==3.0.0 cannot be used.
|
|
||||||
And because we know from (1) that package-a>=2.0.0,<3.0.0 cannot be used, we can conclude that package-a>=2.0.0,<4.0.0 cannot be used. (2)
|
And because we know from (1) that package-a>=2.0.0,<3.0.0 cannot be used, we can conclude that package-a>=2.0.0,<4.0.0 cannot be used. (2)
|
||||||
|
|
||||||
Because the current Python version (3.9.[X]) does not satisfy Python>=3.12 and package-a==4.0.0 depends on Python>=3.12, we can conclude that package-a==4.0.0 cannot be used.
|
Because the current Python version (3.9.[X]) does not satisfy Python>=3.12 and package-a==4.0.0 depends on Python>=3.12, we can conclude that package-a==4.0.0 cannot be used.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue