Ignore tags in universal resolution (#4174)

## Summary

If a package lacks a source distribution, and we can't find a compatible
wheel for the current platform, we need to just _assume_ that the
package will have a valid wheel on all platforms on which it's
requested; if not, we raise an error at install time.

It's possible that we can be smarter about this over time. For example,
if the package was requested _only_ for macOS, we could verify that
there's at least one macOS-compatible wheel. See the linked issue for
more details.

Closes https://github.com/astral-sh/uv/issues/4139.
This commit is contained in:
Charlie Marsh 2024-06-10 05:38:21 -07:00 committed by GitHub
parent bbd961c251
commit 5269a0dba8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 42 additions and 40 deletions

View file

@ -34,7 +34,7 @@ impl FlatIndex {
#[instrument(skip_all)]
pub fn from_entries(
entries: FlatIndexEntries,
tags: &Tags,
tags: Option<&Tags>,
hasher: &HashStrategy,
no_build: &NoBuild,
no_binary: &NoBinary,
@ -66,7 +66,7 @@ impl FlatIndex {
distributions: &mut FlatDistributions,
file: File,
filename: DistFilename,
tags: &Tags,
tags: Option<&Tags>,
hasher: &HashStrategy,
no_build: &NoBuild,
no_binary: &NoBinary,
@ -152,7 +152,7 @@ impl FlatIndex {
fn wheel_compatibility(
filename: &WheelFilename,
hashes: &[HashDigest],
tags: &Tags,
tags: Option<&Tags>,
hasher: &HashStrategy,
no_binary: &NoBinary,
) -> WheelCompatibility {
@ -168,11 +168,14 @@ impl FlatIndex {
}
// Determine a compatibility for the wheel based on tags.
let priority = match filename.compatibility(tags) {
TagCompatibility::Incompatible(tag) => {
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
}
TagCompatibility::Compatible(priority) => priority,
let priority = match tags {
Some(tags) => match filename.compatibility(tags) {
TagCompatibility::Incompatible(tag) => {
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
}
TagCompatibility::Compatible(priority) => Some(priority),
},
None => None,
};
// Check if hashes line up.

View file

@ -131,7 +131,7 @@ impl<'a, Context: BuildContext, InstalledPackages: InstalledPackagesProvider>
options: Options,
python_requirement: &'a PythonRequirement,
markers: Option<&'a MarkerEnvironment>,
tags: &'a Tags,
tags: Option<&'a Tags>,
flat_index: &'a FlatIndex,
index: &'a InMemoryIndex,
hasher: &'a HashStrategy,

View file

@ -74,7 +74,7 @@ pub struct DefaultResolverProvider<'a, Context: BuildContext> {
fetcher: DistributionDatabase<'a, Context>,
/// These are the entries from `--find-links` that act as overrides for index responses.
flat_index: FlatIndex,
tags: Tags,
tags: Option<Tags>,
python_requirement: PythonRequirement,
allowed_yanks: AllowedYanks,
hasher: HashStrategy,
@ -89,7 +89,7 @@ impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
pub fn new(
fetcher: DistributionDatabase<'a, Context>,
flat_index: &'a FlatIndex,
tags: &'a Tags,
tags: Option<&'a Tags>,
python_requirement: PythonRequirement,
allowed_yanks: AllowedYanks,
hasher: &'a HashStrategy,
@ -100,7 +100,7 @@ impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
Self {
fetcher,
flat_index: flat_index.clone(),
tags: tags.clone(),
tags: tags.cloned(),
python_requirement,
allowed_yanks,
hasher: hasher.clone(),
@ -132,7 +132,7 @@ impl<'a, Context: BuildContext> ResolverProvider for DefaultResolverProvider<'a,
metadata,
package_name,
&index,
&self.tags,
self.tags.as_ref(),
&self.python_requirement,
&self.allowed_yanks,
&self.hasher,

View file

@ -45,7 +45,7 @@ impl VersionMap {
simple_metadata: OwnedArchive<SimpleMetadata>,
package_name: &PackageName,
index: &IndexUrl,
tags: &Tags,
tags: Option<&Tags>,
python_requirement: &PythonRequirement,
allowed_yanks: &AllowedYanks,
hasher: &HashStrategy,
@ -120,7 +120,7 @@ impl VersionMap {
no_binary,
no_build,
index: index.clone(),
tags: tags.clone(),
tags: tags.cloned(),
python_requirement: python_requirement.clone(),
exclude_newer: exclude_newer.copied(),
allowed_yanks,
@ -298,7 +298,7 @@ struct VersionMapLazy {
index: IndexUrl,
/// The set of compatibility tags that determines whether a wheel is usable
/// in the current environment.
tags: Tags,
tags: Option<Tags>,
/// The version of Python active in the current environment. This is used
/// to determine whether a package's Python version constraint (if one
/// exists) is satisfied or not.
@ -551,11 +551,14 @@ impl VersionMapLazy {
}
// Determine a compatibility for the wheel based on tags.
let priority = match filename.compatibility(&self.tags) {
TagCompatibility::Incompatible(tag) => {
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
}
TagCompatibility::Compatible(priority) => priority,
let priority = match &self.tags {
Some(tags) => match filename.compatibility(tags) {
TagCompatibility::Incompatible(tag) => {
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
}
TagCompatibility::Compatible(priority) => Some(priority),
},
None => None,
};
// Check if hashes line up. If hashes aren't required, they're considered matching.