Skip to content

Commit ea636bb

Browse files
authored
Simplify available package version ranges when the name includes markers 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
1 parent 05cceee commit ea636bb

File tree

5 files changed

+24
-46
lines changed

5 files changed

+24
-46
lines changed

crates/uv-resolver/src/error.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub(crate) type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, Unava
120120
#[derive(Debug)]
121121
pub struct NoSolutionError {
122122
error: pubgrub::NoSolutionError<UvDependencyProvider>,
123-
available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>,
123+
available_versions: FxHashMap<PackageName, BTreeSet<Version>>,
124124
selector: CandidateSelector,
125125
python_requirement: PythonRequirement,
126126
index_locations: IndexLocations,
@@ -135,7 +135,7 @@ impl NoSolutionError {
135135
/// Create a new [`NoSolutionError`] from a [`pubgrub::NoSolutionError`].
136136
pub(crate) fn new(
137137
error: pubgrub::NoSolutionError<UvDependencyProvider>,
138-
available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>,
138+
available_versions: FxHashMap<PackageName, BTreeSet<Version>>,
139139
selector: CandidateSelector,
140140
python_requirement: PythonRequirement,
141141
index_locations: IndexLocations,

crates/uv-resolver/src/pubgrub/report.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use super::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
2626
#[derive(Debug)]
2727
pub(crate) struct PubGrubReportFormatter<'a> {
2828
/// The versions that were available for each package
29-
pub(crate) available_versions: &'a FxHashMap<PubGrubPackage, BTreeSet<Version>>,
29+
pub(crate) available_versions: &'a FxHashMap<PackageName, BTreeSet<Version>>,
3030

3131
/// The versions that were available for each package
3232
pub(crate) python_requirement: &'a PythonRequirement,
@@ -87,7 +87,7 @@ impl ReportFormatter<PubGrubPackage, Range<Version>, UnavailableReason>
8787
// Note that sometimes we do not have a range of available versions, e.g.,
8888
// when a package is from a non-registry source. In that case, we cannot
8989
// perform further simplicifaction of the range.
90-
if let Some(available_versions) = self.available_versions.get(package) {
90+
if let Some(available_versions) = package.name().and_then(|name| self.available_versions.get(name)) {
9191
update_availability_range(&complement, available_versions)
9292
} else {
9393
complement
@@ -484,10 +484,13 @@ impl PubGrubReportFormatter<'_> {
484484
set: &'a Range<Version>,
485485
package: &PubGrubPackage,
486486
) -> Cow<'a, Range<Version>> {
487+
let Some(name) = package.name() else {
488+
return Cow::Borrowed(set);
489+
};
487490
if set == &Range::full() {
488491
Cow::Borrowed(set)
489492
} else {
490-
Cow::Owned(set.simplify(self.available_versions.get(package).into_iter().flatten()))
493+
Cow::Owned(set.simplify(self.available_versions.get(name).into_iter().flatten()))
491494
}
492495
}
493496

@@ -695,13 +698,17 @@ impl PubGrubReportFormatter<'_> {
695698
range: self.simplify_set(set, package).into_owned(),
696699
});
697700
}
698-
} else if let Some(version) = self.available_versions.get(package).and_then(|versions| {
699-
versions
700-
.iter()
701-
.rev()
702-
.filter(|version| version.any_prerelease())
703-
.find(|version| set.contains(version))
704-
}) {
701+
} else if let Some(version) = package
702+
.name()
703+
.and_then(|name| self.available_versions.get(name))
704+
.and_then(|versions| {
705+
versions
706+
.iter()
707+
.rev()
708+
.filter(|version| version.any_prerelease())
709+
.find(|version| set.contains(version))
710+
})
711+
{
705712
// There are pre-release versions available for the package.
706713
if selector.prerelease_strategy().allows(name, markers) != AllowPrerelease::Yes {
707714
hints.insert(PubGrubHint::PrereleaseAvailable {

crates/uv-resolver/src/resolver/mod.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1963,9 +1963,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
19631963

19641964
let mut available_versions = FxHashMap::default();
19651965
for package in err.packages() {
1966-
let PubGrubPackageInner::Package { name, .. } = &**package else {
1967-
continue;
1968-
};
1966+
let Some(name) = package.name() else { continue };
19691967
if !visited.contains(name) {
19701968
// Avoid including available versions for packages that exist in the derivation
19711969
// tree, but were never visited during resolution. We _may_ have metadata for
@@ -1977,7 +1975,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
19771975
if let VersionsResponse::Found(ref version_maps) = *response {
19781976
for version_map in version_maps {
19791977
available_versions
1980-
.entry(package.clone())
1978+
.entry(name.clone())
19811979
.or_insert_with(BTreeSet::new)
19821980
.extend(version_map.iter().map(|(version, _)| version.clone()));
19831981
}

crates/uv/tests/lock_scenarios.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ fn conflict_in_fork() -> Result<()> {
433433
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.
434434
And because only the following versions of package-a{sys_platform == 'darwin'} are available:
435435
package-a{sys_platform == 'darwin'}==1.0.0
436-
package-a{sys_platform == 'darwin'}>=2
436+
package-a{sys_platform == 'darwin'}>2
437437
and your project depends on package-a{sys_platform == 'darwin'}<2, we can conclude that your project's requirements are unsatisfiable.
438438
"###
439439
);
@@ -2875,7 +2875,7 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> {
28752875
╰─▶ 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.
28762876
And because only the following versions of package-c{sys_platform == 'linux'} are available:
28772877
package-c{sys_platform == 'linux'}==1.0.0
2878-
package-c{sys_platform == 'linux'}>=2.0.0
2878+
package-c{sys_platform == 'linux'}>2.0.0
28792879
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.
28802880
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.
28812881
"###

crates/uv/tests/pip_compile.rs

+1-28
Original file line numberDiff line numberDiff line change
@@ -7993,34 +7993,7 @@ fn universal_requires_python_incomplete() -> Result<()> {
79937993
----- stderr -----
79947994
warning: The requested Python version 3.7 is not available; 3.12.[X] will be used to build dependencies instead.
79957995
× No solution found when resolving dependencies:
7996-
╰─▶ Because only the following versions of uv{python_full_version >= '3.8'} are available:
7997-
uv{python_full_version >= '3.8'}==0.0.5
7998-
uv{python_full_version >= '3.8'}==0.1.0
7999-
uv{python_full_version >= '3.8'}==0.1.1
8000-
uv{python_full_version >= '3.8'}==0.1.2
8001-
uv{python_full_version >= '3.8'}==0.1.3
8002-
uv{python_full_version >= '3.8'}==0.1.4
8003-
uv{python_full_version >= '3.8'}==0.1.5
8004-
uv{python_full_version >= '3.8'}==0.1.6
8005-
uv{python_full_version >= '3.8'}==0.1.7
8006-
uv{python_full_version >= '3.8'}==0.1.8
8007-
uv{python_full_version >= '3.8'}==0.1.9
8008-
uv{python_full_version >= '3.8'}==0.1.10
8009-
uv{python_full_version >= '3.8'}==0.1.11
8010-
uv{python_full_version >= '3.8'}==0.1.12
8011-
uv{python_full_version >= '3.8'}==0.1.13
8012-
uv{python_full_version >= '3.8'}==0.1.14
8013-
uv{python_full_version >= '3.8'}==0.1.15
8014-
uv{python_full_version >= '3.8'}==0.1.16
8015-
uv{python_full_version >= '3.8'}==0.1.17
8016-
uv{python_full_version >= '3.8'}==0.1.18
8017-
uv{python_full_version >= '3.8'}==0.1.19
8018-
uv{python_full_version >= '3.8'}==0.1.20
8019-
uv{python_full_version >= '3.8'}==0.1.21
8020-
uv{python_full_version >= '3.8'}==0.1.22
8021-
uv{python_full_version >= '3.8'}==0.1.23
8022-
uv{python_full_version >= '3.8'}==0.1.24
8023-
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.
7996+
╰─▶ 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.
80247997
And because you require uv{python_full_version >= '3.8'}, we can conclude that your requirements are unsatisfiable.
80257998
"###
80267999
);

0 commit comments

Comments
 (0)