diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 95f951e37653..2faf98e3ed3d 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -4498,11 +4498,13 @@ pub struct PythonInstallArgs { /// The Python version(s) to install. /// - /// If not provided, the requested Python version(s) will be read from the `.python-versions` or - /// `.python-version` files. If neither file is present, uv will check if it has installed any - /// Python versions. If not, it will install the latest stable version of Python. + /// If not provided, the requested Python version(s) will be read from the `UV_PYTHON` + /// environment variable then `.python-versions` or `.python-version` files. If none of the + /// above are present, uv will check if it has installed any Python versions. If not, it will + /// install the latest stable version of Python. /// /// See `uv help python` to view supported request formats. + #[arg(env = EnvVars::UV_PYTHON)] pub targets: Vec, /// Set the URL to use as the source for downloading Python installations. diff --git a/crates/uv/tests/it/help.rs b/crates/uv/tests/it/help.rs index f677508ff4d4..c55b70819049 100644 --- a/crates/uv/tests/it/help.rs +++ b/crates/uv/tests/it/help.rs @@ -480,11 +480,14 @@ fn help_subsubcommand() { [TARGETS]... The Python version(s) to install. - If not provided, the requested Python version(s) will be read from the `.python-versions` - or `.python-version` files. If neither file is present, uv will check if it has installed - any Python versions. If not, it will install the latest stable version of Python. + If not provided, the requested Python version(s) will be read from the `UV_PYTHON` + environment variable then `.python-versions` or `.python-version` files. If none of the + above are present, uv will check if it has installed any Python versions. If not, it will + install the latest stable version of Python. See `uv help python` to view supported request formats. + + [env: UV_PYTHON=] Options: -i, --install-dir @@ -772,7 +775,7 @@ fn help_flag_subsubcommand() { Usage: uv python install [OPTIONS] [TARGETS]... Arguments: - [TARGETS]... The Python version(s) to install + [TARGETS]... The Python version(s) to install [env: UV_PYTHON=] Options: -i, --install-dir The directory to store the Python installation in [env: diff --git a/crates/uv/tests/it/python_install.rs b/crates/uv/tests/it/python_install.rs index 345dba5e62f7..aedcc399f50e 100644 --- a/crates/uv/tests/it/python_install.rs +++ b/crates/uv/tests/it/python_install.rs @@ -1,13 +1,13 @@ use std::{path::Path, process::Command}; +use crate::common::{uv_snapshot, TestContext}; use assert_fs::{ assert::PathAssert, prelude::{FileTouch, PathChild, PathCreateDir}, }; use predicates::prelude::predicate; use uv_fs::Simplified; - -use crate::common::{uv_snapshot, TestContext}; +use uv_static::EnvVars; #[test] fn python_install() { @@ -1058,9 +1058,96 @@ fn python_install_preview_broken_link() { }); } +#[test] +fn python_install_default_from_env() { + let context: TestContext = TestContext::new_with_versions(&[]) + .with_filtered_python_keys() + .with_filtered_exe_suffix() + .with_managed_python_dirs(); + + // Install the version specified by the `UV_PYTHON` environment variable by default + uv_snapshot!(context.filters(), context.python_install().env(EnvVars::UV_PYTHON, "3.12"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Installed Python 3.12.9 in [TIME] + + cpython-3.12.9-[PLATFORM] + "); + + // But prefer explicit requests + uv_snapshot!(context.filters(), context.python_install().arg("3.11").env(EnvVars::UV_PYTHON, "3.12"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Installed Python 3.11.11 in [TIME] + + cpython-3.11.11-[PLATFORM] + "###); + + // We should ignore `UV_PYTHON` here and complain there is not a target + uv_snapshot!(context.filters(), context.python_uninstall().env(EnvVars::UV_PYTHON, "3.12"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the following required arguments were not provided: + ... + + Usage: uv python uninstall --install-dir ... + + For more information, try '--help'. + "###); + + // We should ignore `UV_PYTHON` here and respect `--all` + uv_snapshot!(context.filters(), context.python_uninstall().arg("--all").env(EnvVars::UV_PYTHON, "3.11"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Searching for Python installations + Uninstalled 2 versions in [TIME] + - cpython-3.11.11-[PLATFORM] + - cpython-3.12.9-[PLATFORM] + "###); + + // Uninstall with no targets should error + uv_snapshot!(context.filters(), context.python_uninstall(), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the following required arguments were not provided: + ... + + Usage: uv python uninstall --install-dir ... + + For more information, try '--help'. + "###); + + // Uninstall with conflicting options should error + uv_snapshot!(context.filters(), context.python_uninstall().arg("--all").arg("3.12"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the argument '--all' cannot be used with '...' + + Usage: uv python uninstall --all --install-dir ... + + For more information, try '--help'. + "###); +} + #[cfg(target_os = "macos")] #[test] -fn python_dylib_install_name_is_patched_on_install() { +fn python_install_patch_dylib() { use assert_cmd::assert::OutputAssertExt; use uv_python::managed::platform_key_from_env; diff --git a/docs/reference/cli.md b/docs/reference/cli.md index ffc82994da7e..e4145f21eca0 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -4788,7 +4788,7 @@ uv python install [OPTIONS] [TARGETS]...
TARGETS

The Python version(s) to install.

-

If not provided, the requested Python version(s) will be read from the .python-versions or .python-version files. If neither file is present, uv will check if it has installed any Python versions. If not, it will install the latest stable version of Python.

+

If not provided, the requested Python version(s) will be read from the UV_PYTHON environment variable then .python-versions or .python-version files. If none of the above are present, uv will check if it has installed any Python versions. If not, it will install the latest stable version of Python.

See uv python to view supported request formats.