Invert display of "no versions" incompatibilities with multiple ranges (#1233)

Closes #884 

e.g.

```
❯ cargo run -q -- pip compile --python-version 3.12 requirements.in
  × No solution found when resolving dependencies:
  ╰─▶ Because the requested Python version (3.12) does not satisfy Python>=3.6,<3.10 and recommenders==1.0.0 depends on Python>=3.6,<3.9, we can conclude that recommenders==1.0.0 cannot be used.
      And because only the following versions of recommenders are available:
          recommenders<=0.7
          recommenders==1.0.0
          recommenders==1.1.0
          recommenders==1.1.1
      we can conclude that recommenders>0.7,<1.1.0 cannot be used. (1)

      Because the requested Python version (3.12) does not satisfy Python>=3.6,<3.10 and recommenders>=1.1.0 depends on Python>=3.6,<3.10, we can conclude that recommenders>=1.1.0 cannot be used.
      And because we know from (1) that recommenders>0.7,<1.1.0 cannot be used, we can conclude that recommenders>0.7 cannot be used.
      And because you require recommenders>0.7, we can conclude that the requirements are unsatisfiable.
```
This commit is contained in:
Zanie Blue 2024-02-02 12:00:25 -06:00 committed by GitHub
parent e3c1586310
commit 6db9db0079
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 53 additions and 42 deletions

View file

@ -82,16 +82,18 @@ impl ReportFormatter<PubGrubPackage, Range<Version>> for PubGrubReportFormatter<
} else {
let complement = set.complement();
let segments = complement.iter().collect::<Vec<_>>().len();
// Simple case, there's a single range to report
if segments == 1 {
format!(
"only {} is available",
PackageRange::compatibility(package, &complement)
)
// Complex case, there are multiple ranges
} else {
format!(
"there are no versions of {} that satisfy {}",
"only the following versions of {} {}",
package,
PackageRange::compatibility(package, &set)
PackageRange::available(package, &complement)
)
}
}
@ -485,6 +487,7 @@ impl PackageTerm<'_> {
enum PackageRangeKind {
Dependency,
Compatibility,
Available,
}
/// A [`Range`] and [`PubGrubPackage`] combination for display.
@ -520,6 +523,7 @@ impl std::fmt::Display for PackageRange<'_> {
match self.kind {
PackageRangeKind::Dependency => write!(f, "one of:")?,
PackageRangeKind::Compatibility => write!(f, "any of:")?,
PackageRangeKind::Available => write!(f, "are available:")?,
}
}
for segment in &segments {
@ -531,6 +535,7 @@ impl std::fmt::Display for PackageRange<'_> {
(Bound::Unbounded, Bound::Unbounded) => match self.kind {
PackageRangeKind::Dependency => write!(f, "{package}")?,
PackageRangeKind::Compatibility => write!(f, "all versions of {package}")?,
PackageRangeKind::Available => write!(f, "{package}")?,
},
(Bound::Unbounded, Bound::Included(v)) => write!(f, "{package}<={v}")?,
(Bound::Unbounded, Bound::Excluded(v)) => write!(f, "{package}<{v}")?,
@ -576,6 +581,13 @@ impl PackageRange<'_> {
}
}
fn available<'a>(package: &'a PubGrubPackage, range: &'a Range<Version>) -> PackageRange<'a> {
PackageRange {
package,
range,
kind: PackageRangeKind::Available,
}
}
fn depends_on<'a>(
&'a self,
package: &'a PubGrubPackage,

View file

@ -1743,16 +1743,18 @@ fn compile_yanked_version_indirect() -> Result<()> {
puffin_snapshot!(context.compile()
.arg("requirements.in"), @r###"
success: false
exit_code: 1
----- stdout -----
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
Because there are no versions of attrs that satisfy attrs>20.3.0,<21.2.0
and you require attrs>20.3.0,<21.2.0, we can conclude that the
requirements are unsatisfiable.
"###
----- stderr -----
× No solution found when resolving dependencies:
Because only the following versions of attrs are available:
attrs<=20.3.0
attrs>=21.2.0
and you require attrs>20.3.0,<21.2.0, we can conclude that the
requirements are unsatisfiable.
"###
);
Ok(())

View file

@ -375,10 +375,9 @@ fn requires_incompatible_python_version_compatible_override_other_wheel() -> Res
warning: The requested Python version 3.11 is not available; 3.9.18 will be used to build dependencies instead.
× No solution found when resolving dependencies:
Because the current Python version (3.9.18) does not satisfy Python>=3.10 and albatross==1.0.0 depends on Python>=3.10, we can conclude that albatross==1.0.0 cannot be used.
And because there are no versions of albatross that satisfy any of:
albatross<1.0.0
albatross>1.0.0,<2.0.0
albatross>2.0.0
And because only the following versions of albatross are available:
albatross==1.0.0
albatross==2.0.0
we can conclude that albatross<2.0.0 cannot be used. (1)
Because the requested Python version (3.11) does not satisfy Python>=3.12 and albatross==2.0.0 depends on Python>=3.12, we can conclude that albatross==2.0.0 cannot be used.

View file

@ -340,11 +340,10 @@ fn excluded_only_compatible_version() {
----- stderr -----
× No solution found when resolving dependencies:
Because there are no versions of albatross that satisfy any of:
albatross<1.0.0
albatross>1.0.0,<2.0.0
albatross>2.0.0,<3.0.0
albatross>3.0.0
Because only the following versions of albatross are available:
albatross==1.0.0
albatross==2.0.0
albatross==3.0.0
and albatross==1.0.0 depends on bluebird==1.0.0, we can conclude that albatross<2.0.0 depends on bluebird==1.0.0.
And because albatross==3.0.0 depends on bluebird==3.0.0, we can conclude that any of:
albatross<2.0.0
@ -441,15 +440,14 @@ fn dependency_excludes_range_of_compatible_versions() {
----- stderr -----
× No solution found when resolving dependencies:
Because there are no versions of crow that satisfy any of:
crow<1.0.0
crow>1.0.0,<2.0.0
crow>2.0.0
Because only the following versions of crow are available:
crow==1.0.0
crow==2.0.0
and crow==1.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on albatross<2.0.0. (1)
Because there are no versions of albatross that satisfy any of:
albatross<1.0.0
albatross>1.0.0,<2.0.0
Because only the following versions of albatross are available:
albatross==1.0.0
albatross>=2.0.0
and albatross==1.0.0 depends on bluebird==1.0.0, we can conclude that albatross<2.0.0 depends on bluebird==1.0.0.
And because we know from (1) that crow<2.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on bluebird==1.0.0.
And because crow==2.0.0 depends on albatross>=3.0.0, we can conclude that all versions of crow, bluebird!=1.0.0, albatross<3.0.0 are incompatible. (2)
@ -556,15 +554,14 @@ fn dependency_excludes_non_contiguous_range_of_compatible_versions() {
----- stderr -----
× No solution found when resolving dependencies:
Because there are no versions of crow that satisfy any of:
crow<1.0.0
crow>1.0.0,<2.0.0
crow>2.0.0
Because only the following versions of crow are available:
crow==1.0.0
crow==2.0.0
and crow==1.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on albatross<2.0.0. (1)
Because there are no versions of albatross that satisfy any of:
albatross<1.0.0
albatross>1.0.0,<2.0.0
Because only the following versions of albatross are available:
albatross==1.0.0
albatross>=2.0.0
and albatross==1.0.0 depends on bluebird==1.0.0, we can conclude that albatross<2.0.0 depends on bluebird==1.0.0.
And because we know from (1) that crow<2.0.0 depends on albatross<2.0.0, we can conclude that crow<2.0.0 depends on bluebird==1.0.0.
And because crow==2.0.0 depends on albatross>=3.0.0, we can conclude that all versions of crow, bluebird!=1.0.0, albatross<3.0.0 are incompatible. (2)
@ -1938,10 +1935,11 @@ fn transitive_prerelease_and_stable_dependency_many_versions_holes() {
----- stderr -----
× No solution found when resolving dependencies:
Because there are no versions of crow that satisfy any of:
crow>1.0.0,<2.0.0a5
crow>2.0.0a7,<2.0.0b1
crow>2.0.0b1,<2.0.0b5
Because only the following versions of crow are available:
crow<=1.0.0
crow>=2.0.0a5,<=2.0.0a7
crow==2.0.0b1
crow>=2.0.0b5
and albatross==1.0.0 depends on one of:
crow>1.0.0,<2.0.0a5
crow>2.0.0a7,<2.0.0b1
@ -2282,10 +2280,10 @@ fn requires_python_version_greater_than_current_excluded() {
Python>=3.12
are incompatible.
And because the current Python version (3.9.18) does not satisfy Python>=3.11,<3.12, we can conclude that Python>=3.10 are incompatible.
And because albatross==2.0.0 depends on Python>=3.10 and there are no versions of albatross that satisfy any of:
albatross>2.0.0,<3.0.0
albatross>3.0.0,<4.0.0
albatross>4.0.0
And because albatross==2.0.0 depends on Python>=3.10 and only the following versions of albatross are available:
albatross<=2.0.0
albatross==3.0.0
albatross==4.0.0
we can conclude that albatross>=2.0.0,<3.0.0 cannot be used. (1)
Because the current Python version (3.9.18) does not satisfy Python>=3.11,<3.12 and the current Python version (3.9.18) does not satisfy Python>=3.12, we can conclude that Python>=3.11 are incompatible.