From ea636bbe6163eb15a21c0950f6bd7dc6641b1449 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Fri, 16 Aug 2024 15:21:49 -0500 Subject: [PATCH] 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 https://github.com/astral-sh/uv/issues/5046 --- crates/uv-resolver/src/error.rs | 4 ++-- crates/uv-resolver/src/pubgrub/report.rs | 27 ++++++++++++++-------- crates/uv-resolver/src/resolver/mod.rs | 6 ++--- crates/uv/tests/lock_scenarios.rs | 4 ++-- crates/uv/tests/pip_compile.rs | 29 +----------------------- 5 files changed, 24 insertions(+), 46 deletions(-) diff --git a/crates/uv-resolver/src/error.rs b/crates/uv-resolver/src/error.rs index c7e7a5e58f40..1839becf056c 100644 --- a/crates/uv-resolver/src/error.rs +++ b/crates/uv-resolver/src/error.rs @@ -120,7 +120,7 @@ pub(crate) type ErrorTree = DerivationTree, Unava #[derive(Debug)] pub struct NoSolutionError { error: pubgrub::NoSolutionError, - available_versions: FxHashMap>, + available_versions: FxHashMap>, selector: CandidateSelector, python_requirement: PythonRequirement, index_locations: IndexLocations, @@ -135,7 +135,7 @@ impl NoSolutionError { /// Create a new [`NoSolutionError`] from a [`pubgrub::NoSolutionError`]. pub(crate) fn new( error: pubgrub::NoSolutionError, - available_versions: FxHashMap>, + available_versions: FxHashMap>, selector: CandidateSelector, python_requirement: PythonRequirement, index_locations: IndexLocations, diff --git a/crates/uv-resolver/src/pubgrub/report.rs b/crates/uv-resolver/src/pubgrub/report.rs index 4aafa5ba5b6d..b809ea9421cb 100644 --- a/crates/uv-resolver/src/pubgrub/report.rs +++ b/crates/uv-resolver/src/pubgrub/report.rs @@ -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>, + pub(crate) available_versions: &'a FxHashMap>, /// The versions that were available for each package pub(crate) python_requirement: &'a PythonRequirement, @@ -87,7 +87,7 @@ impl ReportFormatter, 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 @@ -484,10 +484,13 @@ impl PubGrubReportFormatter<'_> { set: &'a Range, package: &PubGrubPackage, ) -> Cow<'a, Range> { + 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())) } } @@ -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 { diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 3ceab47aab01..3bb311a004ec 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -1963,9 +1963,7 @@ impl ResolverState ResolverState 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. "### ); @@ -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. "### diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 99392ee61484..49d3ae0130de 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -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. "### );