mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-01 12:24:15 +00:00
Remove separate test files in favor of same-file mod tests (#9199)
## Summary These were moved as part of a broader refactor to create a single integration test module. That "single integration test module" did indeed have a big impact on compile times, which is great! But we aren't seeing any benefit from moving these tests into their own files (despite the claim in [this blog post](https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html), I see the same compilation pattern regardless of where the tests are located). Plus, we don't have many of these, and same-file tests is such a strong Rust convention.
This commit is contained in:
parent
747d69dc96
commit
d08bfee718
114 changed files with 15321 additions and 15344 deletions
|
|
@ -2522,4 +2522,537 @@ fn split_wheel_tag_release_version(version: Version) -> Version {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod tests {
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use assert_fs::{prelude::*, TempDir};
|
||||
use test_log::test;
|
||||
use uv_pep440::{Prerelease, PrereleaseKind, VersionSpecifiers};
|
||||
|
||||
use crate::{
|
||||
discovery::{PythonRequest, VersionRequest},
|
||||
implementation::ImplementationName,
|
||||
};
|
||||
|
||||
use super::{Error, PythonVariant};
|
||||
|
||||
#[test]
|
||||
fn interpreter_request_from_str() {
|
||||
assert_eq!(PythonRequest::parse("any"), PythonRequest::Any);
|
||||
assert_eq!(PythonRequest::parse("default"), PythonRequest::Default);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.12"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.12").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(">=3.12"),
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(">=3.12,<3.13"),
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(">=3.12,<3.13"),
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0a1"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0a1").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0b5"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0b5").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0rc1"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0rc1").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.1rc1"),
|
||||
PythonRequest::ExecutableName("3.13.1rc1".to_string()),
|
||||
"Pre-release version requests require a patch version of zero"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3rc1"),
|
||||
PythonRequest::ExecutableName("3rc1".to_string()),
|
||||
"Pre-release version requests require a minor version"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cpython"),
|
||||
PythonRequest::Implementation(ImplementationName::CPython)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cpython3.12.2"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::CPython,
|
||||
VersionRequest::from_str("3.12.2").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy"),
|
||||
PythonRequest::Implementation(ImplementationName::PyPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pp"),
|
||||
PythonRequest::Implementation(ImplementationName::PyPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy"),
|
||||
PythonRequest::Implementation(ImplementationName::GraalPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("gp"),
|
||||
PythonRequest::Implementation(ImplementationName::GraalPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cp"),
|
||||
PythonRequest::Implementation(ImplementationName::CPython)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pp310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("gp310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cp38"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::CPython,
|
||||
VersionRequest::from_str("3.8").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy@3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy@3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::parse(tempdir.path().to_str().unwrap()),
|
||||
PythonRequest::Directory(tempdir.path().to_path_buf()),
|
||||
"An existing directory is treated as a directory"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(tempdir.child("foo").path().to_str().unwrap()),
|
||||
PythonRequest::File(tempdir.child("foo").path().to_path_buf()),
|
||||
"A path that does not exist is treated as a file"
|
||||
);
|
||||
tempdir.child("bar").touch().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::parse(tempdir.child("bar").path().to_str().unwrap()),
|
||||
PythonRequest::File(tempdir.child("bar").path().to_path_buf()),
|
||||
"An existing file is treated as a file"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("./foo"),
|
||||
PythonRequest::File(PathBuf::from_str("./foo").unwrap()),
|
||||
"A string with a file system separator is treated as a file"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13t"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13t").unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpreter_request_to_canonical_string() {
|
||||
assert_eq!(PythonRequest::Default.to_canonical_string(), "default");
|
||||
assert_eq!(PythonRequest::Any.to_canonical_string(), "any");
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.12").unwrap()).to_canonical_string(),
|
||||
"3.12"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12").unwrap())
|
||||
.to_canonical_string(),
|
||||
">=3.12"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
.to_canonical_string(),
|
||||
">=3.12, <3.13"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0a1").unwrap())
|
||||
.to_canonical_string(),
|
||||
"3.13a1"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0b5").unwrap())
|
||||
.to_canonical_string(),
|
||||
"3.13b5"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0rc1").unwrap())
|
||||
.to_canonical_string(),
|
||||
"3.13rc1"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("313rc4").unwrap())
|
||||
.to_canonical_string(),
|
||||
"3.13rc4"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::ExecutableName("foo".to_string()).to_canonical_string(),
|
||||
"foo"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Implementation(ImplementationName::CPython).to_canonical_string(),
|
||||
"cpython"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::CPython,
|
||||
VersionRequest::from_str("3.12.2").unwrap(),
|
||||
)
|
||||
.to_canonical_string(),
|
||||
"cpython@3.12.2"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Implementation(ImplementationName::PyPy).to_canonical_string(),
|
||||
"pypy"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
.to_canonical_string(),
|
||||
"pypy@3.10"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Implementation(ImplementationName::GraalPy).to_canonical_string(),
|
||||
"graalpy"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
.to_canonical_string(),
|
||||
"graalpy@3.10"
|
||||
);
|
||||
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::Directory(tempdir.path().to_path_buf()).to_canonical_string(),
|
||||
tempdir.path().to_str().unwrap(),
|
||||
"An existing directory is treated as a directory"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::File(tempdir.child("foo").path().to_path_buf()).to_canonical_string(),
|
||||
tempdir.child("foo").path().to_str().unwrap(),
|
||||
"A path that does not exist is treated as a file"
|
||||
);
|
||||
tempdir.child("bar").touch().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::File(tempdir.child("bar").path().to_path_buf()).to_canonical_string(),
|
||||
tempdir.child("bar").path().to_str().unwrap(),
|
||||
"An existing file is treated as a file"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::File(PathBuf::from_str("./foo").unwrap()).to_canonical_string(),
|
||||
"./foo",
|
||||
"A string with a file system separator is treated as a file"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_request_from_str() {
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3").unwrap(),
|
||||
VersionRequest::Major(3, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.12").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 12, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.12.1").unwrap(),
|
||||
VersionRequest::MajorMinorPatch(3, 12, 1, PythonVariant::Default)
|
||||
);
|
||||
assert!(VersionRequest::from_str("1.foo.1").is_err());
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3").unwrap(),
|
||||
VersionRequest::Major(3, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("38").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 8, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("312").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 12, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3100").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 100, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13a1").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Alpha,
|
||||
number: 1
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("313b1").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Beta,
|
||||
number: 1
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13.0b2").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Beta,
|
||||
number: 2
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13.0rc3").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Rc,
|
||||
number: 3
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3rc1"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Pre-release version requests require a minor version"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.13.2rc1"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Pre-release version requests require a patch version of zero"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.12-dev"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Development version segments are not allowed"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.12+local"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Local version segments are not allowed"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.12.post0"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Post version segments are not allowed"
|
||||
);
|
||||
assert!(
|
||||
// Test for overflow
|
||||
matches!(
|
||||
VersionRequest::from_str("31000"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3t").unwrap(),
|
||||
VersionRequest::Major(3, PythonVariant::Freethreaded)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("313t").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 13, PythonVariant::Freethreaded)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13t").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 13, PythonVariant::Freethreaded)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str(">=3.13t").unwrap(),
|
||||
VersionRequest::Range(
|
||||
VersionSpecifiers::from_str(">=3.13").unwrap(),
|
||||
PythonVariant::Freethreaded
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str(">=3.13").unwrap(),
|
||||
VersionRequest::Range(
|
||||
VersionSpecifiers::from_str(">=3.13").unwrap(),
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str(">=3.12,<3.14t").unwrap(),
|
||||
VersionRequest::Range(
|
||||
VersionSpecifiers::from_str(">=3.12,<3.14").unwrap(),
|
||||
PythonVariant::Freethreaded
|
||||
)
|
||||
);
|
||||
assert!(matches!(
|
||||
VersionRequest::from_str("3.13tt"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn executable_names_from_request() {
|
||||
fn case(request: &str, expected: &[&str]) {
|
||||
let (implementation, version) = match PythonRequest::parse(request) {
|
||||
PythonRequest::Any => (None, VersionRequest::Any),
|
||||
PythonRequest::Default => (None, VersionRequest::Default),
|
||||
PythonRequest::Version(version) => (None, version),
|
||||
PythonRequest::ImplementationVersion(implementation, version) => {
|
||||
(Some(implementation), version)
|
||||
}
|
||||
PythonRequest::Implementation(implementation) => {
|
||||
(Some(implementation), VersionRequest::Default)
|
||||
}
|
||||
result => {
|
||||
panic!("Test cases should request versions or implementations; got {result:?}")
|
||||
}
|
||||
};
|
||||
|
||||
let result: Vec<_> = version
|
||||
.executable_names(implementation.as_ref())
|
||||
.into_iter()
|
||||
.map(|name| name.to_string())
|
||||
.collect();
|
||||
|
||||
let expected: Vec<_> = expected
|
||||
.iter()
|
||||
.map(|name| format!("{name}{exe}", exe = std::env::consts::EXE_SUFFIX))
|
||||
.collect();
|
||||
|
||||
assert_eq!(result, expected, "mismatch for case \"{request}\"");
|
||||
}
|
||||
|
||||
case(
|
||||
"any",
|
||||
&[
|
||||
"python", "python3", "cpython", "cpython3", "pypy", "pypy3", "graalpy", "graalpy3",
|
||||
],
|
||||
);
|
||||
|
||||
case("default", &["python", "python3"]);
|
||||
|
||||
case("3", &["python3", "python"]);
|
||||
|
||||
case("4", &["python4", "python"]);
|
||||
|
||||
case("3.13", &["python3.13", "python3", "python"]);
|
||||
|
||||
case("pypy", &["pypy", "pypy3", "python", "python3"]);
|
||||
|
||||
case(
|
||||
"pypy@3.10",
|
||||
&[
|
||||
"pypy3.10",
|
||||
"pypy3",
|
||||
"pypy",
|
||||
"python3.10",
|
||||
"python3",
|
||||
"python",
|
||||
],
|
||||
);
|
||||
|
||||
case(
|
||||
"3.13t",
|
||||
&[
|
||||
"python3.13t",
|
||||
"python3.13",
|
||||
"python3t",
|
||||
"python3",
|
||||
"pythont",
|
||||
"python",
|
||||
],
|
||||
);
|
||||
case("3t", &["python3t", "python3", "pythont", "python"]);
|
||||
|
||||
case(
|
||||
"3.13.2",
|
||||
&["python3.13.2", "python3.13", "python3", "python"],
|
||||
);
|
||||
|
||||
case(
|
||||
"3.13rc2",
|
||||
&["python3.13rc2", "python3.13", "python3", "python"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,528 +0,0 @@
|
|||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use assert_fs::{prelude::*, TempDir};
|
||||
use test_log::test;
|
||||
use uv_pep440::{Prerelease, PrereleaseKind, VersionSpecifiers};
|
||||
|
||||
use crate::{
|
||||
discovery::{PythonRequest, VersionRequest},
|
||||
implementation::ImplementationName,
|
||||
};
|
||||
|
||||
use super::{Error, PythonVariant};
|
||||
|
||||
#[test]
|
||||
fn interpreter_request_from_str() {
|
||||
assert_eq!(PythonRequest::parse("any"), PythonRequest::Any);
|
||||
assert_eq!(PythonRequest::parse("default"), PythonRequest::Default);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.12"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.12").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(">=3.12"),
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(">=3.12,<3.13"),
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(">=3.12,<3.13"),
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0a1"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0a1").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0b5"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0b5").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.0rc1"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0rc1").unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13.1rc1"),
|
||||
PythonRequest::ExecutableName("3.13.1rc1".to_string()),
|
||||
"Pre-release version requests require a patch version of zero"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3rc1"),
|
||||
PythonRequest::ExecutableName("3rc1".to_string()),
|
||||
"Pre-release version requests require a minor version"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cpython"),
|
||||
PythonRequest::Implementation(ImplementationName::CPython)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cpython3.12.2"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::CPython,
|
||||
VersionRequest::from_str("3.12.2").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy"),
|
||||
PythonRequest::Implementation(ImplementationName::PyPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pp"),
|
||||
PythonRequest::Implementation(ImplementationName::PyPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy"),
|
||||
PythonRequest::Implementation(ImplementationName::GraalPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("gp"),
|
||||
PythonRequest::Implementation(ImplementationName::GraalPy)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cp"),
|
||||
PythonRequest::Implementation(ImplementationName::CPython)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pp310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("gp310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("cp38"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::CPython,
|
||||
VersionRequest::from_str("3.8").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy@3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("pypy310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy@3.10"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("graalpy310"),
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
);
|
||||
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::parse(tempdir.path().to_str().unwrap()),
|
||||
PythonRequest::Directory(tempdir.path().to_path_buf()),
|
||||
"An existing directory is treated as a directory"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse(tempdir.child("foo").path().to_str().unwrap()),
|
||||
PythonRequest::File(tempdir.child("foo").path().to_path_buf()),
|
||||
"A path that does not exist is treated as a file"
|
||||
);
|
||||
tempdir.child("bar").touch().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::parse(tempdir.child("bar").path().to_str().unwrap()),
|
||||
PythonRequest::File(tempdir.child("bar").path().to_path_buf()),
|
||||
"An existing file is treated as a file"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("./foo"),
|
||||
PythonRequest::File(PathBuf::from_str("./foo").unwrap()),
|
||||
"A string with a file system separator is treated as a file"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::parse("3.13t"),
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13t").unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interpreter_request_to_canonical_string() {
|
||||
assert_eq!(PythonRequest::Default.to_canonical_string(), "default");
|
||||
assert_eq!(PythonRequest::Any.to_canonical_string(), "any");
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.12").unwrap()).to_canonical_string(),
|
||||
"3.12"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12").unwrap()).to_canonical_string(),
|
||||
">=3.12"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str(">=3.12,<3.13").unwrap())
|
||||
.to_canonical_string(),
|
||||
">=3.12, <3.13"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0a1").unwrap()).to_canonical_string(),
|
||||
"3.13a1"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0b5").unwrap()).to_canonical_string(),
|
||||
"3.13b5"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("3.13.0rc1").unwrap())
|
||||
.to_canonical_string(),
|
||||
"3.13rc1"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::Version(VersionRequest::from_str("313rc4").unwrap()).to_canonical_string(),
|
||||
"3.13rc4"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
PythonRequest::ExecutableName("foo".to_string()).to_canonical_string(),
|
||||
"foo"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Implementation(ImplementationName::CPython).to_canonical_string(),
|
||||
"cpython"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::CPython,
|
||||
VersionRequest::from_str("3.12.2").unwrap(),
|
||||
)
|
||||
.to_canonical_string(),
|
||||
"cpython@3.12.2"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Implementation(ImplementationName::PyPy).to_canonical_string(),
|
||||
"pypy"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::PyPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
.to_canonical_string(),
|
||||
"pypy@3.10"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::Implementation(ImplementationName::GraalPy).to_canonical_string(),
|
||||
"graalpy"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::ImplementationVersion(
|
||||
ImplementationName::GraalPy,
|
||||
VersionRequest::from_str("3.10").unwrap(),
|
||||
)
|
||||
.to_canonical_string(),
|
||||
"graalpy@3.10"
|
||||
);
|
||||
|
||||
let tempdir = TempDir::new().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::Directory(tempdir.path().to_path_buf()).to_canonical_string(),
|
||||
tempdir.path().to_str().unwrap(),
|
||||
"An existing directory is treated as a directory"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::File(tempdir.child("foo").path().to_path_buf()).to_canonical_string(),
|
||||
tempdir.child("foo").path().to_str().unwrap(),
|
||||
"A path that does not exist is treated as a file"
|
||||
);
|
||||
tempdir.child("bar").touch().unwrap();
|
||||
assert_eq!(
|
||||
PythonRequest::File(tempdir.child("bar").path().to_path_buf()).to_canonical_string(),
|
||||
tempdir.child("bar").path().to_str().unwrap(),
|
||||
"An existing file is treated as a file"
|
||||
);
|
||||
assert_eq!(
|
||||
PythonRequest::File(PathBuf::from_str("./foo").unwrap()).to_canonical_string(),
|
||||
"./foo",
|
||||
"A string with a file system separator is treated as a file"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_request_from_str() {
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3").unwrap(),
|
||||
VersionRequest::Major(3, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.12").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 12, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.12.1").unwrap(),
|
||||
VersionRequest::MajorMinorPatch(3, 12, 1, PythonVariant::Default)
|
||||
);
|
||||
assert!(VersionRequest::from_str("1.foo.1").is_err());
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3").unwrap(),
|
||||
VersionRequest::Major(3, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("38").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 8, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("312").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 12, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3100").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 100, PythonVariant::Default)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13a1").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Alpha,
|
||||
number: 1
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("313b1").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Beta,
|
||||
number: 1
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13.0b2").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Beta,
|
||||
number: 2
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13.0rc3").unwrap(),
|
||||
VersionRequest::MajorMinorPrerelease(
|
||||
3,
|
||||
13,
|
||||
Prerelease {
|
||||
kind: PrereleaseKind::Rc,
|
||||
number: 3
|
||||
},
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3rc1"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Pre-release version requests require a minor version"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.13.2rc1"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Pre-release version requests require a patch version of zero"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.12-dev"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Development version segments are not allowed"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.12+local"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Local version segments are not allowed"
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
VersionRequest::from_str("3.12.post0"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
),
|
||||
"Post version segments are not allowed"
|
||||
);
|
||||
assert!(
|
||||
// Test for overflow
|
||||
matches!(
|
||||
VersionRequest::from_str("31000"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3t").unwrap(),
|
||||
VersionRequest::Major(3, PythonVariant::Freethreaded)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("313t").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 13, PythonVariant::Freethreaded)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str("3.13t").unwrap(),
|
||||
VersionRequest::MajorMinor(3, 13, PythonVariant::Freethreaded)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str(">=3.13t").unwrap(),
|
||||
VersionRequest::Range(
|
||||
VersionSpecifiers::from_str(">=3.13").unwrap(),
|
||||
PythonVariant::Freethreaded
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str(">=3.13").unwrap(),
|
||||
VersionRequest::Range(
|
||||
VersionSpecifiers::from_str(">=3.13").unwrap(),
|
||||
PythonVariant::Default
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
VersionRequest::from_str(">=3.12,<3.14t").unwrap(),
|
||||
VersionRequest::Range(
|
||||
VersionSpecifiers::from_str(">=3.12,<3.14").unwrap(),
|
||||
PythonVariant::Freethreaded
|
||||
)
|
||||
);
|
||||
assert!(matches!(
|
||||
VersionRequest::from_str("3.13tt"),
|
||||
Err(Error::InvalidVersionRequest(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn executable_names_from_request() {
|
||||
fn case(request: &str, expected: &[&str]) {
|
||||
let (implementation, version) = match PythonRequest::parse(request) {
|
||||
PythonRequest::Any => (None, VersionRequest::Any),
|
||||
PythonRequest::Default => (None, VersionRequest::Default),
|
||||
PythonRequest::Version(version) => (None, version),
|
||||
PythonRequest::ImplementationVersion(implementation, version) => {
|
||||
(Some(implementation), version)
|
||||
}
|
||||
PythonRequest::Implementation(implementation) => {
|
||||
(Some(implementation), VersionRequest::Default)
|
||||
}
|
||||
result => {
|
||||
panic!("Test cases should request versions or implementations; got {result:?}")
|
||||
}
|
||||
};
|
||||
|
||||
let result: Vec<_> = version
|
||||
.executable_names(implementation.as_ref())
|
||||
.into_iter()
|
||||
.map(|name| name.to_string())
|
||||
.collect();
|
||||
|
||||
let expected: Vec<_> = expected
|
||||
.iter()
|
||||
.map(|name| format!("{name}{exe}", exe = std::env::consts::EXE_SUFFIX))
|
||||
.collect();
|
||||
|
||||
assert_eq!(result, expected, "mismatch for case \"{request}\"");
|
||||
}
|
||||
|
||||
case(
|
||||
"any",
|
||||
&[
|
||||
"python", "python3", "cpython", "cpython3", "pypy", "pypy3", "graalpy", "graalpy3",
|
||||
],
|
||||
);
|
||||
|
||||
case("default", &["python", "python3"]);
|
||||
|
||||
case("3", &["python3", "python"]);
|
||||
|
||||
case("4", &["python4", "python"]);
|
||||
|
||||
case("3.13", &["python3.13", "python3", "python"]);
|
||||
|
||||
case("pypy", &["pypy", "pypy3", "python", "python3"]);
|
||||
|
||||
case(
|
||||
"pypy@3.10",
|
||||
&[
|
||||
"pypy3.10",
|
||||
"pypy3",
|
||||
"pypy",
|
||||
"python3.10",
|
||||
"python3",
|
||||
"python",
|
||||
],
|
||||
);
|
||||
|
||||
case(
|
||||
"3.13t",
|
||||
&[
|
||||
"python3.13t",
|
||||
"python3.13",
|
||||
"python3t",
|
||||
"python3",
|
||||
"pythont",
|
||||
"python",
|
||||
],
|
||||
);
|
||||
case("3t", &["python3t", "python3", "pythont", "python"]);
|
||||
|
||||
case(
|
||||
"3.13.2",
|
||||
&["python3.13.2", "python3.13", "python3", "python"],
|
||||
);
|
||||
|
||||
case(
|
||||
"3.13rc2",
|
||||
&["python3.13rc2", "python3.13", "python3", "python"],
|
||||
);
|
||||
}
|
||||
|
|
@ -823,4 +823,108 @@ impl InterpreterInfo {
|
|||
|
||||
#[cfg(unix)]
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use fs_err as fs;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use tempfile::tempdir;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_pep440::Version;
|
||||
|
||||
use crate::Interpreter;
|
||||
|
||||
#[test]
|
||||
fn test_cache_invalidation() {
|
||||
let mock_dir = tempdir().unwrap();
|
||||
let mocked_interpreter = mock_dir.path().join("python");
|
||||
let json = indoc! {r##"
|
||||
{
|
||||
"result": "success",
|
||||
"platform": {
|
||||
"os": {
|
||||
"name": "manylinux",
|
||||
"major": 2,
|
||||
"minor": 38
|
||||
},
|
||||
"arch": "x86_64"
|
||||
},
|
||||
"manylinux_compatible": false,
|
||||
"markers": {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.12.0",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "x86_64",
|
||||
"platform_python_implementation": "CPython",
|
||||
"platform_release": "6.5.0-13-generic",
|
||||
"platform_system": "Linux",
|
||||
"platform_version": "#13-Ubuntu SMP PREEMPT_DYNAMIC Fri Nov 3 12:16:05 UTC 2023",
|
||||
"python_full_version": "3.12.0",
|
||||
"python_version": "3.12",
|
||||
"sys_platform": "linux"
|
||||
},
|
||||
"sys_base_exec_prefix": "/home/ferris/.pyenv/versions/3.12.0",
|
||||
"sys_base_prefix": "/home/ferris/.pyenv/versions/3.12.0",
|
||||
"sys_prefix": "/home/ferris/projects/uv/.venv",
|
||||
"sys_executable": "/home/ferris/projects/uv/.venv/bin/python",
|
||||
"sys_path": [
|
||||
"/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/lib/python3.12",
|
||||
"/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/site-packages"
|
||||
],
|
||||
"stdlib": "/home/ferris/.pyenv/versions/3.12.0/lib/python3.12",
|
||||
"scheme": {
|
||||
"data": "/home/ferris/.pyenv/versions/3.12.0",
|
||||
"include": "/home/ferris/.pyenv/versions/3.12.0/include",
|
||||
"platlib": "/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/site-packages",
|
||||
"purelib": "/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/site-packages",
|
||||
"scripts": "/home/ferris/.pyenv/versions/3.12.0/bin"
|
||||
},
|
||||
"virtualenv": {
|
||||
"data": "",
|
||||
"include": "include",
|
||||
"platlib": "lib/python3.12/site-packages",
|
||||
"purelib": "lib/python3.12/site-packages",
|
||||
"scripts": "bin"
|
||||
},
|
||||
"pointer_size": "64",
|
||||
"gil_disabled": true
|
||||
}
|
||||
"##};
|
||||
|
||||
let cache = Cache::temp().unwrap().init().unwrap();
|
||||
|
||||
fs::write(
|
||||
&mocked_interpreter,
|
||||
formatdoc! {r##"
|
||||
#!/bin/bash
|
||||
echo '{json}'
|
||||
"##},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
fs::set_permissions(
|
||||
&mocked_interpreter,
|
||||
std::os::unix::fs::PermissionsExt::from_mode(0o770),
|
||||
)
|
||||
.unwrap();
|
||||
let interpreter = Interpreter::query(&mocked_interpreter, &cache).unwrap();
|
||||
assert_eq!(
|
||||
interpreter.markers.python_version().version,
|
||||
Version::from_str("3.12").unwrap()
|
||||
);
|
||||
fs::write(
|
||||
&mocked_interpreter,
|
||||
formatdoc! {r##"
|
||||
#!/bin/bash
|
||||
echo '{}'
|
||||
"##, json.replace("3.12", "3.13")},
|
||||
)
|
||||
.unwrap();
|
||||
let interpreter = Interpreter::query(&mocked_interpreter, &cache).unwrap();
|
||||
assert_eq!(
|
||||
interpreter.markers.python_version().version,
|
||||
Version::from_str("3.13").unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use fs_err as fs;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use tempfile::tempdir;
|
||||
|
||||
use uv_cache::Cache;
|
||||
use uv_pep440::Version;
|
||||
|
||||
use crate::Interpreter;
|
||||
|
||||
#[test]
|
||||
fn test_cache_invalidation() {
|
||||
let mock_dir = tempdir().unwrap();
|
||||
let mocked_interpreter = mock_dir.path().join("python");
|
||||
let json = indoc! {r##"
|
||||
{
|
||||
"result": "success",
|
||||
"platform": {
|
||||
"os": {
|
||||
"name": "manylinux",
|
||||
"major": 2,
|
||||
"minor": 38
|
||||
},
|
||||
"arch": "x86_64"
|
||||
},
|
||||
"manylinux_compatible": false,
|
||||
"markers": {
|
||||
"implementation_name": "cpython",
|
||||
"implementation_version": "3.12.0",
|
||||
"os_name": "posix",
|
||||
"platform_machine": "x86_64",
|
||||
"platform_python_implementation": "CPython",
|
||||
"platform_release": "6.5.0-13-generic",
|
||||
"platform_system": "Linux",
|
||||
"platform_version": "#13-Ubuntu SMP PREEMPT_DYNAMIC Fri Nov 3 12:16:05 UTC 2023",
|
||||
"python_full_version": "3.12.0",
|
||||
"python_version": "3.12",
|
||||
"sys_platform": "linux"
|
||||
},
|
||||
"sys_base_exec_prefix": "/home/ferris/.pyenv/versions/3.12.0",
|
||||
"sys_base_prefix": "/home/ferris/.pyenv/versions/3.12.0",
|
||||
"sys_prefix": "/home/ferris/projects/uv/.venv",
|
||||
"sys_executable": "/home/ferris/projects/uv/.venv/bin/python",
|
||||
"sys_path": [
|
||||
"/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/lib/python3.12",
|
||||
"/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/site-packages"
|
||||
],
|
||||
"stdlib": "/home/ferris/.pyenv/versions/3.12.0/lib/python3.12",
|
||||
"scheme": {
|
||||
"data": "/home/ferris/.pyenv/versions/3.12.0",
|
||||
"include": "/home/ferris/.pyenv/versions/3.12.0/include",
|
||||
"platlib": "/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/site-packages",
|
||||
"purelib": "/home/ferris/.pyenv/versions/3.12.0/lib/python3.12/site-packages",
|
||||
"scripts": "/home/ferris/.pyenv/versions/3.12.0/bin"
|
||||
},
|
||||
"virtualenv": {
|
||||
"data": "",
|
||||
"include": "include",
|
||||
"platlib": "lib/python3.12/site-packages",
|
||||
"purelib": "lib/python3.12/site-packages",
|
||||
"scripts": "bin"
|
||||
},
|
||||
"pointer_size": "64",
|
||||
"gil_disabled": true
|
||||
}
|
||||
"##};
|
||||
|
||||
let cache = Cache::temp().unwrap().init().unwrap();
|
||||
|
||||
fs::write(
|
||||
&mocked_interpreter,
|
||||
formatdoc! {r##"
|
||||
#!/bin/bash
|
||||
echo '{json}'
|
||||
"##},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
fs::set_permissions(
|
||||
&mocked_interpreter,
|
||||
std::os::unix::fs::PermissionsExt::from_mode(0o770),
|
||||
)
|
||||
.unwrap();
|
||||
let interpreter = Interpreter::query(&mocked_interpreter, &cache).unwrap();
|
||||
assert_eq!(
|
||||
interpreter.markers.python_version().version,
|
||||
Version::from_str("3.12").unwrap()
|
||||
);
|
||||
fs::write(
|
||||
&mocked_interpreter,
|
||||
formatdoc! {r##"
|
||||
#!/bin/bash
|
||||
echo '{}'
|
||||
"##, json.replace("3.12", "3.13")},
|
||||
)
|
||||
.unwrap();
|
||||
let interpreter = Interpreter::query(&mocked_interpreter, &cache).unwrap();
|
||||
assert_eq!(
|
||||
interpreter.markers.python_version().version,
|
||||
Version::from_str("3.13").unwrap()
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -235,4 +235,45 @@ fn find_ld_path_at(path: impl AsRef<Path>) -> Option<PathBuf> {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod tests {
|
||||
use super::*;
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
fn parse_ldd_output() {
|
||||
let ver_str = glibc_ldd_output_to_version(
|
||||
"stdout",
|
||||
indoc! {br"ld.so (Ubuntu GLIBC 2.39-0ubuntu8.3) stable release version 2.39.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions.
|
||||
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
"},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ver_str,
|
||||
LibcVersion::Manylinux {
|
||||
major: 2,
|
||||
minor: 39
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_musl_ld_output() {
|
||||
// This output was generated by running `/lib/ld-musl-x86_64.so.1`
|
||||
// in an Alpine Docker image. The Alpine version:
|
||||
//
|
||||
// # cat /etc/alpine-release
|
||||
// 3.19.1
|
||||
let output = b"\
|
||||
musl libc (x86_64)
|
||||
Version 1.2.4_git20230717
|
||||
Dynamic Program Loader
|
||||
Usage: /lib/ld-musl-x86_64.so.1 [options] [--] pathname [args]\
|
||||
";
|
||||
let got = musl_ld_output_to_version("stderr", output).unwrap();
|
||||
assert_eq!(got, LibcVersion::Musllinux { major: 1, minor: 2 });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
use super::*;
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
fn parse_ldd_output() {
|
||||
let ver_str = glibc_ldd_output_to_version(
|
||||
"stdout",
|
||||
indoc! {br"ld.so (Ubuntu GLIBC 2.39-0ubuntu8.3) stable release version 2.39.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions.
|
||||
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
"},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ver_str,
|
||||
LibcVersion::Manylinux {
|
||||
major: 2,
|
||||
minor: 39
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_musl_ld_output() {
|
||||
// This output was generated by running `/lib/ld-musl-x86_64.so.1`
|
||||
// in an Alpine Docker image. The Alpine version:
|
||||
//
|
||||
// # cat /etc/alpine-release
|
||||
// 3.19.1
|
||||
let output = b"\
|
||||
musl libc (x86_64)
|
||||
Version 1.2.4_git20230717
|
||||
Dynamic Program Loader
|
||||
Usage: /lib/ld-musl-x86_64.so.1 [options] [--] pathname [args]\
|
||||
";
|
||||
let got = musl_ld_output_to_version("stderr", output).unwrap();
|
||||
assert_eq!(got, LibcVersion::Musllinux { major: 1, minor: 2 });
|
||||
}
|
||||
|
|
@ -168,4 +168,37 @@ impl PythonVersion {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use uv_pep440::{Prerelease, PrereleaseKind, Version};
|
||||
|
||||
use crate::PythonVersion;
|
||||
|
||||
#[test]
|
||||
fn python_markers() {
|
||||
let version = PythonVersion::from_str("3.11.0").expect("valid python version");
|
||||
assert_eq!(version.python_version(), Version::new([3, 11]));
|
||||
assert_eq!(version.python_version().to_string(), "3.11");
|
||||
assert_eq!(version.python_full_version(), Version::new([3, 11, 0]));
|
||||
assert_eq!(version.python_full_version().to_string(), "3.11.0");
|
||||
|
||||
let version = PythonVersion::from_str("3.11").expect("valid python version");
|
||||
assert_eq!(version.python_version(), Version::new([3, 11]));
|
||||
assert_eq!(version.python_version().to_string(), "3.11");
|
||||
assert_eq!(version.python_full_version(), Version::new([3, 11, 0]));
|
||||
assert_eq!(version.python_full_version().to_string(), "3.11.0");
|
||||
|
||||
let version = PythonVersion::from_str("3.11.8a1").expect("valid python version");
|
||||
assert_eq!(version.python_version(), Version::new([3, 11]));
|
||||
assert_eq!(version.python_version().to_string(), "3.11");
|
||||
assert_eq!(
|
||||
version.python_full_version(),
|
||||
Version::new([3, 11, 8]).with_pre(Some(Prerelease {
|
||||
kind: PrereleaseKind::Alpha,
|
||||
number: 1
|
||||
}))
|
||||
);
|
||||
assert_eq!(version.python_full_version().to_string(), "3.11.8a1");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use uv_pep440::{Prerelease, PrereleaseKind, Version};
|
||||
|
||||
use crate::PythonVersion;
|
||||
|
||||
#[test]
|
||||
fn python_markers() {
|
||||
let version = PythonVersion::from_str("3.11.0").expect("valid python version");
|
||||
assert_eq!(version.python_version(), Version::new([3, 11]));
|
||||
assert_eq!(version.python_version().to_string(), "3.11");
|
||||
assert_eq!(version.python_full_version(), Version::new([3, 11, 0]));
|
||||
assert_eq!(version.python_full_version().to_string(), "3.11.0");
|
||||
|
||||
let version = PythonVersion::from_str("3.11").expect("valid python version");
|
||||
assert_eq!(version.python_version(), Version::new([3, 11]));
|
||||
assert_eq!(version.python_version().to_string(), "3.11");
|
||||
assert_eq!(version.python_full_version(), Version::new([3, 11, 0]));
|
||||
assert_eq!(version.python_full_version().to_string(), "3.11.0");
|
||||
|
||||
let version = PythonVersion::from_str("3.11.8a1").expect("valid python version");
|
||||
assert_eq!(version.python_version(), Version::new([3, 11]));
|
||||
assert_eq!(version.python_version().to_string(), "3.11");
|
||||
assert_eq!(
|
||||
version.python_full_version(),
|
||||
Version::new([3, 11, 8]).with_pre(Some(Prerelease {
|
||||
kind: PrereleaseKind::Alpha,
|
||||
number: 1
|
||||
}))
|
||||
);
|
||||
assert_eq!(version.python_full_version().to_string(), "3.11.8a1");
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue