fix(env): treat empty VIRTUAL_ENV/CONDA_PREFIX as unset#10784
Merged
radoering merged 5 commits intopython-poetry:mainfrom Mar 28, 2026
Merged
fix(env): treat empty VIRTUAL_ENV/CONDA_PREFIX as unset#10784radoering merged 5 commits intopython-poetry:mainfrom
radoering merged 5 commits intopython-poetry:mainfrom
Conversation
Reviewer's GuideThis PR makes environment detection more robust by treating empty VIRTUAL_ENV and CONDA_PREFIX values as unset, updating env-prefix checks to use truthiness semantics, and adding tests to verify that Poetry falls back to the in-project .venv in these scenarios. Class diagram for updated environment and Python managersclassDiagram
class EnvManager {
+activate(python: str) Env
+get(reload: bool) Env
-create: bool
-env_prefix: str
-consecutive_calls: int
}
class PythonManager {
+find_all() Iterator~Python~
}
class VirtualEnv {
+VirtualEnv(path: Path)
}
class Python {
+executable: Path
}
EnvManager --> VirtualEnv : creates
PythonManager --> Python : returns
%% Highlighted behaviors related to this PR
class EnvManager {
-_detect_in_venv(env_prefix: str | None, conda_env_name: str | None) bool
}
class PythonManager {
-_current_venv_path: Path | None
}
Flow diagram for updated env detection in EnvManager.getflowchart TD
A["Start get(reload)"] --> B["Read env_prefix from environment"]
B --> C["Read conda_env_name from CONDA_DEFAULT_ENV"]
C --> D{"bool(env_prefix) and conda_env_name != base"}
D -- "False" --> E["Treat as not in_venv"]
E --> F{"Existing env instance and not reload"}
F -- "True" --> G["Return existing env"]
F -- "False" --> H{"Project .venv exists"}
H -- "True" --> I["Return VirtualEnv for project .venv"]
H -- "False" --> J["Create new project .venv"] --> I
D -- "True" --> K{"env_prefix is truthy"}
K -- "True" --> L["prefix = Path(env_prefix)"]
K -- "False" --> M["prefix = in-project .venv path"]
L --> N["Return VirtualEnv for prefix"]
M --> N
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Documentation Updates 1 document(s) were updated by changes in this PR: CHANGELOGView Changes@@ -1,4 +1,11 @@
# Change Log
+
+## [Unreleased]
+
+### Fixed
+
+- Fixed handling of empty `VIRTUAL_ENV` and `CONDA_PREFIX` environment variables. Poetry now treats empty environment variables the same as unset variables. This fixes issues where `conda deactivate` could leave `CONDA_PREFIX` set to an empty string, causing `poetry env use` and other commands to fail. ([#10784](https://github.com/python-poetry/poetry/pull/10784))
+
## [2.3.2] - 2026-02-01
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
test_get_ignores_empty_env_prefix, consider using pytest’smonkeypatch.setenv/delenv(or a dedicated helper) instead of mutatingos.environdirectly with manualtry/finally, which will make the env setup/teardown more concise and less error-prone.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `test_get_ignores_empty_env_prefix`, consider using pytest’s `monkeypatch.setenv/delenv` (or a dedicated helper) instead of mutating `os.environ` directly with manual `try/finally`, which will make the env setup/teardown more concise and less error-prone.
## Individual Comments
### Comment 1
<location path="tests/utils/env/test_env_manager.py" line_range="584-591" />
<code_context>
+ "env_var",
+ ["VIRTUAL_ENV", "CONDA_PREFIX"],
+)
+def test_get_ignores_empty_env_prefix(
+ manager: EnvManager,
+ poetry: Poetry,
+ in_project_venv_dir: Path,
+ env_var: str,
+ mocker: MockerFixture,
+) -> None:
+ """An empty VIRTUAL_ENV or CONDA_PREFIX should be treated as unset.
+
+ After ``conda deactivate``, conda can leave CONDA_PREFIX set to an
</code_context>
<issue_to_address>
**suggestion (testing):** Missing tests for empty VIRTUAL_ENV behavior in env_manager.activate and python.manager.find_all
This test covers `EnvManager.get()` for empty `VIRTUAL_ENV`/`CONDA_PREFIX`, but the other updated code paths still lack coverage:
1. `EnvManager.activate` now uses `bool(os.environ.get("VIRTUAL_ENV"))` and should be tested with `VIRTUAL_ENV=""` to confirm it behaves as if no venv is active.
2. `python.manager.PythonManager.find_all` (or equivalent) should be tested with `VIRTUAL_ENV=""` to ensure it does not treat the empty string as a valid venv path.
Adding these tests would round out coverage for all call sites affected by the bugfix.
Suggested implementation:
```python
@pytest.mark.parametrize(
"env_var",
["VIRTUAL_ENV", "CONDA_PREFIX"],
)
def test_get_ignores_empty_env_prefix(
manager: EnvManager,
poetry: Poetry,
in_project_venv_dir: Path,
env_var: str,
mocker: MockerFixture,
) -> None:
"""An empty VIRTUAL_ENV or CONDA_PREFIX should be treated as unset.
After ``conda deactivate``, conda can leave CONDA_PREFIX set to an
empty string. Poetry should not consider that as an active
virtualenv and should fall back to the in-project .venv instead.
See: https://github.com/python-poetry/poetry/issues/10770
"""
os.environ.pop("VIRTUAL_ENV", None)
os.environ.pop("CONDA_PREFIX", None)
os.environ[env_var] = ""
virtualenv_init = mocker.patch(
"poetry.utils.env.virtual_env.VirtualEnv.__init__",
return_value=None,
)
env = manager.get(poetry)
# EnvManager.get() should ignore the empty env var and use the in-project venv.
assert env.path == in_project_venv_dir
virtualenv_init.assert_called_once_with(in_project_venv_dir, in_project_venv_dir)
# EnvManager.activate() should also treat an empty VIRTUAL_ENV as "no active venv".
# When VIRTUAL_ENV is empty, this should behave the same as when it is unset.
activate_env = manager.activate(poetry)
assert activate_env.path == in_project_venv_dir
# The activation path should also rely on the in-project venv, not the empty env var.
# We re-use the same VirtualEnv.__init__ patch to ensure no extra call with an empty
# path sneaks through in the activate code path.
assert virtualenv_init.call_count >= 1
def test_python_manager_find_all_ignores_empty_virtual_env(
poetry: Poetry,
in_project_venv_dir: Path,
mocker: MockerFixture,
) -> None:
"""PythonManager.find_all should ignore an empty VIRTUAL_ENV.
This mirrors the EnvManager behavior: VIRTUAL_ENV="" must not be treated
as a valid virtual environment path.
"""
from poetry.utils.env import EnvManager
from poetry.utils.env.python_manager import PythonManager
os.environ.pop("VIRTUAL_ENV", None)
os.environ["VIRTUAL_ENV"] = ""
manager = EnvManager(poetry)
python_manager = PythonManager(poetry)
# Patch whatever path discovery the PythonManager uses so we can assert it
# does not attempt to inspect the empty VIRTUAL_ENV path.
list_venvs = mocker.patch.object(
python_manager,
"list",
return_value=[in_project_venv_dir],
)
envs = python_manager.find_all(manager)
# The empty VIRTUAL_ENV should not be treated as a candidate environment.
assert in_project_venv_dir in envs
list_venvs.assert_called_once_with()
```
The SEARCH block is based on the visible portion of `test_get_ignores_empty_env_prefix`; you may need to adjust it to match the exact function body in your local copy.
The new `test_python_manager_find_all_ignores_empty_virtual_env` assumes:
1. `PythonManager` lives in `poetry.utils.env.python_manager`.
2. `PythonManager` has a `list()` method that returns discovered virtualenv paths.
3. `PythonManager.find_all(manager)` is the public API you want to exercise.
If the actual API differs (e.g., different module path or method names), you should:
- Update the imports accordingly.
- Patch the appropriate method used internally by `find_all` to look up venv locations.
- Adjust the assertions on the patched method to match how your real implementation works.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
After `conda deactivate`, conda can leave `CONDA_PREFIX` set to an empty string. Poetry was treating this as an active virtualenv because it only checked `is not None` rather than truthiness. This caused `poetry env use` and other commands to fail with an empty prefix path. Change all env-prefix checks to use truthiness (`bool(...)` / `if env_prefix:`) so that an empty string is treated the same as an unset variable. Fixes python-poetry#10770
8a3a78b to
3bd985f
Compare
radoering
approved these changes
Mar 28, 2026
radoering
added a commit
that referenced
this pull request
Mar 28, 2026
Co-authored-by: Randy Döring <30527984+radoering@users.noreply.github.com> (cherry picked from commit 0206165)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
conda deactivate, conda can leaveCONDA_PREFIXset to an empty string. Poetry previously only checkedis not None, treating the empty string as an active virtualenv, causingpoetry env useand other commands to fail.bool(...)/if env_prefix:) so an empty string is treated the same as an unset variable.VIRTUAL_ENVchecks inenv_manager.py(line 162) andpython/manager.pyfor consistency and defensive correctness.VIRTUAL_ENVandCONDA_PREFIXempty-string scenarios.Fixes #10770
Test plan
test_get_ignores_empty_env_prefixparametrized overVIRTUAL_ENVandCONDA_PREFIXmanager.get()falls back to the in-project.venvwhen the env variable is set to an empty stringSummary by Sourcery
Handle empty virtual environment prefix variables as unset across environment detection and Python discovery.
Bug Fixes:
Enhancements:
Tests: