Require tests to opt-in to managed Python installation (#10912)

First of all, I want to test automatic managed installs (see #10913) and
need to set that up. Second of all, some tests were _implicitly_
downloading interpreters instead of using the one from their context —
which is unexpected and naughty and very slow.
This commit is contained in:
Zanie Blue 2025-01-23 15:24:40 -06:00 committed by GitHub
parent a05b0e0346
commit fd5131cb7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 44 deletions

View file

@ -102,6 +102,9 @@ pub struct TestContext {
/// Standard filters for this test context.
filters: Vec<(String, String)>,
/// Extra environment variables to apply to all commands.
extra_env: Vec<(OsString, OsString)>,
#[allow(dead_code)]
_root: tempfile::TempDir,
}
@ -233,6 +236,29 @@ impl TestContext {
self
}
/// Add extra directories and configuration for managed Python installations.
#[must_use]
pub fn with_managed_python_dirs(mut self) -> Self {
let managed = self.temp_dir.join("managed");
let bin = self.temp_dir.join("bin");
self.extra_env.push((
EnvVars::PATH.into(),
env::join_paths(std::iter::once(bin.clone()).chain(env::split_paths(
&env::var(EnvVars::PATH).unwrap_or_default(),
)))
.unwrap(),
));
self.extra_env
.push((EnvVars::UV_PYTHON_BIN_DIR.into(), bin.into()));
self.extra_env
.push((EnvVars::UV_PYTHON_INSTALL_DIR.into(), managed.into()));
self.extra_env
.push((EnvVars::UV_PYTHON_DOWNLOADS.into(), "automatic".into()));
self
}
/// Discover the path to the XDG state directory. We use this, rather than the OS-specific
/// temporary directory, because on macOS (and Windows on GitHub Actions), they involve
/// symlinks. (On macOS, the temporary directory is, like `/var/...`, which resolves to
@ -456,6 +482,7 @@ impl TestContext {
python_version,
python_versions,
filters,
extra_env: vec![],
_root: root,
}
}
@ -510,12 +537,18 @@ impl TestContext {
.env(EnvVars::PATH, path)
.env(EnvVars::HOME, self.home_dir.as_os_str())
.env(EnvVars::UV_PYTHON_INSTALL_DIR, "")
// Installations are not allowed by default; see `Self::with_managed_python_dirs`
.env(EnvVars::UV_PYTHON_DOWNLOADS, "never")
.env(EnvVars::UV_TEST_PYTHON_PATH, self.python_path())
.env(EnvVars::UV_EXCLUDE_NEWER, EXCLUDE_NEWER)
.env_remove(EnvVars::UV_CACHE_DIR)
.env_remove(EnvVars::UV_TOOL_BIN_DIR)
.current_dir(self.temp_dir.path());
for (key, value) in &self.extra_env {
command.env(key, value);
}
if activate_venv {
command.env(EnvVars::VIRTUAL_ENV, self.venv.as_os_str());
}
@ -677,21 +710,10 @@ impl TestContext {
/// Create a `uv python install` command with options shared across scenarios.
pub fn python_install(&self) -> Command {
let mut command = self.new_command();
let managed = self.temp_dir.join("managed");
let bin = self.temp_dir.join("bin");
self.add_shared_args(&mut command, true);
command
.arg("python")
.arg("install")
.env(EnvVars::UV_PYTHON_INSTALL_DIR, managed)
.env(EnvVars::UV_PYTHON_BIN_DIR, bin.as_os_str())
.env(
EnvVars::PATH,
env::join_paths(std::iter::once(bin).chain(env::split_paths(
&env::var(EnvVars::PATH).unwrap_or_default(),
)))
.unwrap(),
)
.current_dir(&self.temp_dir);
command
}
@ -699,14 +721,10 @@ impl TestContext {
/// Create a `uv python uninstall` command with options shared across scenarios.
pub fn python_uninstall(&self) -> Command {
let mut command = self.new_command();
let managed = self.temp_dir.join("managed");
let bin = self.temp_dir.join("bin");
self.add_shared_args(&mut command, true);
command
.arg("python")
.arg("uninstall")
.env(EnvVars::UV_PYTHON_INSTALL_DIR, managed)
.env(EnvVars::UV_PYTHON_BIN_DIR, bin)
.current_dir(&self.temp_dir);
command
}

View file

@ -3394,7 +3394,7 @@ fn shared_optional_dependency_mixed1() -> Result<()> {
/// Regression test for: <https://github.com/astral-sh/uv/issues/9640>
#[test]
fn shared_optional_dependency_extra2() -> Result<()> {
let context = TestContext::new("3.12");
let context = TestContext::new("3.11");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
@ -3432,9 +3432,6 @@ fn shared_optional_dependency_extra2() -> Result<()> {
----- stdout -----
----- stderr -----
Using CPython 3.11.11
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 5 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
@ -3536,7 +3533,7 @@ fn shared_optional_dependency_extra2() -> Result<()> {
/// Regression test for: <https://github.com/astral-sh/uv/issues/9640>
#[test]
fn shared_optional_dependency_group2() -> Result<()> {
let context = TestContext::new("3.12");
let context = TestContext::new("3.11");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
@ -3574,9 +3571,6 @@ fn shared_optional_dependency_group2() -> Result<()> {
----- stdout -----
----- stderr -----
Using CPython 3.11.11
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 5 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
@ -3682,7 +3676,7 @@ fn shared_optional_dependency_group2() -> Result<()> {
/// Regression test for: <https://github.com/astral-sh/uv/issues/9640>
#[test]
fn shared_optional_dependency_mixed2() -> Result<()> {
let context = TestContext::new("3.12");
let context = TestContext::new("3.11");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
@ -3722,9 +3716,6 @@ fn shared_optional_dependency_mixed2() -> Result<()> {
----- stdout -----
----- stderr -----
Using CPython 3.11.11
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 5 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
@ -4364,7 +4355,7 @@ fn shared_dependency_mixed() -> Result<()> {
/// Ref <https://github.com/astral-sh/uv/issues/9289>
#[test]
fn extras_are_namespaced() -> Result<()> {
let context = TestContext::new("3.12");
let context = TestContext::new("3.11");
let root_pyproject_toml = context.temp_dir.child("pyproject.toml");
root_pyproject_toml.write_str(
@ -4423,9 +4414,6 @@ conflicts = [
----- stdout -----
----- stderr -----
Using CPython 3.11.11
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 7 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
@ -7297,7 +7285,7 @@ fn deduplicate_resolution_markers() -> Result<()> {
#[test]
fn overlapping_resolution_markers() -> Result<()> {
let context = TestContext::new("3.12");
let context = TestContext::new("3.10");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
@ -7305,7 +7293,7 @@ fn overlapping_resolution_markers() -> Result<()> {
[project]
name = "ads-mega-model"
version = "0.1.0"
requires-python = "==3.10.12"
requires-python = "==3.10.*"
dependencies = [
"wandb==0.17.6",
]
@ -7344,7 +7332,6 @@ fn overlapping_resolution_markers() -> Result<()> {
----- stdout -----
----- stderr -----
Using CPython 3.10.12
Resolved 45 packages in [TIME]
"###);
@ -7356,7 +7343,7 @@ fn overlapping_resolution_markers() -> Result<()> {
lock,
@r###"
version = 1
requires-python = "==3.10.12"
requires-python = "==3.10.*"
resolution-markers = [
"sys_platform == 'linux' and extra != 'extra-14-ads-mega-model-cpu' and extra == 'extra-14-ads-mega-model-cu118'",
"sys_platform != 'linux' and extra != 'extra-14-ads-mega-model-cpu' and extra == 'extra-14-ads-mega-model-cu118'",

View file

@ -13,7 +13,8 @@ use crate::common::{uv_snapshot, TestContext};
fn python_install() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
// Install the latest version
uv_snapshot!(context.filters(), context.python_install(), @r###"
@ -95,7 +96,8 @@ fn python_install() {
fn python_install_preview() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
// Install the latest version
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r###"
@ -269,7 +271,8 @@ fn python_install_preview() {
fn python_install_preview_upgrade() {
let context = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
let bin_python = context
.temp_dir
@ -408,7 +411,8 @@ fn python_install_preview_upgrade() {
fn python_install_freethreaded() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
// Install the latest version
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.13t"), @r###"
@ -482,7 +486,8 @@ fn python_install_freethreaded() {
fn python_install_invalid_request() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
// Request something that is not a Python version
uv_snapshot!(context.filters(), context.python_install().arg("foobar"), @r###"
@ -519,7 +524,8 @@ fn python_install_invalid_request() {
fn python_install_default() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
let bin_python_minor_13 = context
.temp_dir
@ -815,7 +821,7 @@ fn read_link_path(path: &Path) -> String {
#[test]
fn python_install_unknown() {
let context: TestContext = TestContext::new_with_versions(&[]);
let context: TestContext = TestContext::new_with_versions(&[]).with_managed_python_dirs();
// An unknown request
uv_snapshot!(context.filters(), context.python_install().arg("foobar"), @r###"
@ -848,7 +854,8 @@ fn python_install_preview_broken_link() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix();
.with_filtered_exe_suffix()
.with_managed_python_dirs();
let bin_python = context.temp_dir.child("bin").child("python3.13");
@ -883,7 +890,9 @@ fn python_dylib_install_name_is_patched_on_install() {
use assert_cmd::assert::OutputAssertExt;
use uv_python::managed::platform_key_from_env;
let context: TestContext = TestContext::new_with_versions(&[]).with_filtered_python_keys();
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_managed_python_dirs();
// Install the latest version
context

View file

@ -0,0 +1 @@
3.12

View file

@ -0,0 +1 @@
3.12