From 0c674619b22bfc86a5a4b361714708bed746c359 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 26 Aug 2025 12:43:29 -0400 Subject: [PATCH] Avoid erroring when creating `venv` in current working directory (#15537) ## Summary A strange use-case, but the current behavior is definitely a bug. Part of https://github.com/astral-sh/uv/issues/15474. --- crates/uv-virtualenv/src/virtualenv.rs | 22 ++++++++++++++-------- crates/uv/tests/it/venv.rs | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/crates/uv-virtualenv/src/virtualenv.rs b/crates/uv-virtualenv/src/virtualenv.rs index 5b0c3cb34..cf440a212 100644 --- a/crates/uv-virtualenv/src/virtualenv.rs +++ b/crates/uv-virtualenv/src/virtualenv.rs @@ -77,6 +77,18 @@ pub(crate) fn create( base_python.display() ); + // Extract the prompt and compute the absolute path prior to validating the location; otherwise, + // we risk deleting (and recreating) the current working directory, which would cause the `CWD` + // queries to fail. + let prompt = match prompt { + Prompt::CurrentDirectoryName => CWD + .file_name() + .map(|name| name.to_string_lossy().to_string()), + Prompt::Static(value) => Some(value), + Prompt::None => None, + }; + let absolute = std::path::absolute(location)?; + // Validate the existing location. match location.metadata() { Ok(metadata) if metadata.is_file() => { @@ -172,7 +184,8 @@ pub(crate) fn create( Err(err) => return Err(Error::Io(err)), } - let location = std::path::absolute(location)?; + // Use the absolute path for all further operations. + let location = absolute; let bin_name = if cfg!(unix) { "bin" @@ -182,13 +195,6 @@ pub(crate) fn create( unimplemented!("Only Windows and Unix are supported") }; let scripts = location.join(&interpreter.virtualenv().scripts); - let prompt = match prompt { - Prompt::CurrentDirectoryName => CWD - .file_name() - .map(|name| name.to_string_lossy().to_string()), - Prompt::Static(value) => Some(value), - Prompt::None => None, - }; // Add the CACHEDIR.TAG. cachedir::ensure_tag(&location)?; diff --git a/crates/uv/tests/it/venv.rs b/crates/uv/tests/it/venv.rs index b97299625..d7db5554e 100644 --- a/crates/uv/tests/it/venv.rs +++ b/crates/uv/tests/it/venv.rs @@ -1572,3 +1572,26 @@ fn create_venv_nested_symlink_preservation() -> Result<()> { Ok(()) } + +#[test] +fn create_venv_current_working_directory() { + let context = TestContext::new_with_versions(&["3.12"]); + + uv_snapshot!(context.filters(), context.venv() + .arg(".") + .arg("--python") + .arg("3.12"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Using CPython 3.12.[X] interpreter at: [PYTHON-3.12] + Creating virtual environment at: . + warning: A directory already exists at `.`. In the future, uv will require `--clear` to replace it + Activate with: source bin/activate + " + ); + + context.root.assert(predicates::path::is_dir()); +}