mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Add support for <maj>.<min>-dev
Python version requests
This commit is contained in:
parent
451c834ebb
commit
2fae66f548
1 changed files with 98 additions and 29 deletions
|
@ -152,6 +152,36 @@ pub enum PythonVariant {
|
|||
Freethreaded,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PythonPrerelease {
|
||||
/// Any prerelease, e.g., from `3.14-dev`
|
||||
Any,
|
||||
/// A specific prerelease, e.g., from `3.14b1` or `3.14b`
|
||||
Specific(Prerelease),
|
||||
}
|
||||
|
||||
impl PythonPrerelease {
|
||||
pub(crate) fn matches(&self, prerelease: Option<Prerelease>) -> bool {
|
||||
let Some(pre) = prerelease else {
|
||||
return false;
|
||||
};
|
||||
|
||||
match self {
|
||||
PythonPrerelease::Any => true,
|
||||
PythonPrerelease::Specific(request) => *request == pre,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PythonPrerelease {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
PythonPrerelease::Any => write!(f, "-dev"),
|
||||
PythonPrerelease::Specific(inner) => write!(f, "{inner}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Python discovery version request.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub enum VersionRequest {
|
||||
|
@ -163,7 +193,7 @@ pub enum VersionRequest {
|
|||
Major(u8, PythonVariant),
|
||||
MajorMinor(u8, u8, PythonVariant),
|
||||
MajorMinorPatch(u8, u8, u8, PythonVariant),
|
||||
MajorMinorPrerelease(u8, u8, Prerelease, PythonVariant),
|
||||
MajorMinorPrerelease(u8, u8, PythonPrerelease, PythonVariant),
|
||||
Range(VersionSpecifiers, PythonVariant),
|
||||
}
|
||||
|
||||
|
@ -1393,6 +1423,22 @@ impl PythonRequest {
|
|||
return Self::Default;
|
||||
}
|
||||
|
||||
// e.g., 3.14-dev
|
||||
if let Some((first, second)) = value.split_once('-') {
|
||||
if second.eq_ignore_ascii_case("dev") {
|
||||
if let Ok(VersionRequest::MajorMinor(major, minor, variant)) =
|
||||
VersionRequest::from_str(first)
|
||||
{
|
||||
return Self::Version(VersionRequest::MajorMinorPrerelease(
|
||||
major,
|
||||
minor,
|
||||
PythonPrerelease::Any,
|
||||
variant,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// e.g. `3.12.1`, `312`, or `>=3.12`
|
||||
if let Ok(version) = VersionRequest::from_str(value) {
|
||||
return Self::Version(version);
|
||||
|
@ -1931,12 +1977,16 @@ impl VersionRequest {
|
|||
&self,
|
||||
implementation: Option<&ImplementationName>,
|
||||
) -> Vec<ExecutableName> {
|
||||
let prerelease = if let Self::MajorMinorPrerelease(_, _, prerelease, _) = self {
|
||||
// Include the prerelease version, e.g., `python3.8a`
|
||||
Some(prerelease)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let prerelease =
|
||||
// TODO(zanieb): Determine a way to handle `[PythonPrerelease::Any]`
|
||||
if let Self::MajorMinorPrerelease(_, _, PythonPrerelease::Specific(prerelease), _) =
|
||||
self
|
||||
{
|
||||
// Include the prerelease version, e.g., `python3.8a`
|
||||
Some(prerelease)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Push a default one
|
||||
let mut names = Vec::new();
|
||||
|
@ -2149,14 +2199,8 @@ impl VersionRequest {
|
|||
}
|
||||
Self::MajorMinorPrerelease(major, minor, prerelease, variant) => {
|
||||
let version = interpreter.python_version();
|
||||
let Some(interpreter_prerelease) = version.pre() else {
|
||||
return false;
|
||||
};
|
||||
(
|
||||
interpreter.python_major(),
|
||||
interpreter.python_minor(),
|
||||
interpreter_prerelease,
|
||||
) == (*major, *minor, *prerelease)
|
||||
(interpreter.python_major(), interpreter.python_minor()) == (*major, *minor)
|
||||
&& prerelease.matches(version.pre())
|
||||
&& variant.matches_interpreter(interpreter)
|
||||
}
|
||||
}
|
||||
|
@ -2179,8 +2223,8 @@ impl VersionRequest {
|
|||
}
|
||||
Self::Range(specifiers, _) => specifiers.contains(&version.version),
|
||||
Self::MajorMinorPrerelease(major, minor, prerelease, _) => {
|
||||
(version.major(), version.minor(), version.pre())
|
||||
== (*major, *minor, Some(*prerelease))
|
||||
(version.major(), version.minor()) == (*major, *minor)
|
||||
&& prerelease.matches(version.pre())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2252,7 +2296,7 @@ impl VersionRequest {
|
|||
Self::MajorMinorPrerelease(self_major, self_minor, self_prerelease, _) => {
|
||||
// Pre-releases of Python versions are always for the zero patch version
|
||||
(*self_major, *self_minor, 0) == (major, minor, patch)
|
||||
&& prerelease.is_none_or(|pre| *self_prerelease == pre)
|
||||
&& self_prerelease.matches(prerelease)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2420,7 +2464,10 @@ impl FromStr for VersionRequest {
|
|||
[major, minor] => {
|
||||
if let Some(prerelease) = prerelease {
|
||||
return Ok(Self::MajorMinorPrerelease(
|
||||
*major, *minor, prerelease, variant,
|
||||
*major,
|
||||
*minor,
|
||||
PythonPrerelease::Specific(prerelease),
|
||||
variant,
|
||||
));
|
||||
}
|
||||
Ok(Self::MajorMinor(*major, *minor, variant))
|
||||
|
@ -2434,7 +2481,10 @@ impl FromStr for VersionRequest {
|
|||
return Err(Error::InvalidVersionRequest(s.to_string()));
|
||||
}
|
||||
return Ok(Self::MajorMinorPrerelease(
|
||||
*major, *minor, prerelease, variant,
|
||||
*major,
|
||||
*minor,
|
||||
PythonPrerelease::Specific(prerelease),
|
||||
variant,
|
||||
));
|
||||
}
|
||||
Ok(Self::MajorMinorPatch(*major, *minor, *patch, variant))
|
||||
|
@ -2709,7 +2759,7 @@ mod tests {
|
|||
use uv_pep440::{Prerelease, PrereleaseKind, VersionSpecifiers};
|
||||
|
||||
use crate::{
|
||||
discovery::{PythonRequest, VersionRequest},
|
||||
discovery::{PythonPrerelease, PythonRequest, VersionRequest},
|
||||
implementation::ImplementationName,
|
||||
};
|
||||
|
||||
|
@ -2736,6 +2786,25 @@ mod tests {
|
|||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13-dev"),
|
||||
PythonRequest::Version(VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
PythonPrerelease::Any,
|
||||
PythonVariant::Default
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13t-dev"),
|
||||
PythonRequest::Version(VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
PythonPrerelease::Any,
|
||||
PythonVariant::Freethreaded
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0a1"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0a1").unwrap())
|
||||
|
@ -3026,10 +3095,10 @@ mod tests {
|
|||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
PythonPrerelease::Specific(Prerelease {
|
||||
kind: PrereleaseKind::Alpha,
|
||||
number: 1
|
||||
},
|
||||
}),
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
|
@ -3038,10 +3107,10 @@ mod tests {
|
|||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
PythonPrerelease::Specific(Prerelease {
|
||||
kind: PrereleaseKind::Beta,
|
||||
number: 1
|
||||
},
|
||||
}),
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
|
@ -3050,10 +3119,10 @@ mod tests {
|
|||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
PythonPrerelease::Specific(Prerelease {
|
||||
kind: PrereleaseKind::Beta,
|
||||
number: 2
|
||||
},
|
||||
}),
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
|
@ -3062,10 +3131,10 @@ mod tests {
|
|||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
PythonPrerelease::Specific(Prerelease {
|
||||
kind: PrereleaseKind::Rc,
|
||||
number: 3
|
||||
},
|
||||
}),
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue