#[cfg(windows)]
use std::path::PathBuf;
use std::{env, path::Path, process::Command};
use anyhow::Context;
use assert_cmd::assert::OutputAssertExt;
use assert_fs::{
assert::PathAssert,
prelude::{FileTouch, FileWriteStr, PathChild, PathCreateDir},
};
use indoc::indoc;
use predicates::prelude::predicate;
use tracing::debug;
use uv_test::{LATEST_PYTHON_3_12, uv_snapshot};
use uv_fs::Simplified;
use uv_python::managed::platform_key_from_env;
use uv_static::EnvVars;
use walkdir::WalkDir;
#[test]
fn python_install() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install(), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
let bin_python = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
#[cfg(unix)]
bin_python.assert(predicate::path::is_symlink());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), Command::new(bin_python.as_os_str())
.arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install(), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python is already installed. Use `uv python install <request>` to install another version.
");
uv_snapshot!(context.filters(), context.python_install().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.14 is already installed
");
uv_snapshot!(context.filters(), context.python_install().arg("3.14").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
~ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context.python_uninstall(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the following required arguments were not provided:
<TARGETS>...
Usage: uv python uninstall --cache-dir [CACHE_DIR] --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.14
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python.assert(predicate::path::missing());
}
#[test]
fn python_reinstall() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("3.12").arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
~ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_install().arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
~ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
~ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.11").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.11.[LATEST] in [TIME]
+ cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
}
#[test]
fn python_reinstall_patch() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("3.12.6").arg("3.12.7"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.6-[PLATFORM]
+ cpython-3.12.7-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.[LATEST] in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
");
}
#[test]
fn python_install_automatic() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_python_sources()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.arg("--no-python-downloads")
.arg("python").arg("-c").arg("import sys; print(sys.version_info[:2])"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found in [PYTHON SOURCES]
hint: A managed Python download is available, but Python downloads are set to 'never'
");
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.arg("python").arg("-c").arg("import sys; print(sys.version_info[:2])"), @"
success: true
exit_code: 0
----- stdout -----
(3, 14)
----- stderr -----
");
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.arg("--no-python-downloads")
.arg("python").arg("-c").arg("import sys; print(sys.version_info[:2])"), @"
success: true
exit_code: 0
----- stdout -----
(3, 14)
----- stderr -----
");
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.arg("-p").arg("3.12")
.arg("python").arg("-c").arg("import sys; print(sys.version_info[:2])"), @"
success: true
exit_code: 0
----- stdout -----
(3, 12)
----- stderr -----
");
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.arg("-p").arg("foobar")
.arg("python").arg("-c").arg("import sys; print(sys.version_info[:2])"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for executable name `foobar` in [PYTHON SOURCES]
");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let contents = r"#!/bin/sh
echo 'error: intentionally broken python executable' >&2
exit 1";
let python = context
.bin_dir
.join(format!("python3{}", std::env::consts::EXE_SUFFIX));
fs_err::write(&python, contents).unwrap();
let mut perms = fs_err::metadata(&python).unwrap().permissions();
perms.set_mode(0o755);
fs_err::set_permissions(&python, perms).unwrap();
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.env(EnvVars::UV_PYTHON_SEARCH_PATH, context.bin_dir.as_os_str())
.arg("-p").arg("3.11")
.arg("python").arg("-c").arg("import sys; print(sys.version_info[:2])"), @"
success: true
exit_code: 0
----- stdout -----
(3, 11)
----- stderr -----
");
}
}
#[test]
fn regression_cpython() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_python_sources()
.with_managed_python_dirs()
.with_python_download_cache();
let init = context.temp_dir.child("mre.py");
init.write_str(indoc! { r#"
class Foo(str): ...
a = []
new_value = Foo("1")
a += new_value
"#
})
.unwrap();
uv_snapshot!(context.filters(), context.run()
.env_remove(EnvVars::VIRTUAL_ENV)
.arg("-p").arg("3.12")
.arg("mre.py"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
");
}
#[test]
fn python_install_force() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs();
uv_snapshot!(context.filters(), context.python_install(), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
let bin_python = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
uv_snapshot!(context.filters(), context.python_install().arg("--force"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python.assert(predicate::path::exists());
fs_err::remove_file(bin_python.path()).unwrap();
bin_python.touch().unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: Failed to install executable for cpython-3.14.[LATEST]-[PLATFORM]
Caused by: Executable already exists at `[BIN]/python3.14` but is not managed by uv; use `--force` to replace it
");
uv_snapshot!(context.filters(), context.python_install().arg("--force").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python.assert(predicate::path::exists());
}
#[test]
fn python_install_minor() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs();
uv_snapshot!(context.filters(), context.python_install().arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.11.[LATEST] in [TIME]
+ cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
let bin_python = context
.bin_dir
.child(format!("python3.11{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.11-[PLATFORM]/bin/python3.11"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.11-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.11
Uninstalled Python 3.11.[LATEST] in [TIME]
- cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
bin_python.assert(predicate::path::missing());
}
#[test]
fn python_install_multiple_patch() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs();
uv_snapshot!(context.filters(), context.python_install().arg("3.12.8").arg("3.12.6"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.6-[PLATFORM]
+ cpython-3.12.8-[PLATFORM] (python3.12)
");
let bin_python = context
.bin_dir
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.8-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.8-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12.8
Uninstalled Python 3.12.8 in [TIME]
- cpython-3.12.8-[PLATFORM] (python3.12)
");
}
#[test]
fn python_install_preview() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
let bin_python = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
#[cfg(unix)]
bin_python.assert(predicate::path::is_symlink());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), Command::new(bin_python.as_os_str())
.arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python is already installed. Use `uv python install <request>` to install another version.
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
~ cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--force"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python.assert(predicate::path::exists());
fs_err::remove_file(bin_python.path()).unwrap();
bin_python.touch().unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: Failed to install executable for cpython-3.14.[LATEST]-[PLATFORM]
Caused by: Executable already exists at `[BIN]/python3.14` but is not managed by uv; use `--force` to replace it
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--bin").arg("3.14"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to install executable for cpython-3.14.[LATEST]-[PLATFORM]
Caused by: Executable already exists at `[BIN]/python3.14` but is not managed by uv; use `--force` to replace it
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.14").env(EnvVars::UV_PYTHON_INSTALL_BIN, "1"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to install executable for cpython-3.14.[LATEST]-[PLATFORM]
Caused by: Executable already exists at `[BIN]/python3.14` but is not managed by uv; use `--force` to replace it
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--no-bin").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.14 is already installed
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.14").env(EnvVars::UV_PYTHON_INSTALL_BIN, "0"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.14 is already installed
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--force").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python.assert(predicate::path::exists());
#[cfg(unix)]
bin_python.assert(predicate::path::is_symlink());
uv_snapshot!(context.filters(), context.python_uninstall(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the following required arguments were not provided:
<TARGETS>...
Usage: uv python uninstall --cache-dir [CACHE_DIR] --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.14
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("3.11").arg("--preview"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.11.[LATEST] in [TIME]
+ cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
let bin_python = context
.bin_dir
.child(format!("python3.11{}", std::env::consts::EXE_SUFFIX));
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.11-[PLATFORM]/bin/python3.11"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.11-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.11
Uninstalled Python 3.11.[LATEST] in [TIME]
- cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.8").arg("3.12.6"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.6-[PLATFORM]
+ cpython-3.12.8-[PLATFORM] (python3.12)
");
let bin_python = context
.bin_dir
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.8-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.8-[PLATFORM]/python"
);
});
}
}
#[test]
fn python_install_preview_no_bin() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--no-bin"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM]
");
let bin_python = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--no-bin").arg("--default"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the argument '--no-bin' cannot be used with '--default'
Usage: uv python install --cache-dir [CACHE_DIR] --no-bin --install-dir <INSTALL_DIR> [TARGETS]...
For more information, try '--help'.
");
let bin_python = context
.bin_dir
.child(format!("python{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::missing());
}
#[test]
fn python_install_preview_upgrade() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
let bin_python = context
.bin_dir
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.5"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.5 in [TIME]
+ cpython-3.12.5-[PLATFORM] (python3.12)
");
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.5-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.5-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.4"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.4 in [TIME]
+ cpython-3.12.4-[PLATFORM]
");
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.5-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.5-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.4").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.4 in [TIME]
~ cpython-3.12.4-[PLATFORM]
");
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.5-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.5-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.4").arg("--force"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.4 in [TIME]
+ cpython-3.12.4-[PLATFORM] (python3.12)
");
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.4-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.4-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.6"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.6 in [TIME]
+ cpython-3.12.6-[PLATFORM] (python3.12)
");
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.6-[PLATFORM]/bin/python3.12"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.12.6-[PLATFORM]/python"
);
});
}
}
#[test]
fn python_install_freethreaded() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.13t"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]+freethreaded-[PLATFORM] (python3.13t)
");
let bin_python = context
.bin_dir
.child(format!("python3.13t{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
#[cfg(unix)]
bin_python.assert(predicate::path::is_symlink());
uv_snapshot!(context.filters(), Command::new(bin_python.as_os_str())
.arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13t"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13+freethreaded"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("3.13t"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.13.[LATEST]+freethreaded
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
let scripts = context
.venv
.join(if cfg!(windows) { "Scripts" } else { "bin" });
assert!(
scripts
.join(format!("python{}", std::env::consts::EXE_SUFFIX))
.exists()
);
#[cfg(windows)]
assert!(
scripts
.join(format!("pythonw{}", std::env::consts::EXE_SUFFIX))
.exists()
);
#[cfg(unix)]
assert!(
scripts
.join(format!("python3{}", std::env::consts::EXE_SUFFIX))
.exists()
);
#[cfg(unix)]
assert!(
scripts
.join(format!("python3.13{}", std::env::consts::EXE_SUFFIX))
.exists()
);
assert!(
scripts
.join(format!("python3.13t{}", std::env::consts::EXE_SUFFIX))
.exists()
);
#[cfg(windows)]
assert!(
scripts
.join(format!("pythonw3.13t{}", std::env::consts::EXE_SUFFIX))
.exists()
);
fs_err::remove_dir_all(&context.venv).unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12t"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No download found for request: cpython-3.12+freethreaded-[PLATFORM]
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled 2 versions in [TIME]
- cpython-3.13.[LATEST]+freethreaded-[PLATFORM] (python3.13t)
- cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
}
#[cfg(all(windows, feature = "test-windows-registry"))]
#[test]
fn python_install_freethreaded_and_gil_list() {
use assert_cmd::assert::OutputAssertExt;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix()
.with_collapsed_whitespace();
context
.python_install()
.arg("3.13")
.env_remove(EnvVars::UV_PYTHON_NO_REGISTRY)
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1")
.assert()
.success();
context
.python_install()
.arg("--preview")
.arg("3.13t")
.env_remove(EnvVars::UV_PYTHON_NO_REGISTRY)
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1")
.assert()
.success();
uv_snapshot!(context.filters(), context.python_list()
.arg("3.13")
.arg("--only-installed")
.arg("--managed-python")
.env_remove(EnvVars::UV_PYTHON_NO_REGISTRY)
.env_remove(EnvVars::UV_PYTHON_SEARCH_PATH)
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1"), @"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]-[PLATFORM] managed/cpython-3.13.[LATEST]-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
cpython-3.13.[LATEST]-[PLATFORM] [BIN]/[INSTALL-BIN]/[PYTHON]
cpython-3.13.[LATEST]-[PLATFORM] managed/cpython-3.13-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_list()
.arg("3.13t")
.arg("--only-installed")
.arg("--managed-python")
.env_remove(EnvVars::UV_PYTHON_NO_REGISTRY)
.env_remove(EnvVars::UV_PYTHON_SEARCH_PATH)
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1"), @"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]+freethreaded-[PLATFORM] managed/cpython-3.13.[LATEST]+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
cpython-3.13.[LATEST]+freethreaded-[PLATFORM] [BIN]/python3.13t
cpython-3.13.[LATEST]+freethreaded-[PLATFORM] managed/cpython-3.13+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
context
.python_uninstall()
.arg("--all")
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1")
.assert()
.success();
}
#[cfg(all(windows, feature = "test-windows-registry"))]
#[test]
fn python_install_registry_takes_precedence_over_no_registry() {
use assert_cmd::assert::OutputAssertExt;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix()
.with_collapsed_whitespace();
context
.python_install()
.arg("3.13")
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1")
.env(EnvVars::UV_PYTHON_NO_REGISTRY, "1")
.assert()
.success();
uv_snapshot!(context.filters(), context.python_list()
.arg("3.13")
.arg("--only-installed")
.arg("--managed-python")
.env_remove(EnvVars::UV_PYTHON_NO_REGISTRY)
.env(EnvVars::UV_PYTHON_SEARCH_PATH, "")
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1"), @"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]-[PLATFORM] managed/cpython-3.13.[LATEST]-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
cpython-3.13.[LATEST]-[PLATFORM] managed/cpython-3.13-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
context
.python_uninstall()
.arg("--all")
.env(EnvVars::UV_PYTHON_INSTALL_REGISTRY, "1")
.assert()
.success();
}
#[test]
fn python_upgrade_not_allowed() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs();
uv_snapshot!(context.filters(), context.python_upgrade().arg("--preview").arg("3.13.0"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: `uv python upgrade` only accepts minor versions, got: 3.13.0
");
uv_snapshot!(context.filters(), context.python_upgrade().arg("--preview").arg("3.14rc3"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: `uv python upgrade` only accepts minor versions, got: 3.14rc3
");
}
#[cfg(unix)]
#[test]
fn python_install_debug() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.13+debug"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]+debug-[PLATFORM] (python3.13d)
");
let bin_python = context
.bin_dir
.child(format!("python3.13d{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
#[cfg(unix)]
bin_python.assert(predicate::path::is_symlink());
uv_snapshot!(context.filters(), Command::new(bin_python.as_os_str())
.arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13d"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+debug-[PLATFORM]/bin/python3.13d
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+debug-[PLATFORM]/bin/python3.13d
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13-[PLATFORM]/bin/python3.13
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13d"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+debug-[PLATFORM]/bin/python3.13d
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13+debug"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+debug-[PLATFORM]/bin/python3.13d
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12d"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.[LATEST] in [TIME]
+ cpython-3.12.[LATEST]+debug-[PLATFORM] (python3.12d)
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled 3 versions in [TIME]
- cpython-3.12.[LATEST]+debug-[PLATFORM] (python3.12d)
- cpython-3.13.[LATEST]+debug-[PLATFORM] (python3.13d)
- cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
}
#[cfg(unix)]
#[test]
fn python_install_debug_freethreaded() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.13td"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]+freethreaded+debug-[PLATFORM] (python3.13td)
");
let bin_python = context
.bin_dir
.child(format!("python3.13td{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
#[cfg(unix)]
bin_python.assert(predicate::path::is_symlink());
uv_snapshot!(context.filters(), Command::new(bin_python.as_os_str())
.arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13td"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+freethreaded+debug-[PLATFORM]/bin/python3.13td
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for Python 3.13 in virtual environments, managed installations, or search path
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13+freethreaded+debug"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+freethreaded+debug-[PLATFORM]/bin/python3.13td
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13t"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]+freethreaded-[PLATFORM] (python3.13t)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13d"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]+debug-[PLATFORM] (python3.13d)
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13-[PLATFORM]/bin/python3.13
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13t"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+freethreaded-[PLATFORM]/bin/python3.13t
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13td"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13+freethreaded+debug-[PLATFORM]/bin/python3.13td
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled 4 versions in [TIME]
- cpython-3.13.[LATEST]+freethreaded+debug-[PLATFORM] (python3.13td)
- cpython-3.13.[LATEST]+freethreaded-[PLATFORM] (python3.13t)
- cpython-3.13.[LATEST]+debug-[PLATFORM] (python3.13d)
- cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
}
#[test]
fn python_install_invalid_request() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("foobar"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `foobar` is not a valid Python download request; see `uv help python` for supported formats and `uv python list --only-downloads` for available versions
");
uv_snapshot!(context.filters(), context.python_install().arg("3.8.0"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No download found for request: cpython-3.8.0-[PLATFORM]
");
uv_snapshot!(context.filters(), context.python_install().arg("3.8.0").arg("3.12"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No download found for request: cpython-3.8.0-[PLATFORM]
");
}
#[test]
fn python_install_default() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
let bin_python_minor_14 = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
let bin_python_major = context
.bin_dir
.child(format!("python3{}", std::env::consts::EXE_SUFFIX));
let bin_python_default = context
.bin_dir
.child(format!("python{}", std::env::consts::EXE_SUFFIX));
uv_snapshot!(context.filters(), context.python_install().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::missing());
bin_python_default.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("--default").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::missing());
bin_python_major.assert(predicate::path::missing());
bin_python_default.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("--default"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.14
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::missing());
bin_python_major.assert(predicate::path::missing());
bin_python_default.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("3.12").arg("3.14").arg("--default"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
error: The `--default` flag cannot be used with multiple targets
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12").arg("--default"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
Installed Python 3.12.[LATEST] in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python, python3, python3.12)
");
let bin_python_minor_12 = context
.bin_dir
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
bin_python_minor_12.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/bin/python3.12"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/bin/python3.12"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/bin/python3.12"
);
});
} else {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/python"
);
});
}
}
#[test]
fn python_install_default_preview() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
let bin_python_minor_14 = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
let bin_python_major = context
.bin_dir
.child(format!("python3{}", std::env::consts::EXE_SUFFIX));
let bin_python_default = context
.bin_dir
.child(format!("python{}", std::env::consts::EXE_SUFFIX));
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::missing());
bin_python_default.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--default").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::missing());
bin_python_major.assert(predicate::path::missing());
bin_python_default.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("--default").arg("--preview"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/bin/python3.14"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/bin/python3.14"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/bin/python3.14"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/python"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.14
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::missing());
bin_python_major.assert(predicate::path::missing());
bin_python_default.assert(predicate::path::missing());
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12").arg("3.14").arg("--default"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: The `--default` flag cannot be used with multiple targets
");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12").arg("--default"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.[LATEST] in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python, python3, python3.12)
");
let bin_python_minor_12 = context
.bin_dir
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
bin_python_minor_12.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/bin/python3.12"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/bin/python3.12"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/bin/python3.12"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/bin/python3.12"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/bin/python3.12"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/bin/python3.12"
);
});
} else {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/python"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/python"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/python"
);
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/python"
);
});
}
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.14").arg("--default"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python, python3, python3.14)
");
bin_python_minor_14.assert(predicate::path::exists());
bin_python_minor_12.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
if cfg!(unix) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/bin/python3.14"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/bin/python3.14"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/bin/python3.12"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/bin/python3.14"
);
});
} else if cfg!(windows) {
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_major), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_14), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_minor_12), @"[TEMP_DIR]/managed/cpython-3.12.[LATEST]-[PLATFORM]/python"
);
});
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python_default), @"[TEMP_DIR]/managed/cpython-3.14.[LATEST]-[PLATFORM]/python"
);
});
}
}
#[cfg(windows)]
fn launcher_path(path: &Path) -> PathBuf {
let launcher = uv_trampoline_builder::Launcher::try_from_path(path)
.unwrap_or_else(|_| panic!("{} should be readable", path.display()))
.unwrap_or_else(|| panic!("{} should be a valid launcher", path.display()));
launcher.python_path
}
fn canonicalize_link_path(path: &Path) -> String {
#[cfg(unix)]
let canonical_path = fs_err::canonicalize(path);
#[cfg(windows)]
let canonical_path = dunce::canonicalize(launcher_path(path));
canonical_path
.unwrap_or_else(|_| panic!("{} should be readable", path.display()))
.simplified_display()
.to_string()
}
fn read_link(path: &Path) -> String {
#[cfg(unix)]
let linked_path =
fs_err::read_link(path).unwrap_or_else(|_| panic!("{} should be readable", path.display()));
#[cfg(windows)]
let linked_path = launcher_path(path);
linked_path.simplified_display().to_string()
}
#[test]
fn python_install_unknown() {
let context = uv_test::test_context_with_versions!(&[])
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("foobar"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `foobar` is not a valid Python download request; see `uv help python` for supported formats and `uv python list --only-downloads` for available versions
");
context.temp_dir.child("foo").create_dir_all().unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("./foo"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: `./foo` is not a valid Python download request; see `uv help python` for supported formats and `uv python list --only-downloads` for available versions
");
}
#[cfg(unix)]
#[test]
fn python_install_broken_link() {
use assert_fs::prelude::PathCreateDir;
use fs_err::os::unix::fs::symlink;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_latest_python_versions();
let bin_python = context.bin_dir.child("python3.13");
context.bin_dir.create_dir_all().unwrap();
symlink(context.temp_dir.join("does-not-exist"), &bin_python).unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
canonicalize_link_path(&bin_python), @"[TEMP_DIR]/managed/cpython-3.13.[LATEST]-[PLATFORM]/bin/python3.13"
);
});
}
#[test]
fn python_install_default_prerelease() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
context
.python_install()
.arg("--default")
.arg("--preview-features")
.arg("python-install-default")
.arg("3.15")
.assert()
.success();
let bin_python_minor_15 = context
.bin_dir
.child(format!("python3.15{}", std::env::consts::EXE_SUFFIX));
let bin_python_major = context
.bin_dir
.child(format!("python3{}", std::env::consts::EXE_SUFFIX));
let bin_python_default = context
.bin_dir
.child(format!("python{}", std::env::consts::EXE_SUFFIX));
bin_python_minor_15.assert(predicate::path::exists());
bin_python_major.assert(predicate::path::exists());
bin_python_default.assert(predicate::path::exists());
}
#[test]
fn python_install_default_from_env() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().env(EnvVars::UV_PYTHON, "3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.[LATEST] in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.11").env(EnvVars::UV_PYTHON, "3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.11.[LATEST] in [TIME]
+ cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
uv_snapshot!(context.filters(), context.python_uninstall().env(EnvVars::UV_PYTHON, "3.12"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the following required arguments were not provided:
<TARGETS>...
Usage: uv python uninstall --cache-dir [CACHE_DIR] --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all").env(EnvVars::UV_PYTHON, "3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled 2 versions in [TIME]
- cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
- cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_uninstall(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the following required arguments were not provided:
<TARGETS>...
Usage: uv python uninstall --cache-dir [CACHE_DIR] --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all").arg("3.12"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the argument '--all' cannot be used with '<TARGETS>...'
Usage: uv python uninstall --cache-dir [CACHE_DIR] --all --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
");
}
#[cfg(target_os = "macos")]
#[test]
fn python_install_patch_dylib() {
use assert_cmd::assert::OutputAssertExt;
use uv_python::managed::platform_key_from_env;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_managed_python_dirs()
.with_python_download_cache();
context
.python_install()
.arg("--preview")
.arg("3.13.1")
.assert()
.success();
let dylib = context
.temp_dir
.child("managed")
.child(format!(
"cpython-3.13.1-{}",
platform_key_from_env().unwrap()
))
.child("lib")
.child(format!(
"{}python3.13{}",
std::env::consts::DLL_PREFIX,
std::env::consts::DLL_SUFFIX
));
let mut cmd = std::process::Command::new("otool");
cmd.arg("-D").arg(dylib.as_ref());
uv_snapshot!(context.filters(), cmd, @r###"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13.1-[PLATFORM]/lib/libpython3.13.dylib:
[TEMP_DIR]/managed/cpython-3.13.1-[PLATFORM]/lib/libpython3.13.dylib
----- stderr -----
"###);
}
#[test]
fn python_install_prerelease() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_exe_suffix();
uv_snapshot!(context.filters(), context.python_install().arg("3.15"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.15.[LATEST] in [TIME]
+ cpython-3.15.[LATEST]-[PLATFORM] (python3.15)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.15.0a2"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.15.0a2 in [TIME]
+ cpython-3.15.0a2-[PLATFORM]
");
uv_snapshot!(context.filters(), context.python_install().arg("3.14.5rc1"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.5rc1 in [TIME]
+ cpython-3.14.5rc1-[PLATFORM] (python3.14)
");
}
#[test]
fn python_find_prerelease() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix();
context.python_install().arg("3.15").assert().success();
context.python_install().arg("3.15.0a2").assert().success();
uv_snapshot!(context.filters(), context.python_find().arg("3.15"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.15-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg(">=3.15"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.15-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.15-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_find().arg("3"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
}
#[test]
fn python_install_cached() {
if env::var_os(EnvVars::UV_PYTHON_CACHE_DIR).is_some() && env::var_os(EnvVars::CI).is_none() {
debug!("Skipping test because `UV_PYTHON_CACHE_DIR` is set");
return;
}
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_filtered_latest_python_versions();
let python_cache = context.temp_dir.child("python-cache");
uv_snapshot!(context.filters(), context
.python_install()
.env(EnvVars::UV_PYTHON_CACHE_DIR, python_cache.as_ref()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
let bin_python = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context
.python_install()
.env(EnvVars::UV_PYTHON_CACHE_DIR, python_cache.as_ref()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python is already installed. Use `uv python install <request>` to install another version.
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.14
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
uv_snapshot!(context.filters(), context
.python_install()
.arg("--offline")
.env(EnvVars::UV_PYTHON_CACHE_DIR, python_cache.as_ref()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
let context = context.with_filter((
"cpython-3.12.*.tar.gz",
"cpython-3.12.[PATCH]-[DATE]-[PLATFORM].tar.gz",
));
uv_snapshot!(context.filters(), context
.python_install()
.arg("3.12")
.arg("--offline")
.env(EnvVars::UV_PYTHON_CACHE_DIR, python_cache.as_ref()), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to install cpython-3.12.[LATEST]-[PLATFORM]
Caused by: An offline Python installation was requested, but cpython-3.12.[PATCH]-[DATE]-[PLATFORM].tar.gz) is missing in python-cache
");
}
#[test]
fn python_install_no_cache() {
if env::var_os(EnvVars::UV_PYTHON_CACHE_DIR).is_some() && env::var_os(EnvVars::CI).is_none() {
debug!("Skipping test because `UV_PYTHON_CACHE_DIR` is set");
return;
}
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install(), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
let bin_python = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context.python_install(), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python is already installed. Use `uv python install <request>` to install another version.
");
uv_snapshot!(context.filters(), context.python_install().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.14 is already installed
");
uv_snapshot!(context.filters(), context.python_install().arg("3.14").arg("--reinstall"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
~ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
uv_snapshot!(context.filters(), context.python_uninstall(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the following required arguments were not provided:
<TARGETS>...
Usage: uv python uninstall --cache-dir [CACHE_DIR] --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
");
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.14
Uninstalled Python 3.14.[LATEST] in [TIME]
- cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
let context = context
.with_filter((
"cpython-3.12.*.tar.gz",
"cpython-3.12.[PATCH]-[DATE]-[PLATFORM].tar.gz",
))
.with_filter((r"releases/download/\d{8}/", "releases/download/[DATE]/"));
uv_snapshot!(context.filters(), context
.python_install()
.arg("3.12")
.arg("--offline"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to install cpython-3.12.[LATEST]-[PLATFORM]
Caused by: Failed to download https://github.com/astral-sh/python-build-standalone/releases/download/[DATE]/cpython-3.12.[PATCH]-[DATE]-[PLATFORM].tar.gz
Caused by: Network connectivity is disabled, but the requested data wasn't found in the cache for: `https://github.com/astral-sh/python-build-standalone/releases/download/[DATE]/cpython-3.12.[PATCH]-[DATE]-[PLATFORM].tar.gz`
");
}
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
#[test]
fn python_install_emulated_macos() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_latest_python_versions();
let arch_status = Command::new("/usr/bin/arch")
.arg("-x86_64")
.arg("true")
.status();
if !arch_status.is_ok_and(|x| x.success()) {
#[expect(clippy::manual_assert)]
if env::var(EnvVars::CI).is_ok() {
panic!("x86_64 emulation is not available on this CI runner");
}
debug!("Skipping test because x86_64 emulation is not available");
return;
}
uv_snapshot!(context.filters(), context.python_list().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]-macos-aarch64-none <download available>
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13-x86_64"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-macos-x86_64-none (python3.13)
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13").arg("--resolve-links"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13.[LATEST]-macos-x86_64-none/bin/python3.13
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_list().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]-macos-aarch64-none <download available>
cpython-3.13.[LATEST]-macos-x86_64-none managed/cpython-3.13-macos-x86_64-none/bin/python3.13
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13-aarch64"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-macos-aarch64-none
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13").arg("--resolve-links"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13.[LATEST]-macos-aarch64-none/bin/python3.13
----- stderr -----
");
}
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
#[test]
fn python_install_emulated_windows_x86_on_x64() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_list().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]-windows-x86_64-none <download available>
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13-x86"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-windows-x86-none (python3.13)
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13-windows-x86-none/python
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_list().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
cpython-3.13.[LATEST]-windows-x86_64-none <download available>
cpython-3.13.[LATEST]-windows-x86-none managed/cpython-3.13-windows-x86-none/python
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_install().arg("3.13-x86_64"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-windows-x86_64-none
");
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13-windows-x86_64-none/python
----- stderr -----
");
}
#[test]
fn install_managed_venv_allow_existing() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_latest_python_versions()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.13")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.13.[LATEST]
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.13")
.arg("--allow-existing")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.13.[LATEST]
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
}
#[test]
fn install_transparent_patch_upgrade_uv_venv() {
let context = uv_test::test_context_with_versions!(&["3.13"])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.9"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.9 in [TIME]
+ cpython-3.12.9-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.12")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.9
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.9
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.11 in [TIME]
+ cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.11
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.8 in [TIME]
+ cpython-3.12.8-[PLATFORM]
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.11
----- stderr -----
"
);
}
#[test]
fn install_multiple_patches() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.9").arg("3.12.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.9-[PLATFORM]
+ cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.12")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.11
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.11
----- stderr -----
"
);
fs_err::remove_dir_all(&context.venv).unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.10.17").arg("3.10.16"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.10.16-[PLATFORM]
+ cpython-3.10.17-[PLATFORM] (python3.10)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.10")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.10.17
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.10.17
----- stderr -----
"
);
}
#[test]
fn uninstall_highest_patch() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.11").arg("3.12.9").arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 3 versions in [TIME]
+ cpython-3.12.8-[PLATFORM]
+ cpython-3.12.9-[PLATFORM]
+ cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.12")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.11
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.11
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.python_uninstall().arg("--preview").arg("3.12.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12.11
Uninstalled Python 3.12.11 in [TIME]
- cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.9
----- stderr -----
"
);
}
#[test]
fn install_no_transparent_upgrade_with_venv_patch_specification() {
let context = uv_test::test_context_with_versions!(&["3.13"])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.9"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.9 in [TIME]
+ cpython-3.12.9-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.12.9")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.9
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.9
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.11 in [TIME]
+ cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.9
----- stderr -----
"
);
}
#[test]
fn install_transparent_patch_upgrade_venv_module() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
let bin_dir = context.temp_dir.child("bin");
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.9"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.9 in [TIME]
+ cpython-3.12.9-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.9
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("-m").arg("venv").arg(context.venv.as_os_str()).arg("--without-pip")
.env(EnvVars::PATH, bin_dir.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
");
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.9
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.11 in [TIME]
+ cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.11
----- stderr -----
"
);
}
#[test]
fn install_lower_patch_automatically() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.11 in [TIME]
+ cpython-3.12.11-[PLATFORM] (python3.12)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.12")
.arg(context.venv.as_os_str()), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.11
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.init().arg("-p").arg("3.12.9").arg("proj"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Initialized project `proj` at `[TEMP_DIR]/proj`
"
);
uv_snapshot!(context.filters(), context.venv()
.arg("--directory").arg("proj")
.arg("-p").arg("3.12.9"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.9
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.12.11
----- stderr -----
"
);
}
#[test]
fn uninstall_last_patch() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_virtualenv_bin();
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.10.17"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.10.17 in [TIME]
+ cpython-3.10.17-[PLATFORM] (python3.10)
"
);
uv_snapshot!(context.filters(), context.venv().arg("-p").arg("3.10"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.10.17
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
"
);
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: true
exit_code: 0
----- stdout -----
Python 3.10.17
----- stderr -----
"
);
uv_snapshot!(context.filters(), context.python_uninstall().arg("--preview").arg("3.10.17"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.10.17
Uninstalled Python 3.10.17 in [TIME]
- cpython-3.10.17-[PLATFORM] (python3.10)
"
);
let context = context.with_filter(("python3", "python"));
#[cfg(unix)]
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to inspect Python interpreter from active virtual environment at `.venv/[BIN]/python`
Caused by: Broken symlink at `.venv/[BIN]/python`, was the underlying Python interpreter removed?
hint: Consider recreating the environment (e.g., with `uv venv`)
"
);
#[cfg(windows)]
uv_snapshot!(context.filters(), context.run().arg("python").arg("--version"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to inspect Python interpreter from active virtual environment at `.venv/[BIN]/python`
Caused by: Python interpreter not found at `[VENV]/[BIN]/python`
"
);
}
#[test]
fn uninstall_last_patch_removes_minor_version_link() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
let managed_dir = context.temp_dir.child("managed");
let platform_key = platform_key_from_env().unwrap();
let minor_version_link = managed_dir.child(format!("cpython-3.12-{platform_key}"));
let patch_dir = managed_dir.child(format!("cpython-3.12.8-{platform_key}"));
uv_snapshot!(context.filters(), context.python_install().arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.8 in [TIME]
+ cpython-3.12.8-[PLATFORM] (python3.12)
");
patch_dir.assert(predicate::path::exists());
minor_version_link.assert(predicate::path::exists());
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12.8
Uninstalled Python 3.12.8 in [TIME]
- cpython-3.12.8-[PLATFORM] (python3.12)
");
patch_dir.assert(predicate::path::missing());
assert!(
minor_version_link.path().symlink_metadata().is_err(),
"minor version link should be removed after uninstalling the last patch, \
but it still exists at: {}",
minor_version_link.path().display()
);
}
#[test]
fn uninstall_highest_patch_updates_minor_version_link() {
use uv_python::managed::platform_key_from_env;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin();
let managed_dir = context.temp_dir.child("managed");
let platform_key = platform_key_from_env().unwrap();
let minor_version_link = managed_dir.child(format!("cpython-3.12-{platform_key}"));
let patch_dir_8 = managed_dir.child(format!("cpython-3.12.8-{platform_key}"));
let patch_dir_9 = managed_dir.child(format!("cpython-3.12.9-{platform_key}"));
uv_snapshot!(context.filters(), context.python_install().arg("3.12.9").arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.8-[PLATFORM]
+ cpython-3.12.9-[PLATFORM] (python3.12)
");
patch_dir_8.assert(predicate::path::exists());
patch_dir_9.assert(predicate::path::exists());
minor_version_link.assert(predicate::path::exists());
let link_target = dunce::canonicalize(minor_version_link.path())
.unwrap()
.simplified_display()
.to_string();
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
link_target, @"[TEMP_DIR]/managed/cpython-3.12.9-[PLATFORM]"
);
});
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.12.9"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12.9
Uninstalled Python 3.12.9 in [TIME]
- cpython-3.12.9-[PLATFORM] (python3.12)
");
patch_dir_9.assert(predicate::path::missing());
patch_dir_8.assert(predicate::path::exists());
minor_version_link.assert(predicate::path::exists());
let link_target = dunce::canonicalize(minor_version_link.path())
.unwrap()
.simplified_display()
.to_string();
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
link_target, @"[TEMP_DIR]/managed/cpython-3.12.8-[PLATFORM]"
);
});
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.12.8"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12.8
Uninstalled Python 3.12.8 in [TIME]
- cpython-3.12.8-[PLATFORM]
");
patch_dir_8.assert(predicate::path::missing());
assert!(
minor_version_link.path().symlink_metadata().is_err(),
"minor version link should be removed after uninstalling the last patch, \
but it still exists at: {}",
minor_version_link.path().display()
);
}
#[cfg(unix)] #[test]
fn python_install_pyodide() {
use assert_cmd::assert::OutputAssertExt;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("cpython-3.13.2-emscripten-wasm32-musl"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.2 in [TIME]
+ pyodide-3.13.2-emscripten-wasm32-musl (pyodide3.13)
");
let bin_python = context
.bin_dir
.child(format!("pyodide3.13{}", std::env::consts::EXE_SUFFIX));
bin_python.assert(predicate::path::exists());
bin_python.assert(predicate::path::is_symlink());
insta::with_settings!({
filters => context.filters(),
}, {
insta::assert_snapshot!(
read_link(&bin_python), @"[TEMP_DIR]/managed/pyodide-3.13.2-emscripten-wasm32-musl/python"
);
});
uv_snapshot!(context.filters(), Command::new(bin_python.as_os_str())
.arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("cpython-3.13.2-emscripten-wasm32-musl"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/pyodide-3.13.2-emscripten-wasm32-musl/python
----- stderr -----
");
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("cpython-3.13.2-emscripten-wasm32-musl"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.13.2
Creating virtual environment at: .venv
Activate with: source .venv/[BIN]/activate
");
uv_snapshot!(context.filters(), context.python_command().arg("-c").arg("import subprocess; print('hello world')"), @"
success: true
exit_code: 0
----- stdout -----
hello world
----- stderr -----
");
context.python_uninstall().arg("--all").assert().success();
fs_err::remove_dir_all(&context.venv).unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("pyodide"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.2 in [TIME]
+ pyodide-3.13.2-emscripten-wasm32-musl (pyodide3.13)
");
context.python_uninstall().arg("--all").assert().success();
uv_snapshot!(context.filters(), context.python_install().arg("pyodide@3.13"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.2 in [TIME]
+ pyodide-3.13.2-emscripten-wasm32-musl (pyodide3.13)
");
uv_snapshot!(context.filters(), context.python_find().arg("pyodide"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/pyodide-3.13.2-emscripten-wasm32-musl/python
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find(), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found in virtual environments, managed installations, or search path
");
uv_snapshot!(context.filters(), context.python_find().arg("cpython"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for CPython in virtual environments, managed installations, or search path
");
let context = context.with_filtered_python_keys();
uv_snapshot!(context.filters(), context.python_install().arg("cpython"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
uv_snapshot!(context.filters(), context.python_find().arg("any"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.14-[PLATFORM]/bin/python3.14
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("pyodide"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/pyodide-3.13.2-emscripten-wasm32-musl/python
----- stderr -----
");
}
#[test]
fn python_install_build_version() {
use uv_python::managed::platform_key_from_env;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_sources()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix();
uv_snapshot!(context.filters(), context.python_install()
.arg("3.12")
.env(EnvVars::UV_PYTHON_CPYTHON_BUILD, "20240814"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.5 in [TIME]
+ cpython-3.12.5-[PLATFORM] (python3.12)
");
let cpython_dir = context.temp_dir.child("managed").child(format!(
"cpython-3.12.5-{}",
platform_key_from_env().unwrap()
));
let build_file_path = cpython_dir.join("BUILD");
let build_content = fs_err::read_to_string(&build_file_path).unwrap();
assert_eq!(build_content, "20240814");
uv_snapshot!(context.filters(), context.python_find()
.arg("3.12")
.env(EnvVars::UV_PYTHON_CPYTHON_BUILD, "20240814"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.12-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find()
.arg("3.12")
.env(EnvVars::UV_PYTHON_CPYTHON_BUILD, "99999999"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for Python 3.12 in [PYTHON SOURCES]
");
uv_snapshot!(context.filters(), context.python_install()
.arg("3.12")
.env(EnvVars::UV_PYTHON_CPYTHON_BUILD, "99999999"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No download found for request: cpython-3.12-[PLATFORM]
");
uv_snapshot!(context.filters(), context.python_install()
.arg("3.12.10")
.env(EnvVars::UV_PYTHON_CPYTHON_BUILD, "20250814"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No download found for request: cpython-3.12.10-[PLATFORM]
");
}
#[test]
fn python_install_build_version_pypy() {
use uv_python::managed::platform_key_from_env;
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_python_sources()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix();
uv_snapshot!(context.filters(), context.python_install()
.arg("pypy3.10")
.env(EnvVars::UV_PYTHON_PYPY_BUILD, "7.3.19"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.10.16 in [TIME]
+ pypy-3.10.16-[PLATFORM] (pypy3.10)
");
let pypy_dir = context
.temp_dir
.child("managed")
.child(format!("pypy-3.10.16-{}", platform_key_from_env().unwrap()));
let build_file_path = pypy_dir.join("BUILD");
let build_content = fs_err::read_to_string(&build_file_path).unwrap();
assert_eq!(build_content, "7.3.19");
uv_snapshot!(context.filters(), context.python_find()
.arg("pypy3.10")
.env(EnvVars::UV_PYTHON_PYPY_BUILD, "7.3.19"), @"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/pypy-3.10.16-[PLATFORM]/[INSTALL-BIN]/[PYPY]
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find()
.arg("pypy3.10")
.env(EnvVars::UV_PYTHON_PYPY_BUILD, "99.99.99"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for PyPy 3.10 in [PYTHON SOURCES]
");
uv_snapshot!(context.filters(), context.python_install()
.arg("pypy3.10")
.env(EnvVars::UV_PYTHON_PYPY_BUILD, "99.99.99"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No download found for request: pypy-3.10-[PLATFORM]
");
}
#[test]
fn python_install_upgrade() {
let context = uv_test::test_context_with_versions!(&[])
.with_python_download_cache()
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
The default Python installation is already on the latest supported patch release. Use `uv python install <request>` to install another version.
");
uv_snapshot!(context.filters(), context.python_install().arg("3.10.17"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.10.17 in [TIME]
+ cpython-3.10.17-[PLATFORM] (python3.10)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.10"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.10.[LATEST] in [TIME]
+ cpython-3.10.[LATEST]-[PLATFORM] (python3.10)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.11.4"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: `uv python install --upgrade` only accepts minor versions, got: 3.11.4
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.11.[LATEST] in [TIME]
+ cpython-3.11.[LATEST]-[PLATFORM] (python3.11)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.11 is already on the latest supported patch release
");
uv_snapshot!(context.filters(), context.python_install().arg("3.9.5"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.9.5 in [TIME]
+ cpython-3.9.5-[PLATFORM] (python3.9)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.11 is already on the latest supported patch release
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.10").arg("3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
All requested versions already on latest supported patch release
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.9").arg("3.10").arg("3.11").arg("3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.9.25-[PLATFORM] (python3.9)
+ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
");
}
#[test]
fn python_install_upgrade_version_file() {
let context = uv_test::test_context_with_versions!(&[])
.with_python_download_cache()
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_filtered_latest_python_versions();
context.python_pin().arg("3.13").assert().success();
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.[LATEST] in [TIME]
+ cpython-3.13.[LATEST]-[PLATFORM] (python3.13)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.13 is already on the latest supported patch release
");
context.python_pin().arg("3.12.4").assert().success();
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: `uv python install --upgrade` only accepts minor versions, got: 3.12.4
hint: The version request came from a `.python-version` file; change the patch version in the file to upgrade instead
");
}
#[test]
fn python_install_armv7() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_sources()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix();
uv_snapshot!(context.filters(), context.python_install().arg("cpython-3.12.12-linux-armv7-musl"), @"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: uv does not yet provide musl Python distributions on armv7.
");
uv_snapshot!(context.filters(), context.python_install().arg("cpython-3.12.12-linux-armv7-gnueabi"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.12 in [TIME]
+ cpython-3.12.12-[PLATFORM] (python3.12)
");
}
#[test]
fn python_install_compile_bytecode() -> anyhow::Result<()> {
fn count_files_by_ext(dir: &Path, extension: &str) -> anyhow::Result<usize> {
let mut count = 0;
let walker = WalkDir::new(dir).into_iter();
for entry in walker {
let entry = entry?;
let path = entry.path();
if entry.metadata()?.is_file() && path.extension().is_some_and(|ext| ext == extension) {
count += 1;
}
}
Ok(count)
}
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
Bytecode compiled [COUNT] files in [TIME]
");
let bin_path = context
.bin_dir
.child(format!("python3.14{}", std::env::consts::EXE_SUFFIX));
#[cfg(unix)]
let stdlib = fs_err::read_link(bin_path)?
.parent()
.context("Python binary should be a child of `bin`")?
.parent()
.context("`bin` directory should be a child of the installation path")?
.join("lib")
.join("python3.14");
#[cfg(windows)]
let stdlib = launcher_path(&bin_path)
.parent()
.context("Python binary should be a child of the installation path")?
.join("Lib");
let pyc_count = count_files_by_ext(&stdlib, "pyc")?;
let py_count = count_files_by_ext(&stdlib, "py")?;
assert_eq!(pyc_count, py_count);
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.14 is already installed
Bytecode compiled [COUNT] files in [TIME]
");
uv_snapshot!(context.filters(), context.python_install().arg("--reinstall").arg("--compile-bytecode").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
~ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
Bytecode compiled [COUNT] files in [TIME]
");
Ok(())
}
#[test]
fn python_install_compile_bytecode_existing() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
");
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.14 is already installed
Bytecode compiled [COUNT] files in [TIME]
");
}
#[test]
fn python_install_compile_bytecode_upgrade() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("3.14.0"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.0 in [TIME]
+ cpython-3.14.0-[PLATFORM] (python3.14)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("--compile-bytecode").arg("3.14"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.[LATEST] in [TIME]
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
Bytecode compiled [COUNT] files in [TIME]
");
}
#[test]
fn python_install_upgrade_build_version() {
let context = uv_test::test_context_with_versions!(&[])
.with_python_download_cache()
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.[LATEST] in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.12 is already on the latest supported patch release
");
let installation_dir = context.temp_dir.child("managed").child(format!(
"cpython-{}-{}",
LATEST_PYTHON_3_12,
platform_key_from_env().unwrap()
));
let build_file = installation_dir.join("BUILD");
fs_err::write(&build_file, "19000101").unwrap();
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.[LATEST] in [TIME]
~ cpython-3.12.[LATEST]-[PLATFORM]
");
uv_snapshot!(context.filters(), context.python_install().arg("--upgrade").arg("3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Python 3.12 is already on the latest supported patch release
");
}
#[test]
fn python_install_compile_bytecode_multiple() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache()
.with_filtered_latest_python_versions();
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("3.14").arg("3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 2 versions in [TIME]
+ cpython-3.12.[LATEST]-[PLATFORM] (python3.12)
+ cpython-3.14.[LATEST]-[PLATFORM] (python3.14)
Bytecode compiled [COUNT] files in [TIME]
");
}
#[cfg(unix)] #[test]
fn python_install_compile_bytecode_pyodide() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("cpython-3.13.2-emscripten-wasm32-musl"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.2 in [TIME]
+ pyodide-3.13.2-emscripten-wasm32-musl (pyodide3.13)
No compatible versions to bytecode compile (skipped 1)
");
}
#[test]
fn python_install_compile_bytecode_graalpy() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("graalpy-3.12"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.0 in [TIME]
+ graalpy-3.12.0-[PLATFORM] (graalpy3.12)
Bytecode compiled [COUNT] files in [TIME]
");
}
#[test]
fn python_install_compile_bytecode_pypy() {
let context = uv_test::test_context_with_versions!(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_filtered_compiled_file_count()
.with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("--compile-bytecode").arg("pypy-3.11"), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.11.15 in [TIME]
+ pypy-3.11.15-[PLATFORM] (pypy3.11)
Bytecode compiled [COUNT] files in [TIME]
");
}