From 0007b0e8fb0785da11c32e97cf17af18106b3448 Mon Sep 17 00:00:00 2001 From: Arun Babu Neelicattu Date: Tue, 5 Mar 2024 22:31:08 +0100 Subject: [PATCH] cli/env: handle removal of in-project venv Resolves: #2124 --- docs/managing-environments.md | 9 +++++++++ src/poetry/console/commands/env/remove.py | 18 ++++++++++++------ tests/console/commands/env/conftest.py | 3 ++- tests/console/commands/env/test_remove.py | 11 +++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/docs/managing-environments.md b/docs/managing-environments.md index a663c806397..be89afc7c80 100644 --- a/docs/managing-environments.md +++ b/docs/managing-environments.md @@ -160,3 +160,12 @@ poetry env remove --all ``` If you remove the currently activated virtual environment, it will be automatically deactivated. + +{{% note %}} +If you use the [`virtualenvs.in-project`]({{< relref "configuration#virtualenvsin-project" >}}) configuration, you +can simply use the command as shown below. + +```bash +poetry env remove +``` +{{% /note %}} diff --git a/src/poetry/console/commands/env/remove.py b/src/poetry/console/commands/env/remove.py index 4371ec4f84b..a492959ebbe 100644 --- a/src/poetry/console/commands/env/remove.py +++ b/src/poetry/console/commands/env/remove.py @@ -39,9 +39,12 @@ class EnvRemoveCommand(Command): def handle(self) -> int: from poetry.utils.env import EnvManager + is_in_project = self.poetry.config.get("virtualenvs.in-project") + pythons = self.argument("python") - all = self.option("all") - if not (pythons or all): + remove_all_envs = self.option("all") + + if not (pythons or remove_all_envs or is_in_project): self.line("No virtualenv provided.") manager = EnvManager(self.poetry) @@ -49,14 +52,17 @@ def handle(self) -> int: for python in pythons: venv = manager.remove(python) self.line(f"Deleted virtualenv: {venv.path}") - if all: + if remove_all_envs or is_in_project: for venv in manager.list(): - manager.remove_venv(venv.path) - self.line(f"Deleted virtualenv: {venv.path}") + if not is_in_project or venv.path.is_relative_to( + self.poetry.pyproject_path.parent + ): + manager.remove_venv(venv.path) + self.line(f"Deleted virtualenv: {venv.path}") # Since we remove all the virtualenvs, we can also remove the entry # in the envs file. (Strictly speaking, we should do this explicitly, # in case it points to a virtualenv that had been removed manually before.) - if manager.envs_file.exists(): + if remove_all_envs and manager.envs_file.exists(): manager.envs_file.remove_section(manager.base_env_name) return 0 diff --git a/tests/console/commands/env/conftest.py b/tests/console/commands/env/conftest.py index f118b5f05f1..7fb3b1502a3 100644 --- a/tests/console/commands/env/conftest.py +++ b/tests/console/commands/env/conftest.py @@ -65,7 +65,8 @@ def venvs_in_project_dir(app: PoetryTestApplication) -> Iterator[Path]: try: yield venv_dir finally: - venv_dir.rmdir() + if venv_dir.exists(): + venv_dir.rmdir() @pytest.fixture diff --git a/tests/console/commands/env/test_remove.py b/tests/console/commands/env/test_remove.py index 38998f92634..510f4efa735 100644 --- a/tests/console/commands/env/test_remove.py +++ b/tests/console/commands/env/test_remove.py @@ -137,3 +137,14 @@ def test_remove_multiple( for name in remaining_envs: assert (venv_cache / name).exists() assert set(tester.io.fetch_output().split("\n")) == expected + + +def test_remove_in_project(tester: CommandTester, venvs_in_project_dir: Path) -> None: + assert venvs_in_project_dir.exists() + + tester.execute() + + assert not venvs_in_project_dir.exists() + + expected = f"Deleted virtualenv: {venvs_in_project_dir}\n" + assert tester.io.fetch_output() == expected