diff --git a/crates/uv-build-backend/src/wheel.rs b/crates/uv-build-backend/src/wheel.rs index 38fa4bfea..806700665 100644 --- a/crates/uv-build-backend/src/wheel.rs +++ b/crates/uv-build-backend/src/wheel.rs @@ -10,7 +10,7 @@ use tracing::{debug, trace}; use walkdir::WalkDir; use zip::{CompressionMethod, ZipWriter}; -use uv_distribution_filename::{TagSet, WheelFilename}; +use uv_distribution_filename::WheelFilename; use uv_fs::Simplified; use uv_globfilter::{parse_portable_glob, GlobDirFilter}; use uv_platform_tags::{AbiTag, LanguageTag, PlatformTag}; @@ -33,17 +33,16 @@ pub fn build_wheel( } crate::check_metadata_directory(source_tree, metadata_directory, &pyproject_toml)?; - let filename = WheelFilename { - name: pyproject_toml.name().clone(), - version: pyproject_toml.version().clone(), - build_tag: None, - python_tag: TagSet::from_slice(&[LanguageTag::Python { + let filename = WheelFilename::new( + pyproject_toml.name().clone(), + pyproject_toml.version().clone(), + LanguageTag::Python { major: 3, minor: None, - }]), - abi_tag: TagSet::from_buf([AbiTag::None]), - platform_tag: TagSet::from_buf([PlatformTag::Any]), - }; + }, + AbiTag::None, + PlatformTag::Any, + ); let wheel_path = wheel_dir.join(filename.to_string()); debug!("Writing wheel at {}", wheel_path.user_display()); @@ -71,17 +70,16 @@ pub fn list_wheel( warn_user_once!("{warning}"); } - let filename = WheelFilename { - name: pyproject_toml.name().clone(), - version: pyproject_toml.version().clone(), - build_tag: None, - python_tag: TagSet::from_slice(&[LanguageTag::Python { + let filename = WheelFilename::new( + pyproject_toml.name().clone(), + pyproject_toml.version().clone(), + LanguageTag::Python { major: 3, minor: None, - }]), - abi_tag: TagSet::from_buf([AbiTag::None]), - platform_tag: TagSet::from_buf([PlatformTag::Any]), - }; + }, + AbiTag::None, + PlatformTag::Any, + ); let mut files = FileList::new(); let writer = ListWriter::new(&mut files); @@ -253,17 +251,16 @@ pub fn build_editable( crate::check_metadata_directory(source_tree, metadata_directory, &pyproject_toml)?; - let filename = WheelFilename { - name: pyproject_toml.name().clone(), - version: pyproject_toml.version().clone(), - build_tag: None, - python_tag: TagSet::from_slice(&[LanguageTag::Python { + let filename = WheelFilename::new( + pyproject_toml.name().clone(), + pyproject_toml.version().clone(), + LanguageTag::Python { major: 3, minor: None, - }]), - abi_tag: TagSet::from_buf([AbiTag::None]), - platform_tag: TagSet::from_buf([PlatformTag::Any]), - }; + }, + AbiTag::None, + PlatformTag::Any, + ); let wheel_path = wheel_dir.join(filename.to_string()); debug!("Writing wheel at {}", wheel_path.user_display()); @@ -308,17 +305,16 @@ pub fn metadata( warn_user_once!("{warning}"); } - let filename = WheelFilename { - name: pyproject_toml.name().clone(), - version: pyproject_toml.version().clone(), - build_tag: None, - python_tag: TagSet::from_slice(&[LanguageTag::Python { + let filename = WheelFilename::new( + pyproject_toml.name().clone(), + pyproject_toml.version().clone(), + LanguageTag::Python { major: 3, minor: None, - }]), - abi_tag: TagSet::from_buf([AbiTag::None]), - platform_tag: TagSet::from_buf([PlatformTag::Any]), - }; + }, + AbiTag::None, + PlatformTag::Any, + ); debug!( "Writing metadata files to {}", @@ -568,9 +564,9 @@ fn wheel_info(filename: &WheelFilename, uv_version: &str) -> String { ("Generator", format!("uv {uv_version}")), ("Root-Is-Purelib", "true".to_string()), ]; - for python_tag in &filename.python_tag { - for abi_tag in &filename.abi_tag { - for platform_tag in &filename.platform_tag { + for python_tag in filename.python_tags() { + for abi_tag in filename.abi_tags() { + for platform_tag in filename.platform_tags() { wheel_info.push(("Tag", format!("{python_tag}-{abi_tag}-{platform_tag}"))); } } @@ -765,29 +761,21 @@ mod test { #[test] fn test_wheel() { - let filename = WheelFilename { - name: PackageName::from_str("foo").unwrap(), - version: Version::from_str("1.2.3").unwrap(), - build_tag: None, - python_tag: TagSet::from_slice(&[ - LanguageTag::Python { - major: 2, - minor: None, - }, - LanguageTag::Python { - major: 3, - minor: None, - }, - ]), - abi_tag: TagSet::from_buf([AbiTag::None]), - platform_tag: TagSet::from_buf([PlatformTag::Any]), - }; + let filename = WheelFilename::new( + PackageName::from_str("foo").unwrap(), + Version::from_str("1.2.3").unwrap(), + LanguageTag::Python { + major: 3, + minor: None, + }, + AbiTag::None, + PlatformTag::Any, + ); assert_snapshot!(wheel_info(&filename, "1.0.0+test"), @r" Wheel-Version: 1.0 Generator: uv 1.0.0+test Root-Is-Purelib: true - Tag: py2-none-any Tag: py3-none-any "); } diff --git a/crates/uv-distribution-filename/src/lib.rs b/crates/uv-distribution-filename/src/lib.rs index f74043952..39c8ac0f8 100644 --- a/crates/uv-distribution-filename/src/lib.rs +++ b/crates/uv-distribution-filename/src/lib.rs @@ -99,6 +99,6 @@ mod tests { #[test] fn wheel_filename_size() { - assert_eq!(size_of::(), 128); + assert_eq!(size_of::(), 48); } } diff --git a/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_build_tag.snap b/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_build_tag.snap index 2014265e0..cfd6846e3 100644 --- a/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_build_tag.snap +++ b/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_build_tag.snap @@ -8,23 +8,27 @@ Ok( "foo", ), version: "1.2.3", - build_tag: Some( - BuildTag( - 202206090410, - None, - ), - ), - python_tag: [ - Python { - major: 3, - minor: None, + tags: Large { + large: WheelTagLarge { + build_tag: Some( + BuildTag( + 202206090410, + None, + ), + ), + python_tag: [ + Python { + major: 3, + minor: None, + }, + ], + abi_tag: [ + None, + ], + platform_tag: [ + Any, + ], }, - ], - abi_tag: [ - None, - ], - platform_tag: [ - Any, - ], + }, }, ) diff --git a/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_multiple_tags.snap b/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_multiple_tags.snap index 64c6a3948..2da1f4005 100644 --- a/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_multiple_tags.snap +++ b/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_multiple_tags.snap @@ -8,33 +8,37 @@ Ok( "foo", ), version: "1.2.3", - build_tag: None, - python_tag: [ - CPython { - python_version: ( - 3, - 11, - ), + tags: Large { + large: WheelTagLarge { + build_tag: None, + python_tag: [ + CPython { + python_version: ( + 3, + 11, + ), + }, + ], + abi_tag: [ + CPython { + gil_disabled: false, + python_version: ( + 3, + 11, + ), + }, + ], + platform_tag: [ + Manylinux { + major: 2, + minor: 17, + arch: X86_64, + }, + Manylinux2014 { + arch: X86_64, + }, + ], }, - ], - abi_tag: [ - CPython { - gil_disabled: false, - python_version: ( - 3, - 11, - ), - }, - ], - platform_tag: [ - Manylinux { - major: 2, - minor: 17, - arch: X86_64, - }, - Manylinux2014 { - arch: X86_64, - }, - ], + }, }, ) diff --git a/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_single_tags.snap b/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_single_tags.snap index 1f6fcf5e1..fb6f0ab2d 100644 --- a/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_single_tags.snap +++ b/crates/uv-distribution-filename/src/snapshots/uv_distribution_filename__wheel__tests__ok_single_tags.snap @@ -8,18 +8,15 @@ Ok( "foo", ), version: "1.2.3", - build_tag: None, - python_tag: [ - Python { - major: 3, - minor: None, + tags: Small { + small: WheelTagSmall { + python_tag: Python { + major: 3, + minor: None, + }, + abi_tag: None, + platform_tag: Any, }, - ], - abi_tag: [ - None, - ], - platform_tag: [ - Any, - ], + }, }, ) diff --git a/crates/uv-distribution-filename/src/wheel.rs b/crates/uv-distribution-filename/src/wheel.rs index 8c87b136c..72e58d182 100644 --- a/crates/uv-distribution-filename/src/wheel.rs +++ b/crates/uv-distribution-filename/src/wheel.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Formatter}; -use std::str::FromStr; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use std::str::FromStr; use thiserror::Error; use url::Url; @@ -14,12 +14,6 @@ use uv_platform_tags::{ use crate::{BuildTag, BuildTagError}; -/// A [`SmallVec`] type for storing tags. -/// -/// Wheels tend to include a single language, ABI, and platform tag, so we use a [`SmallVec`] with a -/// capacity of 1 to optimize for this common case. -pub type TagSet = smallvec::SmallVec<[T; 1]>; - #[derive( Debug, Clone, @@ -36,10 +30,7 @@ pub type TagSet = smallvec::SmallVec<[T; 1]>; pub struct WheelFilename { pub name: PackageName, pub version: Version, - pub build_tag: Option, - pub python_tag: TagSet, - pub abi_tag: TagSet, - pub platform_tag: TagSet, + tags: WheelTag, } impl FromStr for WheelFilename { @@ -63,20 +54,41 @@ impl Display for WheelFilename { "{}-{}-{}.whl", self.name.as_dist_info_name(), self.version, - self.get_tag() + self.tags, ) } } impl WheelFilename { + /// Create a [`WheelFilename`] from its components. + pub fn new( + name: PackageName, + version: Version, + python_tag: LanguageTag, + abi_tag: AbiTag, + platform_tag: PlatformTag, + ) -> Self { + Self { + name, + version, + tags: WheelTag::Small { + small: WheelTagSmall { + python_tag, + abi_tag, + platform_tag, + }, + }, + } + } + /// Returns `true` if the wheel is compatible with the given tags. pub fn is_compatible(&self, compatible_tags: &Tags) -> bool { - compatible_tags.is_compatible(&self.python_tag, &self.abi_tag, &self.platform_tag) + compatible_tags.is_compatible(self.python_tags(), self.abi_tags(), self.platform_tags()) } /// Return the [`TagCompatibility`] of the wheel with the given tags pub fn compatibility(&self, compatible_tags: &Tags) -> TagCompatibility { - compatible_tags.compatibility(&self.python_tag, &self.abi_tag, &self.platform_tag) + compatible_tags.compatibility(self.python_tags(), self.abi_tags(), self.platform_tags()) } /// The wheel filename without the extension. @@ -85,45 +97,47 @@ impl WheelFilename { "{}-{}-{}", self.name.as_dist_info_name(), self.version, - self.get_tag() + self.tags ) } + /// Return the wheel's Python tags. + pub fn python_tags(&self) -> &[LanguageTag] { + match &self.tags { + WheelTag::Small { small } => std::slice::from_ref(&small.python_tag), + WheelTag::Large { large } => large.python_tag.as_slice(), + } + } + + /// Return the wheel's ABI tags. + pub fn abi_tags(&self) -> &[AbiTag] { + match &self.tags { + WheelTag::Small { small } => std::slice::from_ref(&small.abi_tag), + WheelTag::Large { large } => large.abi_tag.as_slice(), + } + } + + /// Return the wheel's platform tags. + pub fn platform_tags(&self) -> &[PlatformTag] { + match &self.tags { + WheelTag::Small { small } => std::slice::from_ref(&small.platform_tag), + WheelTag::Large { large } => large.platform_tag.as_slice(), + } + } + + /// Return the wheel's build tag, if present. + pub fn build_tag(&self) -> Option<&BuildTag> { + match &self.tags { + WheelTag::Small { .. } => None, + WheelTag::Large { large } => large.build_tag.as_ref(), + } + } + /// Parse a wheel filename from the stem (e.g., `foo-1.2.3-py3-none-any`). pub fn from_stem(stem: &str) -> Result { Self::parse(stem, stem) } - /// Get the tag for this wheel. - fn get_tag(&self) -> String { - if let ([python_tag], [abi_tag], [platform_tag]) = ( - self.python_tag.as_slice(), - self.abi_tag.as_slice(), - self.platform_tag.as_slice(), - ) { - format!("{python_tag}-{abi_tag}-{platform_tag}",) - } else { - format!( - "{}-{}-{}", - self.python_tag - .iter() - .map(ToString::to_string) - .collect::>() - .join("."), - self.abi_tag - .iter() - .map(ToString::to_string) - .collect::>() - .join("."), - self.platform_tag - .iter() - .map(ToString::to_string) - .collect::>() - .join("."), - ) - } - } - /// Parse a wheel filename from the stem (e.g., `foo-1.2.3-py3-none-any`). /// /// The originating `filename` is used for high-fidelity error messages. @@ -202,25 +216,58 @@ impl WheelFilename { .map_err(|err| WheelFilenameError::InvalidBuildTag(filename.to_string(), err)) }) .transpose()?; + + let tags = if build_tag.is_some() + || python_tag.contains('.') + || abi_tag.contains('.') + || platform_tag.contains('.') + { + WheelTag::Large { + large: Box::new(WheelTagLarge { + build_tag, + python_tag: python_tag + .split('.') + .map(LanguageTag::from_str) + .collect::>() + .map_err(|err| { + WheelFilenameError::InvalidLanguageTag(filename.to_string(), err) + })?, + abi_tag: abi_tag + .split('.') + .map(AbiTag::from_str) + .collect::>() + .map_err(|err| { + WheelFilenameError::InvalidAbiTag(filename.to_string(), err) + })?, + platform_tag: platform_tag + .split('.') + .map(PlatformTag::from_str) + .collect::>() + .map_err(|err| { + WheelFilenameError::InvalidPlatformTag(filename.to_string(), err) + })?, + }), + } + } else { + WheelTag::Small { + small: WheelTagSmall { + python_tag: LanguageTag::from_str(python_tag).map_err(|err| { + WheelFilenameError::InvalidLanguageTag(filename.to_string(), err) + })?, + abi_tag: AbiTag::from_str(abi_tag).map_err(|err| { + WheelFilenameError::InvalidAbiTag(filename.to_string(), err) + })?, + platform_tag: PlatformTag::from_str(platform_tag).map_err(|err| { + WheelFilenameError::InvalidPlatformTag(filename.to_string(), err) + })?, + }, + } + }; + Ok(Self { name, version, - build_tag, - python_tag: python_tag - .split('.') - .map(LanguageTag::from_str) - .collect::>() - .map_err(|err| WheelFilenameError::InvalidLanguageTag(filename.to_string(), err))?, - abi_tag: abi_tag - .split('.') - .map(AbiTag::from_str) - .collect::>() - .map_err(|err| WheelFilenameError::InvalidAbiTag(filename.to_string(), err))?, - platform_tag: platform_tag - .split('.') - .map(PlatformTag::from_str) - .collect::>() - .map_err(|err| WheelFilenameError::InvalidPlatformTag(filename.to_string(), err))?, + tags, }) } } @@ -267,6 +314,121 @@ impl Serialize for WheelFilename { } } +/// A [`SmallVec`] type for storing tags. +/// +/// Wheels tend to include a single language, ABI, and platform tag, so we use a [`SmallVec`] with a +/// capacity of 1 to optimize for this common case. +pub type TagSet = smallvec::SmallVec<[T; 3]>; + +/// The portion of the wheel filename following the name and version: the optional build tag, along +/// with the Python tag(s), ABI tag(s), and platform tag(s). +/// +/// Most wheels consist of a single Python, ABI, and platform tag (and no build tag). We represent +/// such wheels with [`WheelTagSmall`], a variant with a smaller memory footprint and (generally) +/// zero allocations. The [`WheelTagLarge`] variant is used for wheels with multiple tags and/or a +/// build tag. +#[derive( + Debug, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + rkyv::Archive, + rkyv::Deserialize, + rkyv::Serialize, +)] +#[rkyv(derive(Debug))] +enum WheelTag { + Small { small: WheelTagSmall }, + Large { large: Box }, +} + +impl Display for WheelTag { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Small { small } => write!(f, "{small}"), + Self::Large { large } => write!(f, "{large}"), + } + } +} + +#[derive( + Debug, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + rkyv::Archive, + rkyv::Deserialize, + rkyv::Serialize, +)] +#[rkyv(derive(Debug))] +#[allow(clippy::struct_field_names)] +struct WheelTagSmall { + python_tag: LanguageTag, + abi_tag: AbiTag, + platform_tag: PlatformTag, +} + +impl Display for WheelTagSmall { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}-{}-{}", + self.python_tag, self.abi_tag, self.platform_tag + ) + } +} + +#[derive( + Debug, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + rkyv::Archive, + rkyv::Deserialize, + rkyv::Serialize, +)] +#[rkyv(derive(Debug))] +#[allow(clippy::struct_field_names)] +pub struct WheelTagLarge { + build_tag: Option, + python_tag: TagSet, + abi_tag: TagSet, + platform_tag: TagSet, +} + +impl Display for WheelTagLarge { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}-{}-{}", + self.python_tag + .iter() + .map(ToString::to_string) + .collect::>() + .join("."), + self.abi_tag + .iter() + .map(ToString::to_string) + .collect::>() + .join("."), + self.platform_tag + .iter() + .map(ToString::to_string) + .collect::>() + .join("."), + ) + } +} + #[derive(Error, Debug)] pub enum WheelFilenameError { #[error("The wheel filename \"{0}\" is invalid: {1}")] @@ -283,6 +445,12 @@ pub enum WheelFilenameError { InvalidAbiTag(String, ParseAbiTagError), #[error("The wheel filename \"{0}\" has an invalid platform tag: {1}")] InvalidPlatformTag(String, ParsePlatformTagError), + #[error("The wheel filename \"{0}\" is missing a language tag")] + MissingLanguageTag(String), + #[error("The wheel filename \"{0}\" is missing an ABI tag")] + MissingAbiTag(String), + #[error("The wheel filename \"{0}\" is missing a platform tag")] + MissingPlatformTag(String), } #[cfg(test)] diff --git a/crates/uv-distribution-types/src/lib.rs b/crates/uv-distribution-types/src/lib.rs index 239fbbdca..0ce995728 100644 --- a/crates/uv-distribution-types/src/lib.rs +++ b/crates/uv-distribution-types/src/lib.rs @@ -1343,8 +1343,8 @@ mod test { /// Ensure that we don't accidentally grow the `Dist` sizes. #[test] fn dist_size() { - assert!(size_of::() <= 272, "{}", size_of::()); - assert!(size_of::() <= 272, "{}", size_of::()); + assert!(size_of::() <= 248, "{}", size_of::()); + assert!(size_of::() <= 216, "{}", size_of::()); assert!( size_of::() <= 248, "{}", diff --git a/crates/uv-distribution-types/src/prioritized_distribution.rs b/crates/uv-distribution-types/src/prioritized_distribution.rs index 612ae44db..89be9cb41 100644 --- a/crates/uv-distribution-types/src/prioritized_distribution.rs +++ b/crates/uv-distribution-types/src/prioritized_distribution.rs @@ -527,7 +527,7 @@ impl PrioritizedDist { self.0 .wheels .iter() - .flat_map(|(wheel, _)| wheel.filename.python_tag.iter().copied()) + .flat_map(|(wheel, _)| wheel.filename.python_tags().iter().copied()) .collect() } @@ -536,7 +536,7 @@ impl PrioritizedDist { self.0 .wheels .iter() - .flat_map(|(wheel, _)| wheel.filename.abi_tag.iter().copied()) + .flat_map(|(wheel, _)| wheel.filename.abi_tags().iter().copied()) .collect() } @@ -545,10 +545,10 @@ impl PrioritizedDist { pub fn platform_tags<'a>(&'a self, tags: &'a Tags) -> BTreeSet<&'a PlatformTag> { let mut candidates = BTreeSet::new(); for (wheel, _) in &self.0.wheels { - for wheel_py in &wheel.filename.python_tag { - for wheel_abi in &wheel.filename.abi_tag { + for wheel_py in wheel.filename.python_tags() { + for wheel_abi in wheel.filename.abi_tags() { if tags.is_compatible_abi(*wheel_py, *wheel_abi) { - candidates.extend(wheel.filename.platform_tag.iter()); + candidates.extend(wheel.filename.platform_tags().iter()); } } } @@ -724,7 +724,7 @@ impl IncompatibleWheel { /// supported platforms (rather than generating the supported tags from a given platform). pub fn implied_markers(filename: &WheelFilename) -> MarkerTree { let mut marker = MarkerTree::FALSE; - for platform_tag in &filename.platform_tag { + for platform_tag in filename.platform_tags() { match platform_tag { PlatformTag::Any => { return MarkerTree::TRUE; diff --git a/crates/uv-publish/src/lib.rs b/crates/uv-publish/src/lib.rs index 7a3a64b72..b13ef9e00 100644 --- a/crates/uv-publish/src/lib.rs +++ b/crates/uv-publish/src/lib.rs @@ -674,7 +674,7 @@ async fn form_metadata( ]; if let DistFilename::WheelFilename(wheel) = filename { - form_metadata.push(("pyversion", wheel.python_tag.iter().join("."))); + form_metadata.push(("pyversion", wheel.python_tags().iter().join("."))); } else { form_metadata.push(("pyversion", "source".to_string())); } diff --git a/crates/uv-resolver/src/flat_index.rs b/crates/uv-resolver/src/flat_index.rs index a7570f250..4ade75139 100644 --- a/crates/uv-resolver/src/flat_index.rs +++ b/crates/uv-resolver/src/flat_index.rs @@ -181,7 +181,7 @@ impl FlatIndex { }; // Break ties with the build tag. - let build_tag = filename.build_tag.clone(); + let build_tag = filename.build_tag().cloned(); WheelCompatibility::Compatible(hash, priority, build_tag) } diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index c9faf4a22..d0ef155cd 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -291,7 +291,7 @@ impl Lock { // `(A ∩ (B ∩ C) = ∅) => ((A ∩ B = ∅) or (A ∩ C = ∅))` // a single disjointness check with the intersection is sufficient, so we have one // constant per platform. - let platform_tags = &wheel.filename.platform_tag; + let platform_tags = wheel.filename.platform_tags(); if platform_tags .iter() .all(uv_platform_tags::PlatformTag::is_linux) @@ -2275,7 +2275,7 @@ impl Package { else { continue; }; - let build_tag = wheel.filename.build_tag.as_ref(); + let build_tag = wheel.filename.build_tag(); let wheel_priority = (tag_priority, build_tag); match best { None => { diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap index 81566c0c7..873835f7e 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap @@ -66,19 +66,16 @@ Ok( "anyio", ), version: "4.3.0", - build_tag: None, - python_tag: [ - Python { - major: 3, - minor: None, + tags: Small { + small: WheelTagSmall { + python_tag: Python { + major: 3, + minor: None, + }, + abi_tag: None, + platform_tag: Any, }, - ], - abi_tag: [ - None, - ], - platform_tag: [ - Any, - ], + }, }, }, ], diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap index 57f836c16..74cea264f 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap @@ -73,19 +73,16 @@ Ok( "anyio", ), version: "4.3.0", - build_tag: None, - python_tag: [ - Python { - major: 3, - minor: None, + tags: Small { + small: WheelTagSmall { + python_tag: Python { + major: 3, + minor: None, + }, + abi_tag: None, + platform_tag: Any, }, - ], - abi_tag: [ - None, - ], - platform_tag: [ - Any, - ], + }, }, }, ], diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap index 68fbd77b7..fce4cc5a0 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap @@ -69,19 +69,16 @@ Ok( "anyio", ), version: "4.3.0", - build_tag: None, - python_tag: [ - Python { - major: 3, - minor: None, + tags: Small { + small: WheelTagSmall { + python_tag: Python { + major: 3, + minor: None, + }, + abi_tag: None, + platform_tag: Any, }, - ], - abi_tag: [ - None, - ], - platform_tag: [ - Any, - ], + }, }, }, ], diff --git a/crates/uv-resolver/src/requires_python.rs b/crates/uv-resolver/src/requires_python.rs index 6d0c3f59e..cef410c92 100644 --- a/crates/uv-resolver/src/requires_python.rs +++ b/crates/uv-resolver/src/requires_python.rs @@ -380,12 +380,12 @@ impl RequiresPython { /// It is meant to filter out clearly unusable wheels with perfect specificity and acceptable /// sensitivity, we return `true` if the tags are unknown. pub fn matches_wheel_tag(&self, wheel: &WheelFilename) -> bool { - wheel.abi_tag.iter().any(|abi_tag| { + wheel.abi_tags().iter().any(|abi_tag| { if *abi_tag == AbiTag::Abi3 { // Universal tags are allowed. true } else if *abi_tag == AbiTag::None { - wheel.python_tag.iter().any(|python_tag| { + wheel.python_tags().iter().any(|python_tag| { // Remove `py2-none-any` and `py27-none-any` and analogous `cp` and `pp` tags. if matches!( python_tag, diff --git a/crates/uv-resolver/src/version_map.rs b/crates/uv-resolver/src/version_map.rs index 60d822f20..c5b05b328 100644 --- a/crates/uv-resolver/src/version_map.rs +++ b/crates/uv-resolver/src/version_map.rs @@ -555,7 +555,7 @@ impl VersionMapLazy { }; // Break ties with the build tag. - let build_tag = filename.build_tag.clone(); + let build_tag = filename.build_tag().cloned(); WheelCompatibility::Compatible(hash, priority, build_tag) }