Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3170,9 +3170,16 @@ 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.
#[arg(long)]
#[arg(long, overrides_with("no_relocatable"))]
pub relocatable: bool,

/// Don't make the virtual environment relocatable.
///
/// Disables the default relocatable behavior when the `relocatable-envs-default` preview
/// feature is enabled.
#[arg(long, overrides_with("relocatable"), hide = true)]
pub no_relocatable: bool,

#[command(flatten)]
pub index_args: IndexArgs,

Expand Down
7 changes: 7 additions & 0 deletions crates/uv-preview/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub enum PreviewFeature {
GcsEndpoint = 1 << 21,
AdjustUlimit = 1 << 22,
SpecialCondaEnvNames = 1 << 23,
RelocatableEnvsDefault = 1 << 24,
}

impl PreviewFeature {
Expand Down Expand Up @@ -66,6 +67,7 @@ impl PreviewFeature {
Self::GcsEndpoint => "gcs-endpoint",
Self::AdjustUlimit => "adjust-ulimit",
Self::SpecialCondaEnvNames => "special-conda-env-names",
Self::RelocatableEnvsDefault => "relocatable-envs-default",
}
}
}
Expand Down Expand Up @@ -109,6 +111,7 @@ impl FromStr for PreviewFeature {
"metadata-json" => Self::MetadataJson,
"adjust-ulimit" => Self::AdjustUlimit,
"special-conda-env-names" => Self::SpecialCondaEnvNames,
"relocatable-envs-default" => Self::RelocatableEnvsDefault,
_ => return Err(PreviewFeatureParseError),
})
}
Expand Down Expand Up @@ -336,5 +339,9 @@ mod tests {
PreviewFeature::SpecialCondaEnvNames.as_str(),
"special-conda-env-names"
);
assert_eq!(
PreviewFeature::RelocatableEnvsDefault.as_str(),
"relocatable-envs-default"
);
}
}
6 changes: 5 additions & 1 deletion crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,11 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.no_project,
&cache,
printer,
args.relocatable,
args.relocatable
|| (globals
.preview
.is_enabled(PreviewFeature::RelocatableEnvsDefault)
&& !args.no_relocatable),
globals.preview,
)
.await
Expand Down
3 changes: 3 additions & 0 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3347,6 +3347,7 @@ pub(crate) struct VenvSettings {
pub(crate) prompt: Option<String>,
pub(crate) system_site_packages: bool,
pub(crate) relocatable: bool,
pub(crate) no_relocatable: bool,
pub(crate) no_project: bool,
pub(crate) refresh: Refresh,
pub(crate) settings: PipSettings,
Expand All @@ -3371,6 +3372,7 @@ impl VenvSettings {
prompt,
system_site_packages,
relocatable,
no_relocatable,
index_args,
index_strategy,
keyring_provider,
Expand All @@ -3396,6 +3398,7 @@ impl VenvSettings {
system_site_packages,
no_project,
relocatable,
no_relocatable,
refresh: Refresh::from(refresh),
settings: PipSettings::combine(
PipOptions {
Expand Down
2 changes: 2 additions & 0 deletions crates/uv/tests/it/show_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7931,6 +7931,7 @@ fn preview_features() {
GcsEndpoint,
AdjustUlimit,
SpecialCondaEnvNames,
RelocatableEnvsDefault,
],
},
python_preference: Managed,
Expand Down Expand Up @@ -8190,6 +8191,7 @@ fn preview_features() {
GcsEndpoint,
AdjustUlimit,
SpecialCondaEnvNames,
RelocatableEnvsDefault,
],
},
python_preference: Managed,
Expand Down
49 changes: 49 additions & 0 deletions crates/uv/tests/it/venv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,55 @@ fn verify_pyvenv_cfg_relocatable() {
));
}

/// With `relocatable-envs-default` preview feature, venvs are relocatable by default.
#[test]
fn relocatable_envs_default_preview() {
let context = TestContext::new("3.12");

// Create a virtual environment with the preview feature enabled.
context
.venv()
.arg(context.venv.as_os_str())
.arg("--clear")
.arg("--python")
.arg("3.12")
.arg("--preview-features")
.arg("relocatable-envs-default")
.assert()
.success();

let pyvenv_cfg = context.venv.child("pyvenv.cfg");
pyvenv_cfg.assert(predicates::path::is_file());

// Relocatable flag is set by default under preview.
pyvenv_cfg.assert(predicates::str::contains("relocatable = true"));
}

/// With `relocatable-envs-default` preview feature, `--no-relocatable` opts out.
#[test]
fn relocatable_envs_default_no_relocatable() {
let context = TestContext::new("3.12");

// Create a virtual environment with the preview feature but opt out.
context
.venv()
.arg(context.venv.as_os_str())
.arg("--clear")
.arg("--python")
.arg("3.12")
.arg("--preview-features")
.arg("relocatable-envs-default")
.arg("--no-relocatable")
.assert()
.success();

let pyvenv_cfg = context.venv.child("pyvenv.cfg");
pyvenv_cfg.assert(predicates::path::is_file());

// Relocatable flag is NOT set because of --no-relocatable.
pyvenv_cfg.assert(predicates::str::contains("relocatable").not());
}

/// Ensure that a nested virtual environment uses the same `home` directory as the parent.
#[test]
fn verify_nested_pyvenv_cfg() -> Result<()> {
Expand Down
Loading