mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 10:58:28 +00:00
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:
parent
bbd961c251
commit
5269a0dba8
14 changed files with 42 additions and 40 deletions
|
@ -162,7 +162,7 @@ mod resolver {
|
||||||
Options::default(),
|
Options::default(),
|
||||||
&python_requirement,
|
&python_requirement,
|
||||||
Some(&MARKERS),
|
Some(&MARKERS),
|
||||||
&TAGS,
|
Some(&TAGS),
|
||||||
&flat_index,
|
&flat_index,
|
||||||
&index,
|
&index,
|
||||||
&hashes,
|
&hashes,
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub enum CompatibleDist<'a> {
|
||||||
/// The wheel that should be used.
|
/// The wheel that should be used.
|
||||||
wheel: &'a RegistryBuiltWheel,
|
wheel: &'a RegistryBuiltWheel,
|
||||||
/// The platform priority associated with the wheel.
|
/// The platform priority associated with the wheel.
|
||||||
priority: TagPriority,
|
priority: Option<TagPriority>,
|
||||||
/// The prioritized distribution that the wheel came from.
|
/// The prioritized distribution that the wheel came from.
|
||||||
prioritized: &'a PrioritizedDist,
|
prioritized: &'a PrioritizedDist,
|
||||||
},
|
},
|
||||||
|
@ -145,7 +145,7 @@ pub enum PythonRequirementKind {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum WheelCompatibility {
|
pub enum WheelCompatibility {
|
||||||
Incompatible(IncompatibleWheel),
|
Incompatible(IncompatibleWheel),
|
||||||
Compatible(HashComparison, TagPriority, Option<BuildTag>),
|
Compatible(HashComparison, Option<TagPriority>, Option<BuildTag>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
|
|
@ -158,7 +158,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
|
||||||
self.options,
|
self.options,
|
||||||
&python_requirement,
|
&python_requirement,
|
||||||
Some(markers),
|
Some(markers),
|
||||||
tags,
|
Some(tags),
|
||||||
self.flat_index,
|
self.flat_index,
|
||||||
self.index,
|
self.index,
|
||||||
&HashStrategy::None,
|
&HashStrategy::None,
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl FlatIndex {
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub fn from_entries(
|
pub fn from_entries(
|
||||||
entries: FlatIndexEntries,
|
entries: FlatIndexEntries,
|
||||||
tags: &Tags,
|
tags: Option<&Tags>,
|
||||||
hasher: &HashStrategy,
|
hasher: &HashStrategy,
|
||||||
no_build: &NoBuild,
|
no_build: &NoBuild,
|
||||||
no_binary: &NoBinary,
|
no_binary: &NoBinary,
|
||||||
|
@ -66,7 +66,7 @@ impl FlatIndex {
|
||||||
distributions: &mut FlatDistributions,
|
distributions: &mut FlatDistributions,
|
||||||
file: File,
|
file: File,
|
||||||
filename: DistFilename,
|
filename: DistFilename,
|
||||||
tags: &Tags,
|
tags: Option<&Tags>,
|
||||||
hasher: &HashStrategy,
|
hasher: &HashStrategy,
|
||||||
no_build: &NoBuild,
|
no_build: &NoBuild,
|
||||||
no_binary: &NoBinary,
|
no_binary: &NoBinary,
|
||||||
|
@ -152,7 +152,7 @@ impl FlatIndex {
|
||||||
fn wheel_compatibility(
|
fn wheel_compatibility(
|
||||||
filename: &WheelFilename,
|
filename: &WheelFilename,
|
||||||
hashes: &[HashDigest],
|
hashes: &[HashDigest],
|
||||||
tags: &Tags,
|
tags: Option<&Tags>,
|
||||||
hasher: &HashStrategy,
|
hasher: &HashStrategy,
|
||||||
no_binary: &NoBinary,
|
no_binary: &NoBinary,
|
||||||
) -> WheelCompatibility {
|
) -> WheelCompatibility {
|
||||||
|
@ -168,11 +168,14 @@ impl FlatIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine a compatibility for the wheel based on tags.
|
// Determine a compatibility for the wheel based on tags.
|
||||||
let priority = match filename.compatibility(tags) {
|
let priority = match tags {
|
||||||
TagCompatibility::Incompatible(tag) => {
|
Some(tags) => match filename.compatibility(tags) {
|
||||||
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
|
TagCompatibility::Incompatible(tag) => {
|
||||||
}
|
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
|
||||||
TagCompatibility::Compatible(priority) => priority,
|
}
|
||||||
|
TagCompatibility::Compatible(priority) => Some(priority),
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if hashes line up.
|
// Check if hashes line up.
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl<'a, Context: BuildContext, InstalledPackages: InstalledPackagesProvider>
|
||||||
options: Options,
|
options: Options,
|
||||||
python_requirement: &'a PythonRequirement,
|
python_requirement: &'a PythonRequirement,
|
||||||
markers: Option<&'a MarkerEnvironment>,
|
markers: Option<&'a MarkerEnvironment>,
|
||||||
tags: &'a Tags,
|
tags: Option<&'a Tags>,
|
||||||
flat_index: &'a FlatIndex,
|
flat_index: &'a FlatIndex,
|
||||||
index: &'a InMemoryIndex,
|
index: &'a InMemoryIndex,
|
||||||
hasher: &'a HashStrategy,
|
hasher: &'a HashStrategy,
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub struct DefaultResolverProvider<'a, Context: BuildContext> {
|
||||||
fetcher: DistributionDatabase<'a, Context>,
|
fetcher: DistributionDatabase<'a, Context>,
|
||||||
/// These are the entries from `--find-links` that act as overrides for index responses.
|
/// These are the entries from `--find-links` that act as overrides for index responses.
|
||||||
flat_index: FlatIndex,
|
flat_index: FlatIndex,
|
||||||
tags: Tags,
|
tags: Option<Tags>,
|
||||||
python_requirement: PythonRequirement,
|
python_requirement: PythonRequirement,
|
||||||
allowed_yanks: AllowedYanks,
|
allowed_yanks: AllowedYanks,
|
||||||
hasher: HashStrategy,
|
hasher: HashStrategy,
|
||||||
|
@ -89,7 +89,7 @@ impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
fetcher: DistributionDatabase<'a, Context>,
|
fetcher: DistributionDatabase<'a, Context>,
|
||||||
flat_index: &'a FlatIndex,
|
flat_index: &'a FlatIndex,
|
||||||
tags: &'a Tags,
|
tags: Option<&'a Tags>,
|
||||||
python_requirement: PythonRequirement,
|
python_requirement: PythonRequirement,
|
||||||
allowed_yanks: AllowedYanks,
|
allowed_yanks: AllowedYanks,
|
||||||
hasher: &'a HashStrategy,
|
hasher: &'a HashStrategy,
|
||||||
|
@ -100,7 +100,7 @@ impl<'a, Context: BuildContext> DefaultResolverProvider<'a, Context> {
|
||||||
Self {
|
Self {
|
||||||
fetcher,
|
fetcher,
|
||||||
flat_index: flat_index.clone(),
|
flat_index: flat_index.clone(),
|
||||||
tags: tags.clone(),
|
tags: tags.cloned(),
|
||||||
python_requirement,
|
python_requirement,
|
||||||
allowed_yanks,
|
allowed_yanks,
|
||||||
hasher: hasher.clone(),
|
hasher: hasher.clone(),
|
||||||
|
@ -132,7 +132,7 @@ impl<'a, Context: BuildContext> ResolverProvider for DefaultResolverProvider<'a,
|
||||||
metadata,
|
metadata,
|
||||||
package_name,
|
package_name,
|
||||||
&index,
|
&index,
|
||||||
&self.tags,
|
self.tags.as_ref(),
|
||||||
&self.python_requirement,
|
&self.python_requirement,
|
||||||
&self.allowed_yanks,
|
&self.allowed_yanks,
|
||||||
&self.hasher,
|
&self.hasher,
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl VersionMap {
|
||||||
simple_metadata: OwnedArchive<SimpleMetadata>,
|
simple_metadata: OwnedArchive<SimpleMetadata>,
|
||||||
package_name: &PackageName,
|
package_name: &PackageName,
|
||||||
index: &IndexUrl,
|
index: &IndexUrl,
|
||||||
tags: &Tags,
|
tags: Option<&Tags>,
|
||||||
python_requirement: &PythonRequirement,
|
python_requirement: &PythonRequirement,
|
||||||
allowed_yanks: &AllowedYanks,
|
allowed_yanks: &AllowedYanks,
|
||||||
hasher: &HashStrategy,
|
hasher: &HashStrategy,
|
||||||
|
@ -120,7 +120,7 @@ impl VersionMap {
|
||||||
no_binary,
|
no_binary,
|
||||||
no_build,
|
no_build,
|
||||||
index: index.clone(),
|
index: index.clone(),
|
||||||
tags: tags.clone(),
|
tags: tags.cloned(),
|
||||||
python_requirement: python_requirement.clone(),
|
python_requirement: python_requirement.clone(),
|
||||||
exclude_newer: exclude_newer.copied(),
|
exclude_newer: exclude_newer.copied(),
|
||||||
allowed_yanks,
|
allowed_yanks,
|
||||||
|
@ -298,7 +298,7 @@ struct VersionMapLazy {
|
||||||
index: IndexUrl,
|
index: IndexUrl,
|
||||||
/// The set of compatibility tags that determines whether a wheel is usable
|
/// The set of compatibility tags that determines whether a wheel is usable
|
||||||
/// in the current environment.
|
/// in the current environment.
|
||||||
tags: Tags,
|
tags: Option<Tags>,
|
||||||
/// The version of Python active in the current environment. This is used
|
/// The version of Python active in the current environment. This is used
|
||||||
/// to determine whether a package's Python version constraint (if one
|
/// to determine whether a package's Python version constraint (if one
|
||||||
/// exists) is satisfied or not.
|
/// exists) is satisfied or not.
|
||||||
|
@ -551,11 +551,14 @@ impl VersionMapLazy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine a compatibility for the wheel based on tags.
|
// Determine a compatibility for the wheel based on tags.
|
||||||
let priority = match filename.compatibility(&self.tags) {
|
let priority = match &self.tags {
|
||||||
TagCompatibility::Incompatible(tag) => {
|
Some(tags) => match filename.compatibility(tags) {
|
||||||
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
|
TagCompatibility::Incompatible(tag) => {
|
||||||
}
|
return WheelCompatibility::Incompatible(IncompatibleWheel::Tag(tag))
|
||||||
TagCompatibility::Compatible(priority) => priority,
|
}
|
||||||
|
TagCompatibility::Compatible(priority) => Some(priority),
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if hashes line up. If hashes aren't required, they're considered matching.
|
// Check if hashes line up. If hashes aren't required, they're considered matching.
|
||||||
|
|
|
@ -291,7 +291,7 @@ pub(crate) async fn pip_compile(
|
||||||
let flat_index = {
|
let flat_index = {
|
||||||
let client = FlatIndexClient::new(&client, &cache);
|
let client = FlatIndexClient::new(&client, &cache);
|
||||||
let entries = client.fetch(index_locations.flat_index()).await?;
|
let entries = client.fetch(index_locations.flat_index()).await?;
|
||||||
FlatIndex::from_entries(entries, &tags, &hasher, &no_build, &NoBinary::None)
|
FlatIndex::from_entries(entries, Some(&tags), &hasher, &no_build, &NoBinary::None)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Track in-flight downloads, builds, etc., across resolutions.
|
// Track in-flight downloads, builds, etc., across resolutions.
|
||||||
|
@ -509,7 +509,7 @@ pub(crate) async fn pip_compile(
|
||||||
options,
|
options,
|
||||||
&python_requirement,
|
&python_requirement,
|
||||||
Some(&markers),
|
Some(&markers),
|
||||||
&tags,
|
Some(&tags),
|
||||||
&flat_index,
|
&flat_index,
|
||||||
&top_level_index,
|
&top_level_index,
|
||||||
&hasher,
|
&hasher,
|
||||||
|
|
|
@ -302,7 +302,7 @@ pub(crate) async fn pip_install(
|
||||||
let flat_index = {
|
let flat_index = {
|
||||||
let client = FlatIndexClient::new(&client, &cache);
|
let client = FlatIndexClient::new(&client, &cache);
|
||||||
let entries = client.fetch(index_locations.flat_index()).await?;
|
let entries = client.fetch(index_locations.flat_index()).await?;
|
||||||
FlatIndex::from_entries(entries, &tags, &hasher, &no_build, &no_binary)
|
FlatIndex::from_entries(entries, Some(&tags), &hasher, &no_build, &no_binary)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine whether to enable build isolation.
|
// Determine whether to enable build isolation.
|
||||||
|
@ -366,7 +366,7 @@ pub(crate) async fn pip_install(
|
||||||
&reinstall,
|
&reinstall,
|
||||||
&upgrade,
|
&upgrade,
|
||||||
interpreter,
|
interpreter,
|
||||||
&tags,
|
Some(&tags),
|
||||||
Some(&markers),
|
Some(&markers),
|
||||||
None,
|
None,
|
||||||
&client,
|
&client,
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
|
||||||
reinstall: &Reinstall,
|
reinstall: &Reinstall,
|
||||||
upgrade: &Upgrade,
|
upgrade: &Upgrade,
|
||||||
interpreter: &Interpreter,
|
interpreter: &Interpreter,
|
||||||
tags: &Tags,
|
tags: Option<&Tags>,
|
||||||
markers: Option<&MarkerEnvironment>,
|
markers: Option<&MarkerEnvironment>,
|
||||||
requires_python: Option<&RequiresPython>,
|
requires_python: Option<&RequiresPython>,
|
||||||
client: &RegistryClient,
|
client: &RegistryClient,
|
||||||
|
|
|
@ -245,7 +245,7 @@ pub(crate) async fn pip_sync(
|
||||||
let flat_index = {
|
let flat_index = {
|
||||||
let client = FlatIndexClient::new(&client, &cache);
|
let client = FlatIndexClient::new(&client, &cache);
|
||||||
let entries = client.fetch(index_locations.flat_index()).await?;
|
let entries = client.fetch(index_locations.flat_index()).await?;
|
||||||
FlatIndex::from_entries(entries, &tags, &hasher, &no_build, &no_binary)
|
FlatIndex::from_entries(entries, Some(&tags), &hasher, &no_build, &no_binary)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine whether to enable build isolation.
|
// Determine whether to enable build isolation.
|
||||||
|
@ -318,7 +318,7 @@ pub(crate) async fn pip_sync(
|
||||||
reinstall,
|
reinstall,
|
||||||
&upgrade,
|
&upgrade,
|
||||||
interpreter,
|
interpreter,
|
||||||
&tags,
|
Some(&tags),
|
||||||
Some(&markers),
|
Some(&markers),
|
||||||
None,
|
None,
|
||||||
&client,
|
&client,
|
||||||
|
|
|
@ -138,15 +138,11 @@ pub(super) async fn do_lock(
|
||||||
requires_python
|
requires_python
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine the tags and markers to use for resolution.
|
|
||||||
let tags = interpreter.tags()?;
|
|
||||||
let markers = interpreter.markers();
|
|
||||||
|
|
||||||
// Initialize the registry client.
|
// Initialize the registry client.
|
||||||
// TODO(zanieb): Support client options e.g. offline, tls, etc.
|
// TODO(zanieb): Support client options e.g. offline, tls, etc.
|
||||||
let client = RegistryClientBuilder::new(cache.clone())
|
let client = RegistryClientBuilder::new(cache.clone())
|
||||||
.index_urls(index_locations.index_urls())
|
.index_urls(index_locations.index_urls())
|
||||||
.markers(markers)
|
.markers(interpreter.markers())
|
||||||
.platform(interpreter.platform())
|
.platform(interpreter.platform())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -214,7 +210,7 @@ pub(super) async fn do_lock(
|
||||||
&reinstall,
|
&reinstall,
|
||||||
&upgrade,
|
&upgrade,
|
||||||
interpreter,
|
interpreter,
|
||||||
tags,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(&requires_python),
|
Some(&requires_python),
|
||||||
&client,
|
&client,
|
||||||
|
|
|
@ -233,7 +233,7 @@ pub(crate) async fn update_environment(
|
||||||
&reinstall,
|
&reinstall,
|
||||||
&upgrade,
|
&upgrade,
|
||||||
interpreter,
|
interpreter,
|
||||||
tags,
|
Some(tags),
|
||||||
Some(markers),
|
Some(markers),
|
||||||
None,
|
None,
|
||||||
&client,
|
&client,
|
||||||
|
|
|
@ -180,7 +180,7 @@ async fn venv_impl(
|
||||||
.map_err(VenvError::FlatIndex)?;
|
.map_err(VenvError::FlatIndex)?;
|
||||||
FlatIndex::from_entries(
|
FlatIndex::from_entries(
|
||||||
entries,
|
entries,
|
||||||
tags,
|
Some(tags),
|
||||||
&HashStrategy::None,
|
&HashStrategy::None,
|
||||||
&NoBuild::All,
|
&NoBuild::All,
|
||||||
&NoBinary::None,
|
&NoBinary::None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue