From eec0c284d083de9b64e252d1f37a9cd53a9f9bea Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 5 Mar 2026 18:40:39 -0500 Subject: [PATCH] Add an environment variable for `UV_VENV_RELOCATABLE` (#18331) Closes https://github.com/astral-sh/uv/issues/18319. --- crates/uv-cli/src/lib.rs | 3 ++- crates/uv-settings/src/lib.rs | 2 ++ crates/uv-static/src/env_vars.rs | 5 +++++ crates/uv/src/settings.rs | 1 + crates/uv/tests/it/venv.rs | 23 +++++++++++++++++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index e2a7281d6..a9d4f17bf 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -3166,7 +3166,7 @@ pub struct VenvArgs { #[arg(long)] pub system_site_packages: bool, - /// Make the virtual environment relocatable. + /// Make the virtual environment relocatable [env: UV_VENV_RELOCATABLE=] /// /// A relocatable virtual environment can be moved around and redistributed without invalidating /// its associated entrypoint and activation scripts. @@ -3179,6 +3179,7 @@ pub struct VenvArgs { /// absolute paths), the entrypoints and scripts themselves will _not_ be relocatable. In other /// words, copying those entrypoints and scripts to a location outside the environment will not /// work, as they reference paths relative to the environment itself. + #[expect(clippy::doc_markdown)] #[arg(long, overrides_with("no_relocatable"))] pub relocatable: bool, diff --git a/crates/uv-settings/src/lib.rs b/crates/uv-settings/src/lib.rs index 8d7492281..358d47e4d 100644 --- a/crates/uv-settings/src/lib.rs +++ b/crates/uv-settings/src/lib.rs @@ -663,6 +663,7 @@ pub struct EnvironmentOptions { pub no_env_file: EnvFlag, pub venv_seed: EnvFlag, pub venv_clear: EnvFlag, + pub venv_relocatable: EnvFlag, pub init_bare: EnvFlag, } @@ -756,6 +757,7 @@ impl EnvironmentOptions { no_env_file: EnvFlag::new(EnvVars::UV_NO_ENV_FILE)?, venv_seed: EnvFlag::new(EnvVars::UV_VENV_SEED)?, venv_clear: EnvFlag::new(EnvVars::UV_VENV_CLEAR)?, + venv_relocatable: EnvFlag::new(EnvVars::UV_VENV_RELOCATABLE)?, init_bare: EnvFlag::new(EnvVars::UV_INIT_BARE)?, }) } diff --git a/crates/uv-static/src/env_vars.rs b/crates/uv-static/src/env_vars.rs index 8ce16e0a5..9a5627160 100644 --- a/crates/uv-static/src/env_vars.rs +++ b/crates/uv-static/src/env_vars.rs @@ -477,6 +477,11 @@ impl EnvVars { #[attr_added_in("0.8.0")] pub const UV_VENV_CLEAR: &'static str = "UV_VENV_CLEAR"; + /// Equivalent to the `--relocatable` command-line argument. If set, the virtual + /// environment will be relocatable. + #[attr_added_in("0.10.8")] + pub const UV_VENV_RELOCATABLE: &'static str = "UV_VENV_RELOCATABLE"; + /// Install seed packages (one or more of: `pip`, `setuptools`, and `wheel`) into the virtual environment /// created by `uv venv`. /// diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 7e256bca5..1655a7457 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -3489,6 +3489,7 @@ impl VenvSettings { // Resolve flags from CLI and environment variables. let seed = seed || environment.venv_seed.value == Some(true); let clear = clear || environment.venv_clear.value == Some(true); + let relocatable = relocatable || environment.venv_relocatable.value == Some(true); Self { seed, diff --git a/crates/uv/tests/it/venv.rs b/crates/uv/tests/it/venv.rs index 6e19d9fcc..89460e250 100644 --- a/crates/uv/tests/it/venv.rs +++ b/crates/uv/tests/it/venv.rs @@ -1307,6 +1307,29 @@ fn verify_pyvenv_cfg_relocatable() { activate_csh.assert(predicates::path::missing()); } +/// With `UV_VENV_RELOCATABLE=1`, the virtual environment is relocatable. +#[test] +fn verify_pyvenv_cfg_relocatable_env_var() { + let context = uv_test::test_context!("3.12"); + + // Create a virtual environment at `.venv` with the env var. + context + .venv() + .arg(context.venv.as_os_str()) + .arg("--clear") + .arg("--python") + .arg("3.12") + .env("UV_VENV_RELOCATABLE", "1") + .assert() + .success(); + + let pyvenv_cfg = context.venv.child("pyvenv.cfg"); + pyvenv_cfg.assert(predicates::path::is_file()); + + // Relocatable flag is set. + pyvenv_cfg.assert(predicates::str::contains("relocatable = true")); +} + /// With `relocatable-envs-default` preview feature, venvs are relocatable by default. #[test] fn relocatable_envs_default_preview() {