Skip to content

Commit 11b181a

Browse files
committed
Add an ArchMode to filter displayed architectures in uv python list
1 parent 5620348 commit 11b181a

File tree

4 files changed

+76
-6
lines changed

4 files changed

+76
-6
lines changed

crates/uv-python/src/discovery.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,7 +2799,8 @@ mod tests {
27992799
arch: None,
28002800
os: None,
28012801
libc: None,
2802-
prereleases: None
2802+
prereleases: None,
2803+
arch_mode: None,
28032804
})
28042805
);
28052806
assert_eq!(
@@ -2818,7 +2819,8 @@ mod tests {
28182819
}),
28192820
os: Some(Os(target_lexicon::OperatingSystem::Darwin(None))),
28202821
libc: Some(Libc::None),
2821-
prereleases: None
2822+
prereleases: None,
2823+
arch_mode: None,
28222824
})
28232825
);
28242826
assert_eq!(
@@ -2834,7 +2836,8 @@ mod tests {
28342836
arch: None,
28352837
os: None,
28362838
libc: None,
2837-
prereleases: None
2839+
prereleases: None,
2840+
arch_mode: None,
28382841
})
28392842
);
28402843
assert_eq!(
@@ -2853,7 +2856,8 @@ mod tests {
28532856
}),
28542857
os: None,
28552858
libc: None,
2856-
prereleases: None
2859+
prereleases: None,
2860+
arch_mode: None,
28572861
})
28582862
);
28592863

crates/uv-python/src/downloads.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::implementation::{
3636
use crate::installation::PythonInstallationKey;
3737
use crate::libc::LibcDetectionError;
3838
use crate::managed::ManagedPythonInstallation;
39-
use crate::platform::{self, Arch, Libc, Os};
39+
use crate::platform::{self, Arch, ArchMode, Libc, Os};
4040
use crate::{Interpreter, PythonRequest, PythonVersion, VersionRequest};
4141

4242
#[derive(Error, Debug)]
@@ -125,6 +125,8 @@ pub struct PythonDownloadRequest {
125125
/// Whether to allow pre-releases or not. If not set, defaults to true if [`Self::version`] is
126126
/// not None, and false otherwise.
127127
pub(crate) prereleases: Option<bool>,
128+
129+
pub(crate) arch_mode: Option<ArchMode>,
128130
}
129131

130132
impl PythonDownloadRequest {
@@ -135,6 +137,7 @@ impl PythonDownloadRequest {
135137
os: Option<Os>,
136138
libc: Option<Libc>,
137139
prereleases: Option<bool>,
140+
arch_mode: Option<ArchMode>,
138141
) -> Self {
139142
Self {
140143
version,
@@ -143,6 +146,7 @@ impl PythonDownloadRequest {
143146
os,
144147
libc,
145148
prereleases,
149+
arch_mode,
146150
}
147151
}
148152

@@ -188,6 +192,12 @@ impl PythonDownloadRequest {
188192
self
189193
}
190194

195+
#[must_use]
196+
pub fn with_arch_mode(mut self, arch_mode: ArchMode) -> Self {
197+
self.arch_mode = Some(arch_mode);
198+
self
199+
}
200+
191201
/// Construct a new [`PythonDownloadRequest`] from a [`PythonRequest`] if possible.
192202
///
193203
/// Returns [`None`] if the request kind is not compatible with a download, e.g., it is
@@ -249,6 +259,7 @@ impl PythonDownloadRequest {
249259
Some(Os::from_env()),
250260
Some(Libc::from_env()?),
251261
None,
262+
None,
252263
))
253264
}
254265

@@ -293,6 +304,9 @@ impl PythonDownloadRequest {
293304
if !arch.supports(key.arch) {
294305
return false;
295306
}
307+
if !self.arch_mode.unwrap_or_default().allows(arch, &key.arch) {
308+
return false;
309+
}
296310
}
297311

298312
if let Some(libc) = &self.libc {
@@ -414,6 +428,7 @@ impl From<&ManagedPythonInstallation> for PythonDownloadRequest {
414428
Some(key.os),
415429
Some(key.libc),
416430
Some(key.prerelease.is_some()),
431+
None,
417432
)
418433
}
419434
}
@@ -485,7 +500,15 @@ impl FromStr for PythonDownloadRequest {
485500
_ => return Err(Error::TooManyParts(s.to_string())),
486501
}
487502
}
488-
Ok(Self::new(version, implementation, arch, os, libc, None))
503+
Ok(Self::new(
504+
version,
505+
implementation,
506+
arch,
507+
os,
508+
libc,
509+
None,
510+
None,
511+
))
489512
}
490513
}
491514

crates/uv-python/src/platform.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ pub enum ArchVariant {
3131
V4,
3232
}
3333

34+
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, Default)]
35+
pub enum ArchMode {
36+
/// Select the most precise architecture matching the current platform, e.g., x86-64-v4
37+
#[default]
38+
BestNative,
39+
/// Select the most compatible architecture matching the current platform, e.g., x86-64-v1
40+
CompatibleNative,
41+
/// Select an emulated architecture, e.g., x86-64 on aarch64 macOS.
42+
Emulated,
43+
}
44+
3445
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
3546
pub struct Arch {
3647
pub(crate) family: target_lexicon::Architecture,
@@ -95,6 +106,37 @@ impl Os {
95106
}
96107
}
97108

109+
impl ArchMode {
110+
pub fn allows(self, current: &Arch, other: &Arch) -> bool {
111+
match self {
112+
Self::CompatibleNative | Self::BestNative => {
113+
// The architecture is native if the family is equal
114+
if current.family != other.family {
115+
return false;
116+
}
117+
118+
// There is only a compatibility nuance for x86_64 here
119+
if current.family != target_lexicon::Architecture::X86_64 {
120+
return true;
121+
}
122+
123+
if matches!(self, Self::CompatibleNative) {
124+
// Only allow x86_64 without a variant
125+
return other.variant.is_none();
126+
} else if matches!(self, Self::BestNative) {
127+
// Only allow the variant matching the current architecture
128+
return current.variant == other.variant;
129+
}
130+
131+
// We should handle all cases above
132+
unreachable!();
133+
}
134+
// The architecture is emulated if the family differs
135+
Self::Emulated => current.family != other.family,
136+
}
137+
}
138+
}
139+
98140
impl Arch {
99141
pub fn from_env() -> Self {
100142
Self {

crates/uv/src/commands/python/list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::collections::BTreeSet;
33
use std::fmt::Write;
44
use uv_cli::PythonListFormat;
55
use uv_pep440::Version;
6+
use uv_python::platform::ArchMode;
67

78
use anyhow::Result;
89
use itertools::Either;

0 commit comments

Comments
 (0)