Repository: astral-sh/uv
File: crates/uv/tests/it/sync.rs (Rust)

Code before:
    error: failed to remove directory `[VENV]/z2.txt`: Permission denied (os error 13)
    ");

    uv_snapshot!(context.filters(), context.sync().arg("-p").arg("3.12").env_remove(EnvVars::VIRTUAL_ENV), @r"
    success: false
    exit_code: 2
    ----- stdout -----

    ----- stderr -----
    Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
    error: failed to remove directory `[VENV]/z2.txt`: Permission denied (os error 13)
    ");

    // Remove the unreadable directory
    fs_err::remove_dir(unreadable2)?;

    // Check that we're still failing if the venv doesn't look like one anymore.
    context.venv().arg("--clear").assert().success();
    fs_err::remove_file(context.temp_dir.join(".venv/pyvenv.cfg"))?;
    uv_snapshot!(context.filters(), context.sync().arg("-p").arg("3.12").env_remove(EnvVars::VIRTUAL_ENV), @r"
    success: true
    exit_code: 0
    ----- stdout -----

    ----- stderr -----
    Resolved 1 package in [TIME]
    Audited in [TIME]
    ");

    Ok(())
}

#[test]
fn sync_active_project_environment() -> Result<()> {
    let context = TestContext::new_with_versions(&["3.11", "3.12"])
        .with_filtered_virtualenv_bin()
        .with_filtered_python_names();

    let pyproject_toml = context.temp_dir.child("pyproject.toml");
    pyproject_toml.write_str(
        r#"
        [project]
        name = "project"
        version = "0.1.0"
        requires-python = ">=3.11"
        dependencies = ["iniconfig"]
        "#,
    )?;

    // Running `uv sync` with `VIRTUAL_ENV` should warn
    uv_snapshot!(context.filters(), context.sync().env(EnvVars::VIRTUAL_ENV, "foo"), @r"

Review comment (suggestion):
We're too smart for the simple check, we need to delete Python too:

```suggestion
    context.venv().arg("--clear").assert().success();
    fs_err::remove_file(context.temp_dir.join(".venv/pyvenv.cfg"))?;
    fs_err::remove_file(context.temp_dir.join(".venv/bin/python"))?;
    uv_snapshot!(context.filters(), context.sync().arg("-p").arg("3.12").env_remove(EnvVars::VIRTUAL_ENV), @r"
    success: false
    exit_code: 2
    ----- stdout -----

    ----- stderr -----
    warning: Ignoring existing virtual environment linked to non-existent Python interpreter: .venv/bin/python3 -> python
    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
    ");
```

Code after:

    context
        .temp_dir
        .child("foo")
        .assert(predicate::path::missing());

    // Using `--active` should create the environment
    uv_snapshot!(context.filters(), context.sync().env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
    success: true
    exit_code: 0
    ----- stdout -----

    ----- stderr -----
    Using CPython 3.11.[X] interpreter at: [PYTHON-3.11]
    Creating virtual environment at: foo
    Resolved 2 packages in [TIME]
    Installed 1 package in [TIME]
     + iniconfig==2.0.0
    ");

    context
        .temp_dir
        .child("foo")
        .assert(predicate::path::is_dir());

    // A subsequent sync will re-use the environment
    uv_snapshot!(context.filters(), context.sync().env(EnvVars::VIRTUAL_ENV, "foo").arg("--active"), @r"
    success: true
    exit_code: 0
    ----- stdout -----

    ----- stderr -----
    Resolved 2 packages in [TIME]
    Audited 1 package in [TIME]
    ");

    // Setting both the `VIRTUAL_ENV` and `UV_PROJECT_ENVIRONMENT` is fine if they agree
    uv_snapshot!(context.filters(), context.sync()
        .arg("--active")
        .env(EnvVars::VIRTUAL_ENV, "foo")
        .env(EnvVars::UV_PROJECT_ENVIRONMENT, "foo"), @r"
    success: true
    exit_code: 0
    ----- stdout -----

    ----- stderr -----
    Resolved 2 packages in [TIME]
    Audited 1 package in [TIME]
    ");

    // If they disagree, we use `VIRTUAL_ENV` because of `--active`