mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-10-31 12:06:13 +00:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									05cceee523
								
							
						
					
					
						commit
						ea636bbe61
					
				
					 5 changed files with 24 additions and 46 deletions
				
			
		|  | @ -120,7 +120,7 @@ pub(crate) type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, Unava | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct NoSolutionError { | pub struct NoSolutionError { | ||||||
|     error: pubgrub::NoSolutionError<UvDependencyProvider>, |     error: pubgrub::NoSolutionError<UvDependencyProvider>, | ||||||
|     available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>, |     available_versions: FxHashMap<PackageName, BTreeSet<Version>>, | ||||||
|     selector: CandidateSelector, |     selector: CandidateSelector, | ||||||
|     python_requirement: PythonRequirement, |     python_requirement: PythonRequirement, | ||||||
|     index_locations: IndexLocations, |     index_locations: IndexLocations, | ||||||
|  | @ -135,7 +135,7 @@ impl NoSolutionError { | ||||||
|     /// Create a new [`NoSolutionError`] from a [`pubgrub::NoSolutionError`].
 |     /// Create a new [`NoSolutionError`] from a [`pubgrub::NoSolutionError`].
 | ||||||
|     pub(crate) fn new( |     pub(crate) fn new( | ||||||
|         error: pubgrub::NoSolutionError<UvDependencyProvider>, |         error: pubgrub::NoSolutionError<UvDependencyProvider>, | ||||||
|         available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>, |         available_versions: FxHashMap<PackageName, BTreeSet<Version>>, | ||||||
|         selector: CandidateSelector, |         selector: CandidateSelector, | ||||||
|         python_requirement: PythonRequirement, |         python_requirement: PythonRequirement, | ||||||
|         index_locations: IndexLocations, |         index_locations: IndexLocations, | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ use super::{PubGrubPackage, PubGrubPackageInner, PubGrubPython}; | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub(crate) struct PubGrubReportFormatter<'a> { | pub(crate) struct PubGrubReportFormatter<'a> { | ||||||
|     /// The versions that were available for each package
 |     /// 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
 |     /// The versions that were available for each package
 | ||||||
|     pub(crate) python_requirement: &'a PythonRequirement, |     pub(crate) python_requirement: &'a PythonRequirement, | ||||||
|  | @ -87,7 +87,7 @@ impl ReportFormatter<PubGrubPackage, Range<Version>, UnavailableReason> | ||||||
|                         // Note that sometimes we do not have a range of available versions, e.g.,
 |                         // 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
 |                         // when a package is from a non-registry source. In that case, we cannot
 | ||||||
|                         // perform further simplicifaction of the range.
 |                         // 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) |                             update_availability_range(&complement, available_versions) | ||||||
|                         } else { |                         } else { | ||||||
|                             complement |                             complement | ||||||
|  | @ -484,10 +484,13 @@ impl PubGrubReportFormatter<'_> { | ||||||
|         set: &'a Range<Version>, |         set: &'a Range<Version>, | ||||||
|         package: &PubGrubPackage, |         package: &PubGrubPackage, | ||||||
|     ) -> Cow<'a, Range<Version>> { |     ) -> Cow<'a, Range<Version>> { | ||||||
|  |         let Some(name) = package.name() else { | ||||||
|  |             return Cow::Borrowed(set); | ||||||
|  |         }; | ||||||
|         if set == &Range::full() { |         if set == &Range::full() { | ||||||
|             Cow::Borrowed(set) |             Cow::Borrowed(set) | ||||||
|         } else { |         } 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(), |                     range: self.simplify_set(set, package).into_owned(), | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         } else if let Some(version) = self.available_versions.get(package).and_then(|versions| { |         } else if let Some(version) = package | ||||||
|             versions |             .name() | ||||||
|                 .iter() |             .and_then(|name| self.available_versions.get(name)) | ||||||
|                 .rev() |             .and_then(|versions| { | ||||||
|                 .filter(|version| version.any_prerelease()) |                 versions | ||||||
|                 .find(|version| set.contains(version)) |                     .iter() | ||||||
|         }) { |                     .rev() | ||||||
|  |                     .filter(|version| version.any_prerelease()) | ||||||
|  |                     .find(|version| set.contains(version)) | ||||||
|  |             }) | ||||||
|  |         { | ||||||
|             // There are pre-release versions available for the package.
 |             // There are pre-release versions available for the package.
 | ||||||
|             if selector.prerelease_strategy().allows(name, markers) != AllowPrerelease::Yes { |             if selector.prerelease_strategy().allows(name, markers) != AllowPrerelease::Yes { | ||||||
|                 hints.insert(PubGrubHint::PrereleaseAvailable { |                 hints.insert(PubGrubHint::PrereleaseAvailable { | ||||||
|  |  | ||||||
|  | @ -1963,9 +1963,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag | ||||||
| 
 | 
 | ||||||
|         let mut available_versions = FxHashMap::default(); |         let mut available_versions = FxHashMap::default(); | ||||||
|         for package in err.packages() { |         for package in err.packages() { | ||||||
|             let PubGrubPackageInner::Package { name, .. } = &**package else { |             let Some(name) = package.name() else { continue }; | ||||||
|                 continue; |  | ||||||
|             }; |  | ||||||
|             if !visited.contains(name) { |             if !visited.contains(name) { | ||||||
|                 // Avoid including available versions for packages that exist in the derivation
 |                 // Avoid including available versions for packages that exist in the derivation
 | ||||||
|                 // tree, but were never visited during resolution. We _may_ have metadata for
 |                 // tree, but were never visited during resolution. We _may_ have metadata for
 | ||||||
|  | @ -1977,7 +1975,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag | ||||||
|                 if let VersionsResponse::Found(ref version_maps) = *response { |                 if let VersionsResponse::Found(ref version_maps) = *response { | ||||||
|                     for version_map in version_maps { |                     for version_map in version_maps { | ||||||
|                         available_versions |                         available_versions | ||||||
|                             .entry(package.clone()) |                             .entry(name.clone()) | ||||||
|                             .or_insert_with(BTreeSet::new) |                             .or_insert_with(BTreeSet::new) | ||||||
|                             .extend(version_map.iter().map(|(version, _)| version.clone())); |                             .extend(version_map.iter().map(|(version, _)| version.clone())); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  | @ -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 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: |           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'}==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. |           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. |       ╰─▶ 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: |           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'}==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 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. |           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. | ||||||
|     "###
 |     "###
 | ||||||
|  |  | ||||||
|  | @ -7993,34 +7993,7 @@ fn universal_requires_python_incomplete() -> Result<()> { | ||||||
|     ----- stderr ----- |     ----- stderr ----- | ||||||
|     warning: The requested Python version 3.7 is not available; 3.12.[X] will be used to build dependencies instead. |     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: |       × No solution found when resolving dependencies: | ||||||
|       ╰─▶ Because only the following versions of uv{python_full_version >= '3.8'} are available: |       ╰─▶ 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. | ||||||
|               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. |  | ||||||
|           And because you require uv{python_full_version >= '3.8'}, we can conclude that your requirements are unsatisfiable. |           And because you require uv{python_full_version >= '3.8'}, we can conclude that your requirements are unsatisfiable. | ||||||
|     "###
 |     "###
 | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zanie Blue
						Zanie Blue