Skip to content

Commit

Permalink
Simplify available package version ranges when the name includes mark…
Browse files Browse the repository at this point in the history
…ers or extras (#6162)

There were different `PubGrubPackage` types so they never matched the
available versions set! Luckily, the available versions are agnostic to
the markers and optional dependencies so we can just broaden to using
`PackageName` as a lookup key.

Addresses yet another complaint in
#5046
  • Loading branch information
zanieb committed Aug 16, 2024
1 parent 05cceee commit ea636bb
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 46 deletions.
4 changes: 2 additions & 2 deletions crates/uv-resolver/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub(crate) type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, Unava
#[derive(Debug)]
pub struct NoSolutionError {
error: pubgrub::NoSolutionError<UvDependencyProvider>,
available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>,
available_versions: FxHashMap<PackageName, BTreeSet<Version>>,
selector: CandidateSelector,
python_requirement: PythonRequirement,
index_locations: IndexLocations,
Expand All @@ -135,7 +135,7 @@ impl NoSolutionError {
/// Create a new [`NoSolutionError`] from a [`pubgrub::NoSolutionError`].
pub(crate) fn new(
error: pubgrub::NoSolutionError<UvDependencyProvider>,
available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>,
available_versions: FxHashMap<PackageName, BTreeSet<Version>>,
selector: CandidateSelector,
python_requirement: PythonRequirement,
index_locations: IndexLocations,
Expand Down
27 changes: 17 additions & 10 deletions crates/uv-resolver/src/pubgrub/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use super::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
#[derive(Debug)]
pub(crate) struct PubGrubReportFormatter<'a> {
/// The versions that were available for each package
pub(crate) available_versions: &'a FxHashMap<PubGrubPackage, BTreeSet<Version>>,
pub(crate) available_versions: &'a FxHashMap<PackageName, BTreeSet<Version>>,

/// The versions that were available for each package
pub(crate) python_requirement: &'a PythonRequirement,
Expand Down Expand Up @@ -87,7 +87,7 @@ impl ReportFormatter<PubGrubPackage, Range<Version>, UnavailableReason>
// Note that sometimes we do not have a range of available versions, e.g.,
// when a package is from a non-registry source. In that case, we cannot
// perform further simplicifaction of the range.
if let Some(available_versions) = self.available_versions.get(package) {
if let Some(available_versions) = package.name().and_then(|name| self.available_versions.get(name)) {
update_availability_range(&complement, available_versions)
} else {
complement
Expand Down Expand Up @@ -484,10 +484,13 @@ impl PubGrubReportFormatter<'_> {
set: &'a Range<Version>,
package: &PubGrubPackage,
) -> Cow<'a, Range<Version>> {
let Some(name) = package.name() else {
return Cow::Borrowed(set);
};
if set == &Range::full() {
Cow::Borrowed(set)
} else {
Cow::Owned(set.simplify(self.available_versions.get(package).into_iter().flatten()))
Cow::Owned(set.simplify(self.available_versions.get(name).into_iter().flatten()))
}
}

Expand Down Expand Up @@ -695,13 +698,17 @@ impl PubGrubReportFormatter<'_> {
range: self.simplify_set(set, package).into_owned(),
});
}
} else if let Some(version) = self.available_versions.get(package).and_then(|versions| {
versions
.iter()
.rev()
.filter(|version| version.any_prerelease())
.find(|version| set.contains(version))
}) {
} else if let Some(version) = package
.name()
.and_then(|name| self.available_versions.get(name))
.and_then(|versions| {
versions
.iter()
.rev()
.filter(|version| version.any_prerelease())
.find(|version| set.contains(version))
})
{
// There are pre-release versions available for the package.
if selector.prerelease_strategy().allows(name, markers) != AllowPrerelease::Yes {
hints.insert(PubGrubHint::PrereleaseAvailable {
Expand Down
6 changes: 2 additions & 4 deletions crates/uv-resolver/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1963,9 +1963,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag

let mut available_versions = FxHashMap::default();
for package in err.packages() {
let PubGrubPackageInner::Package { name, .. } = &**package else {
continue;
};
let Some(name) = package.name() else { continue };
if !visited.contains(name) {
// Avoid including available versions for packages that exist in the derivation
// tree, but were never visited during resolution. We _may_ have metadata for
Expand All @@ -1977,7 +1975,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
if let VersionsResponse::Found(ref version_maps) = *response {
for version_map in version_maps {
available_versions
.entry(package.clone())
.entry(name.clone())
.or_insert_with(BTreeSet::new)
.extend(version_map.iter().map(|(version, _)| version.clone()));
}
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/tests/lock_scenarios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ fn conflict_in_fork() -> Result<()> {
And because package-a{sys_platform == 'darwin'}==1.0.0 depends on package-b and package-c, we can conclude that package-a{sys_platform == 'darwin'}==1.0.0 cannot be used.
And because only the following versions of package-a{sys_platform == 'darwin'} are available:
package-a{sys_platform == 'darwin'}==1.0.0
package-a{sys_platform == 'darwin'}>=2
package-a{sys_platform == 'darwin'}>2
and your project depends on package-a{sys_platform == 'darwin'}<2, we can conclude that your project's requirements are unsatisfiable.
"###
);
Expand Down Expand Up @@ -2875,7 +2875,7 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> {
╰─▶ Because package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}>=2.0.0 and only package-c{sys_platform == 'darwin'}<=2.0.0 is available, we can conclude that package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}==2.0.0.
And because only the following versions of package-c{sys_platform == 'linux'} are available:
package-c{sys_platform == 'linux'}==1.0.0
package-c{sys_platform == 'linux'}>=2.0.0
package-c{sys_platform == 'linux'}>2.0.0
and package-a==1.0.0 depends on package-c{sys_platform == 'linux'}<2.0.0, we can conclude that package-a==1.0.0 and package-b==1.0.0 are incompatible.
And because your project depends on package-a==1.0.0 and package-b==1.0.0, we can conclude that your project's requirements are unsatisfiable.
"###
Expand Down
29 changes: 1 addition & 28 deletions crates/uv/tests/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7993,34 +7993,7 @@ fn universal_requires_python_incomplete() -> Result<()> {
----- stderr -----
warning: The requested Python version 3.7 is not available; 3.12.[X] will be used to build dependencies instead.
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of uv{python_full_version >= '3.8'} are available:
uv{python_full_version >= '3.8'}==0.0.5
uv{python_full_version >= '3.8'}==0.1.0
uv{python_full_version >= '3.8'}==0.1.1
uv{python_full_version >= '3.8'}==0.1.2
uv{python_full_version >= '3.8'}==0.1.3
uv{python_full_version >= '3.8'}==0.1.4
uv{python_full_version >= '3.8'}==0.1.5
uv{python_full_version >= '3.8'}==0.1.6
uv{python_full_version >= '3.8'}==0.1.7
uv{python_full_version >= '3.8'}==0.1.8
uv{python_full_version >= '3.8'}==0.1.9
uv{python_full_version >= '3.8'}==0.1.10
uv{python_full_version >= '3.8'}==0.1.11
uv{python_full_version >= '3.8'}==0.1.12
uv{python_full_version >= '3.8'}==0.1.13
uv{python_full_version >= '3.8'}==0.1.14
uv{python_full_version >= '3.8'}==0.1.15
uv{python_full_version >= '3.8'}==0.1.16
uv{python_full_version >= '3.8'}==0.1.17
uv{python_full_version >= '3.8'}==0.1.18
uv{python_full_version >= '3.8'}==0.1.19
uv{python_full_version >= '3.8'}==0.1.20
uv{python_full_version >= '3.8'}==0.1.21
uv{python_full_version >= '3.8'}==0.1.22
uv{python_full_version >= '3.8'}==0.1.23
uv{python_full_version >= '3.8'}==0.1.24
and the requested Python version (>=3.7) does not satisfy Python>=3.8, we can conclude that all versions of uv{python_full_version >= '3.8'} are incompatible.
╰─▶ Because only uv{python_full_version >= '3.8'}<=0.1.24 is available and the requested Python version (>=3.7) does not satisfy Python>=3.8, we can conclude that all versions of uv{python_full_version >= '3.8'} are incompatible.
And because you require uv{python_full_version >= '3.8'}, we can conclude that your requirements are unsatisfiable.
"###
);
Expand Down

0 comments on commit ea636bb

Please sign in to comment.