Skip to content

Commit 7d12b6a

Browse files
committed
Fix PythonDownloadRequest parsing for partial keys
1 parent df35919 commit 7d12b6a

File tree

3 files changed

+107
-31
lines changed

3 files changed

+107
-31
lines changed

crates/uv-python/src/discovery.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,12 +2705,15 @@ mod tests {
27052705
use std::{path::PathBuf, str::FromStr};
27062706

27072707
use assert_fs::{prelude::*, TempDir};
2708+
use target_lexicon::{Aarch64Architecture, Architecture};
27082709
use test_log::test;
27092710
use uv_pep440::{Prerelease, PrereleaseKind, VersionSpecifiers};
27102711

27112712
use crate::{
27122713
discovery::{PythonRequest, VersionRequest},
2714+
downloads::PythonDownloadRequest,
27132715
implementation::ImplementationName,
2716+
platform::{Arch, Libc, Os},
27142717
};
27152718

27162719
use super::{Error, PythonVariant};
@@ -2763,13 +2766,86 @@ mod tests {
27632766
PythonRequest::parse("cpython"),
27642767
PythonRequest::Implementation(ImplementationName::CPython)
27652768
);
2769+
27662770
assert_eq!(
27672771
PythonRequest::parse("cpython3.12.2"),
27682772
PythonRequest::ImplementationVersion(
27692773
ImplementationName::CPython,
27702774
VersionRequest::from_str("3.12.2").unwrap(),
27712775
)
27722776
);
2777+
2778+
assert_eq!(
2779+
PythonRequest::parse("cpython-3.13.2"),
2780+
PythonRequest::Key(PythonDownloadRequest {
2781+
version: Some(VersionRequest::MajorMinorPatch(
2782+
3,
2783+
13,
2784+
2,
2785+
PythonVariant::Default
2786+
)),
2787+
implementation: Some(ImplementationName::CPython),
2788+
arch: None,
2789+
os: None,
2790+
libc: None,
2791+
prereleases: None
2792+
})
2793+
);
2794+
assert_eq!(
2795+
PythonRequest::parse("cpython-3.13.2-macos-aarch64-none"),
2796+
PythonRequest::Key(PythonDownloadRequest {
2797+
version: Some(VersionRequest::MajorMinorPatch(
2798+
3,
2799+
13,
2800+
2,
2801+
PythonVariant::Default
2802+
)),
2803+
implementation: Some(ImplementationName::CPython),
2804+
arch: Some(Arch {
2805+
family: Architecture::Aarch64(Aarch64Architecture::Aarch64),
2806+
variant: None
2807+
}),
2808+
os: Some(Os(target_lexicon::OperatingSystem::Darwin(None))),
2809+
libc: Some(Libc::None),
2810+
prereleases: None
2811+
})
2812+
);
2813+
assert_eq!(
2814+
PythonRequest::parse("any-3.13.2"),
2815+
PythonRequest::Key(PythonDownloadRequest {
2816+
version: Some(VersionRequest::MajorMinorPatch(
2817+
3,
2818+
13,
2819+
2,
2820+
PythonVariant::Default
2821+
)),
2822+
implementation: None,
2823+
arch: None,
2824+
os: None,
2825+
libc: None,
2826+
prereleases: None
2827+
})
2828+
);
2829+
assert_eq!(
2830+
PythonRequest::parse("any-3.13.2-any-aarch64"),
2831+
PythonRequest::Key(PythonDownloadRequest {
2832+
version: Some(VersionRequest::MajorMinorPatch(
2833+
3,
2834+
13,
2835+
2,
2836+
PythonVariant::Default
2837+
)),
2838+
implementation: None,
2839+
arch: Some(Arch {
2840+
family: Architecture::Aarch64(Aarch64Architecture::Aarch64),
2841+
variant: None
2842+
}),
2843+
os: None,
2844+
libc: None,
2845+
prereleases: None
2846+
})
2847+
);
2848+
27732849
assert_eq!(
27742850
PythonRequest::parse("pypy"),
27752851
PythonRequest::Implementation(ImplementationName::PyPy)

crates/uv-python/src/downloads.rs

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,15 @@ pub struct ManagedPythonDownload {
107107

108108
#[derive(Debug, Clone, Default, Eq, PartialEq)]
109109
pub struct PythonDownloadRequest {
110-
version: Option<VersionRequest>,
111-
implementation: Option<ImplementationName>,
112-
arch: Option<Arch>,
113-
os: Option<Os>,
114-
libc: Option<Libc>,
110+
pub(crate) version: Option<VersionRequest>,
111+
pub(crate) implementation: Option<ImplementationName>,
112+
pub(crate) arch: Option<Arch>,
113+
pub(crate) os: Option<Os>,
114+
pub(crate) libc: Option<Libc>,
115115

116116
/// Whether to allow pre-releases or not. If not set, defaults to true if [`Self::version`] is
117117
/// not None, and false otherwise.
118-
prereleases: Option<bool>,
118+
pub(crate) prereleases: Option<bool>,
119119
}
120120

121121
impl PythonDownloadRequest {
@@ -419,39 +419,29 @@ impl FromStr for PythonDownloadRequest {
419419
let mut arch = None;
420420
let mut libc = None;
421421

422+
let mut position = 0;
422423
loop {
423424
// Consume each part
424425
let Some(part) = parts.next() else { break };
426+
position += 1;
425427

426-
if implementation.is_none() {
427-
implementation = Some(ImplementationName::from_str(part)?);
428+
if part.eq_ignore_ascii_case("any") {
428429
continue;
429430
}
430431

431-
if version.is_none() {
432-
version = Some(
433-
VersionRequest::from_str(part)
434-
.map_err(|_| Error::InvalidPythonVersion(part.to_string()))?,
435-
);
436-
continue;
437-
}
438-
439-
if os.is_none() {
440-
os = Some(Os::from_str(part)?);
441-
continue;
442-
}
443-
444-
if arch.is_none() {
445-
arch = Some(Arch::from_str(part)?);
446-
continue;
447-
}
448-
449-
if libc.is_none() {
450-
libc = Some(Libc::from_str(part)?);
451-
continue;
432+
match position {
433+
1 => implementation = Some(ImplementationName::from_str(part)?),
434+
2 => {
435+
version = Some(
436+
VersionRequest::from_str(part)
437+
.map_err(|_| Error::InvalidPythonVersion(part.to_string()))?,
438+
);
439+
}
440+
3 => os = Some(Os::from_str(part)?),
441+
4 => arch = Some(Arch::from_str(part)?),
442+
5 => libc = Some(Libc::from_str(part)?),
443+
_ => return Err(Error::TooManyParts(s.to_string())),
452444
}
453-
454-
return Err(Error::TooManyParts(s.to_string()));
455445
}
456446
Ok(Self::new(version, implementation, arch, os, libc, None))
457447
}

crates/uv/tests/it/python_find.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ fn python_find() {
8282
----- stderr -----
8383
"###);
8484

85+
// Request Python 3.12 via partial key syntax with placeholders
86+
uv_snapshot!(context.filters(), context.python_find().arg("any-3.12-any"), @r###"
87+
success: true
88+
exit_code: 0
89+
----- stdout -----
90+
[PYTHON-3.12]
91+
92+
----- stderr -----
93+
"###);
94+
8595
// Request CPython 3.12 for the current platform
8696
let os = Os::from_env();
8797
let arch = Arch::from_env();

0 commit comments

Comments
 (0)