From 7ac506a4d2c8d1f22c143b97133ed9d42893e9a9 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Mon, 28 Oct 2024 14:39:18 -0500 Subject: [PATCH] Add support for requesting free-threaded builds via `+freethreaded` e.g., `uv python install 3.13+freethreaded` --- crates/uv-python/src/discovery.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/uv-python/src/discovery.rs b/crates/uv-python/src/discovery.rs index 13fd159bf678..0aa66dc71718 100644 --- a/crates/uv-python/src/discovery.rs +++ b/crates/uv-python/src/discovery.rs @@ -2074,11 +2074,30 @@ impl FromStr for VersionRequest { // Split the release component if it uses the wheel tag format (e.g., `38`) let version = split_wheel_tag_release_version(version); - // We dont allow post, dev, or local versions here - if version.post().is_some() || version.dev().is_some() || !version.local().is_empty() { + // We dont allow post or dev version here + if version.post().is_some() || version.dev().is_some() { return Err(Error::InvalidVersionRequest(s.to_string())); } + // Check if the local version includes a variant + let variant = if version.local().is_empty() { + variant + } else { + // If we already have a variant, do not allow another to be requested + if variant != PythonVariant::Default { + return Err(Error::InvalidVersionRequest(s.to_string())); + } + + let [uv_pep440::LocalSegment::String(local)] = version.local() else { + return Err(Error::InvalidVersionRequest(s.to_string())); + }; + + match local.as_str() { + "freethreaded" => PythonVariant::Freethreaded, + _ => return Err(Error::InvalidVersionRequest(s.to_string())), + } + }; + // Cast the release components into u8s since that's what we use in `VersionRequest` let Ok(release) = try_into_u8_slice(version.release()) else { return Err(Error::InvalidVersionRequest(s.to_string()));