mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-03 13:14:41 +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);
|
||||
|
||||
while collapse_redundant_no_versions_tree(&mut tree) {
|
||||
// Continue collapsing until no more redundant nodes are found
|
||||
}
|
||||
|
||||
if should_display_tree {
|
||||
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
|
||||
/// to avoid saying things like "only <workspace-member>==0.1.0 is available".
|
||||
fn collapse_no_versions_of_workspace_members(
|
||||
|
|
|
|||
|
|
@ -3232,8 +3232,8 @@ fn lock_requires_python() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
× 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.
|
||||
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:
|
||||
╰─▶ 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 only pygls<=1.3.0 is available, we can conclude that all of:
|
||||
pygls>=1.1.0,<1.3.0
|
||||
pygls>1.3.0
|
||||
cannot be used. (1)
|
||||
|
|
|
|||
|
|
@ -3722,19 +3722,14 @@ fn python_greater_than_current_excluded() {
|
|||
|
||||
----- stderr -----
|
||||
× 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:
|
||||
Python>=3.10,<3.11
|
||||
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:
|
||||
╰─▶ 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.
|
||||
And because only the following versions of package-a are available:
|
||||
package-a<=2.0.0
|
||||
package-a==3.0.0
|
||||
package-a==4.0.0
|
||||
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.
|
||||
And because package-a==3.0.0 depends on Python>=3.11, we can conclude that package-a==3.0.0 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 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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue