From 30fc0920821acee93f25f6b935e48ebcf838e116 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Wed, 12 Apr 2023 20:03:03 +0100 Subject: [PATCH 1/4] Use existing .venv even without explicit in-project --- src/poetry/utils/env.py | 24 ++++++++++----------- tests/utils/test_env.py | 48 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index 721660b9db3..38d86ba9973 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -621,7 +621,7 @@ def activate(self, python: str) -> Env: patch = python_version.text create = False - is_root_venv = self._poetry.config.get("virtualenvs.in-project") + is_root_venv = self.use_root_env() # If we are required to create the virtual environment in the root folder, # create or recreate it if needed if is_root_venv: @@ -730,11 +730,7 @@ def get(self, reload: bool = False) -> Env: if not in_venv or env is not None: # Checking if a local virtualenv exists - if ( - self._poetry.config.get("virtualenvs.in-project") is not False - and (cwd / ".venv").exists() - and (cwd / ".venv").is_dir() - ): + if self.use_root_env(): venv = cwd / ".venv" return VirtualEnv(venv) @@ -773,11 +769,7 @@ def list(self, name: str | None = None) -> list[VirtualEnv]: env_list = [VirtualEnv(p) for p in sorted(venv_path.glob(f"{venv_name}-py*"))] venv = self._poetry.file.parent / ".venv" - if ( - self._poetry.config.get("virtualenvs.in-project") is not False - and venv.exists() - and venv.is_dir() - ): + if self.use_root_env(): env_list.insert(0, VirtualEnv(venv)) return env_list @@ -891,6 +883,14 @@ def remove(self, python: str) -> Env: return VirtualEnv(venv_path, venv_path) + def use_root_env(self) -> bool: + in_project: bool | None = self._poetry.config.get("virtualenvs.in-project") + if in_project is not None: + return in_project + + root_venv: Path = self._poetry.file.parent / ".venv" + return root_venv.exists() and root_venv.is_dir() + def create_venv( self, name: str | None = None, @@ -918,7 +918,7 @@ def create_venv( return env create_venv = self._poetry.config.get("virtualenvs.create") - root_venv = self._poetry.config.get("virtualenvs.in-project") + root_venv = self.use_root_env() prefer_active_python = self._poetry.config.get( "virtualenvs.prefer-active-python" ) diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index 4e1acb4b98c..5691895d39b 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -208,6 +208,52 @@ def check_output(cmd: list[str], *args: Any, **kwargs: Any) -> str: return check_output +def test_activate_in_project_venv_no_explicit_config( + tmp_path: Path, + manager: EnvManager, + poetry: Poetry, + mocker: MockerFixture, + venv_name: str, + in_project_venv_dir: Path, +) -> None: + mocker.patch("shutil.which", side_effect=lambda py: f"/usr/bin/{py}") + mocker.patch( + "subprocess.check_output", + side_effect=check_output_wrapper(), + ) + mocker.patch( + "subprocess.Popen.communicate", + side_effect=[ + ("/prefix", None), + ('{"version_info": [3, 7, 0]}', None), + ("/prefix", None), + ("/prefix", None), + ("/prefix", None), + ], + ) + m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv) + + env = manager.activate("python3.7") + + assert env.path == tmp_path / "poetry-fixture-simple" / ".venv" + assert env.base == Path("/prefix") + + m.assert_called_with( + tmp_path / "poetry-fixture-simple" / ".venv", + executable=Path("/usr/bin/python3.7"), + flags={ + "always-copy": False, + "system-site-packages": False, + "no-pip": False, + "no-setuptools": False, + }, + prompt="simple-project-py3.7", + ) + + envs_file = TOMLFile(tmp_path / "envs.toml") + assert not envs_file.exists() + + def test_activate_activates_non_existing_virtualenv_no_envs_file( tmp_path: Path, manager: EnvManager, @@ -1382,7 +1428,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir( ) mocker.patch( "subprocess.Popen.communicate", - side_effect=[("/prefix", None), ("/prefix", None)], + side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)], ) m = mocker.patch("poetry.utils.env.EnvManager.build_venv") From 0184cd0bc2f36e5313e412056be0a7f5eeb5b9d6 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sat, 22 Apr 2023 12:31:42 +0100 Subject: [PATCH 2/4] code review --- src/poetry/utils/env.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index 38d86ba9973..20d2fe4b51c 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -588,6 +588,11 @@ def get_python_version( return Version.parse(version) + @property + def in_project_venv(self) -> Path: + venv: Path = self._poetry.file.parent / ".venv" + return venv + def activate(self, python: str) -> Env: venv_path = self._poetry.config.virtualenvs_path cwd = self._poetry.file.parent @@ -621,12 +626,12 @@ def activate(self, python: str) -> Env: patch = python_version.text create = False - is_root_venv = self.use_root_env() + is_root_venv = self.use_in_project_venv() # If we are required to create the virtual environment in the root folder, # create or recreate it if needed if is_root_venv: create = False - venv = self._poetry.file.parent / ".venv" + venv = self.in_project_venv if venv.exists(): # We need to check if the patch version is correct _venv = VirtualEnv(venv) @@ -730,8 +735,8 @@ def get(self, reload: bool = False) -> Env: if not in_venv or env is not None: # Checking if a local virtualenv exists - if self.use_root_env(): - venv = cwd / ".venv" + if self.use_in_project_venv(): + venv = self.in_project_venv return VirtualEnv(venv) @@ -768,8 +773,8 @@ def list(self, name: str | None = None) -> list[VirtualEnv]: venv_path = self._poetry.config.virtualenvs_path env_list = [VirtualEnv(p) for p in sorted(venv_path.glob(f"{venv_name}-py*"))] - venv = self._poetry.file.parent / ".venv" - if self.use_root_env(): + if self.use_in_project_venv(): + venv = self.in_project_venv env_list.insert(0, VirtualEnv(venv)) return env_list @@ -883,13 +888,13 @@ def remove(self, python: str) -> Env: return VirtualEnv(venv_path, venv_path) - def use_root_env(self) -> bool: + def use_in_project_venv(self) -> bool: in_project: bool | None = self._poetry.config.get("virtualenvs.in-project") if in_project is not None: return in_project root_venv: Path = self._poetry.file.parent / ".venv" - return root_venv.exists() and root_venv.is_dir() + return root_venv.is_dir() def create_venv( self, @@ -918,7 +923,7 @@ def create_venv( return env create_venv = self._poetry.config.get("virtualenvs.create") - root_venv = self.use_root_env() + root_venv = self.use_in_project_venv() prefer_active_python = self._poetry.config.get( "virtualenvs.prefer-active-python" ) @@ -927,12 +932,11 @@ def create_venv( if not executable and prefer_active_python: executable = self._detect_active_python() - venv_path: Path = ( - cwd / ".venv" if root_venv else self._poetry.config.virtualenvs_path + venv_path = ( + self.in_project_venv if root_venv else self._poetry.config.virtualenvs_path ) if not name: name = self._poetry.package.name - assert name is not None python_patch = ".".join([str(v) for v in sys.version_info[:3]]) python_minor = ".".join([str(v) for v in sys.version_info[:2]]) From 220855bb8dcb2ee4446c84842e62febba613ebf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 22 Apr 2023 14:56:22 +0200 Subject: [PATCH 3/4] consistent naming --- src/poetry/utils/env.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index 20d2fe4b51c..fd4bad4a8d9 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -626,10 +626,9 @@ def activate(self, python: str) -> Env: patch = python_version.text create = False - is_root_venv = self.use_in_project_venv() - # If we are required to create the virtual environment in the root folder, + # If we are required to create the virtual environment in the project directory, # create or recreate it if needed - if is_root_venv: + if self.use_in_project_venv(): create = False venv = self.in_project_venv if venv.exists(): @@ -893,8 +892,8 @@ def use_in_project_venv(self) -> bool: if in_project is not None: return in_project - root_venv: Path = self._poetry.file.parent / ".venv" - return root_venv.is_dir() + venv: Path = self._poetry.file.parent / ".venv" + return venv.is_dir() def create_venv( self, @@ -923,7 +922,7 @@ def create_venv( return env create_venv = self._poetry.config.get("virtualenvs.create") - root_venv = self.use_in_project_venv() + in_project_venv = self.use_in_project_venv() prefer_active_python = self._poetry.config.get( "virtualenvs.prefer-active-python" ) @@ -933,7 +932,9 @@ def create_venv( executable = self._detect_active_python() venv_path = ( - self.in_project_venv if root_venv else self._poetry.config.virtualenvs_path + self.in_project_venv + if in_project_venv + else self._poetry.config.virtualenvs_path ) if not name: name = self._poetry.package.name @@ -1011,7 +1012,7 @@ def create_venv( self._poetry.package.python_versions ) - if root_venv: + if in_project_venv: venv = venv_path else: name = self.generate_env_name(name, str(cwd)) From b2a2176685a941c89b0f3a40f271f0da8a1100bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 22 Apr 2023 15:01:21 +0200 Subject: [PATCH 4/4] one more --- src/poetry/utils/env.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index fd4bad4a8d9..57ff0bbf47b 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -891,9 +891,7 @@ def use_in_project_venv(self) -> bool: in_project: bool | None = self._poetry.config.get("virtualenvs.in-project") if in_project is not None: return in_project - - venv: Path = self._poetry.file.parent / ".venv" - return venv.is_dir() + return self.in_project_venv.is_dir() def create_venv( self,