Skip to content

Commit

Permalink
Allow use of older variants on newer systems
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Dec 10, 2024
1 parent c0f146c commit d51e5d7
Show file tree
Hide file tree
Showing 8 changed files with 10,513 additions and 10,479 deletions.
14,110 changes: 7,055 additions & 7,055 deletions crates/uv-python/download-metadata.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions crates/uv-python/fetch-download-metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,12 @@ def __str__(self) -> str:
return (self.family + "_" + self.variant) if self.variant else self.family

def __gt__(self, other) -> bool:
return (self.family, self.variant or "") > (other.family, other.variant or "")
# Note this is inverted to prefer newer variants
return (self.family, self.variant or "") < (other.family, other.variant or "")

def __lt__(self, other) -> bool:
return (self.family, self.variant or "") < (other.family, other.variant or "")
# Note this is inverted to prefer newer variants
return (self.family, self.variant or "") > (other.family, other.variant or "")


type PlatformTripleKey = tuple[str, str, str]
Expand Down
6,800 changes: 3,400 additions & 3,400 deletions crates/uv-python/src/downloads.inc

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions crates/uv-python/src/downloads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,26 +251,30 @@ impl PythonDownloadRequest {

/// Whether this request is satisfied by the key of an existing installation.
pub fn satisfied_by_key(&self, key: &PythonInstallationKey) -> bool {
if let Some(arch) = &self.arch {
if key.arch != *arch {
if let Some(os) = &self.os {
if key.os != *os {
return false;
}
}
if let Some(os) = &self.os {
if key.os != *os {

if let Some(arch) = &self.arch {
if !arch.is_compatible(key.arch) {
return false;
}
}

if let Some(libc) = &self.libc {
if key.libc != *libc {
return false;
}
}

if let Some(implementation) = &self.implementation {
if key.implementation != LenientImplementationName::from(*implementation) {
return false;
}
}

// If we don't allow pre-releases, don't match a key with a pre-release tag
if !self.allows_prereleases() && key.prerelease.is_some() {
return false;
Expand Down
19 changes: 5 additions & 14 deletions crates/uv-python/src/managed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,16 +237,15 @@ impl ManagedPythonInstallations {
pub fn find_matching_current_platform(
&self,
) -> Result<impl DoubleEndedIterator<Item = ManagedPythonInstallation>, Error> {
let platform_key = platform_key_from_env()?;
let os = Os::from_env();
let arch = Arch::from_env();
let libc = Libc::from_env()?;

let iter = ManagedPythonInstallations::from_settings(None)?
.find_all()?
.filter(move |installation| {
installation
.path
.file_name()
.map(OsStr::to_string_lossy)
.is_some_and(|filename| filename.ends_with(&platform_key))
let key = installation.key();
key.os == os && arch.is_compatible(key.arch) && key.libc == libc
});

Ok(iter)
Expand Down Expand Up @@ -585,14 +584,6 @@ impl ManagedPythonInstallation {
}
}

/// Generate a platform portion of a key from the environment.
fn platform_key_from_env() -> Result<String, Error> {
let os = Os::from_env();
let arch = Arch::from_env();
let libc = Libc::from_env()?;
Ok(format!("{os}-{arch}-{libc}").to_lowercase())
}

impl fmt::Display for ManagedPythonInstallation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
Expand Down
41 changes: 39 additions & 2 deletions crates/uv-python/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,30 @@ impl Arch {
variant: ArchVariant::from_env(),
}
}

/// Is the current architecture compatible with `other`?
///
/// `other` can be a compatible microarchitecture with worse performance characteristics.
pub(crate) fn is_compatible(self, other: Self) -> bool {
self.family == other.family
&& ((self.variant.is_none() && other.variant.is_none())
|| self
.variant
.is_some_and(|variant| variant.is_compatible(other.variant)))
}

#[must_use]
pub fn without_variant(self) -> Self {
Self {
family: self.family,
variant: None,
}
}
}

impl ArchVariant {
#[cfg(target_arch = "x86_64")]
/// Only Linux `x86_64` variants are published upstream at this time.
#[cfg(all(unix, target_arch = "x86_64"))]
pub fn from_env() -> Option<Self> {
if is_x86_feature_detected!("avx512f")
&& is_x86_feature_detected!("avx512bw")
Expand Down Expand Up @@ -141,10 +161,27 @@ impl ArchVariant {
}
}

#[cfg(not(target_arch = "x86_64"))]
#[cfg(not(all(unix, target_arch = "x86_64")))]
pub fn from_env() -> Option<Self> {
None
}

/// Is the current variant compatible with `other`?
///
/// `other` can be a compatible variant with lower priority, however, it must be a subset of
/// `self`.
pub(crate) fn is_compatible(self, other: Option<Self>) -> bool {
let Some(other) = other else {
// `None` can be used on any architecture
return true;
};
match self {
Self::V2 => matches!(other, Self::V2),
Self::V3 => matches!(other, Self::V2 | Self::V3),
// If on V4, any variant can be used.
Self::V4 => true,
}
}
}

impl Display for Libc {
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/tests/it/python_find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn python_find() {

// Request CPython 3.12 for the current platform
let os = Os::from_env();
let arch = Arch::from_env();
let arch = Arch::from_env().without_variant();

uv_snapshot!(context.filters(), context.python_find()
.arg(format!("cpython-3.12-{os}-{arch}"))
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/tests/it/python_pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ fn python_pin_resolve() {

// Request CPython 3.13 for the current platform
let os = Os::from_env();
let arch = Arch::from_env();
let arch = Arch::from_env().without_variant();

uv_snapshot!(context.filters(), context.python_pin().arg("--resolved")
.arg(format!("cpython-3.13-{os}-{arch}"))
Expand Down

0 comments on commit d51e5d7

Please sign in to comment.