Repository: wntrblm/nox (language: python)

Issue:
Error when running a uv backend session with active conda environment
### Current Behavior

If you have a conda environment active and try to run a session with using uv as a backend and `session.install`, uv throws an error because it detects both an active conda environment and an active virtual environment:

```
nox > Command uv pip install ruff failed with exit code 2:
error: Both VIRTUAL_ENV and CONDA_PREFIX are set. Please unset one of them.
```

### Expected Behavior

nox should clear both `VIRTUAL_ENV` and `CONDA_PREFIX` environment variables before trying to run a session. 

(I am mixing conda environments and virtual environments for a project because my project needs graphviz, which is nice to install with conda. My dev environment is using conda. However, I don't need it for all environments like linting, so it would be nice to be able to use uv for fast sessions.)

### Steps To Reproduce

```python
# noxfile.py
import nox


@nox.session(venv_backend="uv")
def lint(session):
    session.install("ruff")
```

```bash
# No conda environment active, no problem
❯ nox -s lint
nox > Running session lint
nox > Creating virtual environment (uv) using python in .nox/lint
nox > uv pip install ruff
nox > Session lint was successful.

# Activate a conda environment, try to run
❯ mamba create -n my-conda-env -y
...redacted for brevity...
❯ mamba activate my-conda-env
❯ nox -s lint
nox > Running session lint
nox > Creating virtual environment (uv) using python in .nox/lint
nox > uv pip install ruff
nox > Command uv pip install ruff failed with exit code 2:
error: Both VIRTUAL_ENV and CONDA_PREFIX are set. Please unset one of them.
nox > Session lint failed.
```

### Environment

```Markdown
- OS: macOS
- Python: 3.12.1
- Nox: 2024.3.2
```


### Anything else?

_No response_


Discussion / hints:
It looks like manually unsetting the `CONDA_PREFIX` environment variable is a workaround, e.g., 

```python
@nox.session(venv_backend="uv")
def lint(session):
    session.env.pop("CONDA_PREFIX")
    session.install("ruff")
```
I just saw https://github.com/astral-sh/uv/pull/2574 was released with [uv v0.1.23](https://github.com/astral-sh/uv/releases/tag/0.1.23). 

This fixes the specific problem I was having. However, I think the opposite case would still be an issue (active venv, nox session uses conda env and user tries to use uv) and would install things into the wrong environment. 

Fix patch:
diff --git a/nox/virtualenv.py b/nox/virtualenv.py
index 64560b87..b5610540 100644
--- a/nox/virtualenv.py
+++ b/nox/virtualenv.py
@@ -75,14 +75,18 @@ class ProcessEnv(abc.ABC):
     allowed_globals: ClassVar[tuple[Any, ...]] = ()
 
     def __init__(
-        self, bin_paths: None = None, env: Mapping[str, str] | None = None
+        self, bin_paths: None = None, env: Mapping[str, str | None] | None = None
     ) -> None:
         self._bin_paths = bin_paths
         self.env = os.environ.copy()
         self._reused = False
+        env = env or {}
 
-        if env is not None:
-            self.env.update(env)
+        for k, v in env.items():
+            if v is None:
+                self.env.pop(k, None)
+            else:
+                self.env[k] = v
 
         for key in _BLACKLISTED_ENV_VARS:
             self.env.pop(key, None)
@@ -249,7 +253,7 @@ def __init__(
         self.reuse_existing = reuse_existing
         self.venv_params = venv_params or []
         self.conda_cmd = conda_cmd
-        super().__init__(env={"CONDA_PREFIX": self.location})
+        super().__init__(env={"CONDA_PREFIX": self.location, "VIRTUAL_ENV": None})
 
     def _clean_location(self) -> bool:
         """Deletes existing conda environment"""
@@ -379,7 +383,7 @@ def __init__(
         if venv_backend not in {"virtualenv", "venv", "uv"}:
             msg = f"venv_backend {venv_backend} not recognized"
             raise ValueError(msg)
-        super().__init__(env={"VIRTUAL_ENV": self.location})
+        super().__init__(env={"VIRTUAL_ENV": self.location, "CONDA_PREFIX": None})
 
     def _clean_location(self) -> bool:
         """Deletes any existing virtual environment"""


Test patch:
diff --git a/tests/test_virtualenv.py b/tests/test_virtualenv.py
index 12d41c5c..340c2f98 100644
--- a/tests/test_virtualenv.py
+++ b/tests/test_virtualenv.py
@@ -364,9 +364,15 @@ def test_bin_windows(make_one):
 
 
 def test_create(monkeypatch, make_one):
+    monkeypatch.setenv("CONDA_PREFIX", "no-prefix-allowed")
+    monkeypatch.setenv("NOT_CONDA_PREFIX", "something-else")
+
     venv, dir_ = make_one()
     venv.create()
 
+    assert "CONDA_PREFIX" not in venv.env
+    assert "NOT_CONDA_PREFIX" in venv.env
+
     if IS_WINDOWS:
         assert dir_.join("Scripts", "python.exe").check()
         assert dir_.join("Scripts", "pip.exe").check()