Allow syncing to empty virtual environment directories (#9427)
Some checks are pending
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / check system | python on macos x86_64 (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | python3.10 on windows (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on linux (push) Blocked by required conditions
CI / check system | conda3.8 on linux (push) Blocked by required conditions
CI / check system | conda3.11 on macos (push) Blocked by required conditions
CI / check system | conda3.8 on macos (push) Blocked by required conditions
CI / check system | conda3.11 on windows (push) Blocked by required conditions
CI / check system | conda3.8 on windows (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions

As discussed in https://github.com/astral-sh/uv/issues/9423, it's
confusing that we do not allow `uv sync` just because the `.venv`
directory _exists_. This change matches `uv venv`.
This commit is contained in:
Zanie Blue 2024-11-25 16:23:49 -06:00 committed by GitHub
parent 5759cb9891
commit 21aa9bc53a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 28 additions and 7 deletions

View file

@ -43,6 +43,7 @@ pub struct InvalidEnvironment {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum InvalidEnvironmentKind { pub enum InvalidEnvironmentKind {
NotDirectory, NotDirectory,
Empty,
MissingExecutable(PathBuf), MissingExecutable(PathBuf),
} }
@ -128,6 +129,7 @@ impl std::fmt::Display for InvalidEnvironmentKind {
Self::MissingExecutable(path) => { Self::MissingExecutable(path) => {
write!(f, "missing Python executable at `{}`", path.user_display()) write!(f, "missing Python executable at `{}`", path.user_display())
} }
Self::Empty => write!(f, "directory is empty"),
} }
} }
} }
@ -178,6 +180,14 @@ impl PythonEnvironment {
.into()); .into());
} }
if venv.read_dir().is_ok_and(|mut dir| dir.next().is_none()) {
return Err(InvalidEnvironment {
path: venv,
kind: InvalidEnvironmentKind::Empty,
}
.into());
}
let executable = virtualenv_python_executable(&venv); let executable = virtualenv_python_executable(&venv);
// Check if the executable exists before querying so we can provide a more specific error // Check if the executable exists before querying so we can provide a more specific error

View file

@ -689,6 +689,8 @@ impl ProjectInterpreter {
)); ));
} }
} }
// If the environment is an empty directory, it's fine to use
InvalidEnvironmentKind::Empty => {}
}; };
} }
Err(uv_python::Error::Query(uv_python::InterpreterError::NotFound(path))) => { Err(uv_python::Error::Query(uv_python::InterpreterError::NotFound(path))) => {
@ -807,10 +809,15 @@ pub(crate) async fn get_or_init_environment(
(Ok(false), Ok(false)) => false, (Ok(false), Ok(false)) => false,
// If it's not a virtual environment, bail // If it's not a virtual environment, bail
(Ok(true), Ok(false)) => { (Ok(true), Ok(false)) => {
return Err(ProjectError::InvalidProjectEnvironmentDir( // Unless it's empty, in which case we just ignore it
venv, if venv.read_dir().is_ok_and(|mut dir| dir.next().is_none()) {
"it is not a compatible environment but cannot be recreated because it is not a virtual environment".to_string(), false
)); } else {
return Err(ProjectError::InvalidProjectEnvironmentDir(
venv,
"it is not a compatible environment but cannot be recreated because it is not a virtual environment".to_string(),
));
}
} }
// Similarly, if we can't _tell_ if it exists we should bail // Similarly, if we can't _tell_ if it exists we should bail
(_, Err(err)) | (Err(err), _) => { (_, Err(err)) | (Err(err), _) => {

View file

@ -2795,13 +2795,17 @@ fn sync_empty_virtual_environment() -> Result<()> {
// Running `uv sync` should work // Running `uv sync` should work
uv_snapshot!(context.filters(), context.sync(), @r###" uv_snapshot!(context.filters(), context.sync(), @r###"
success: false success: true
exit_code: 2 exit_code: 0
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12] Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
error: Project virtual environment directory `[VENV]/` cannot be used because it is not a compatible environment but cannot be recreated because it is not a virtual environment Creating virtual environment at: .venv
Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ iniconfig==2.0.0
"###); "###);
Ok(()) Ok(())