diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index 721660b9db3..57ff0bbf47b 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,11 @@ def activate(self, python: str) -> Env: patch = python_version.text create = False - is_root_venv = self._poetry.config.get("virtualenvs.in-project") - # 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._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,12 +734,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._poetry.config.get("virtualenvs.in-project") is not False - and (cwd / ".venv").exists() - and (cwd / ".venv").is_dir() - ): - venv = cwd / ".venv" + if self.use_in_project_venv(): + venv = self.in_project_venv return VirtualEnv(venv) @@ -772,12 +772,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._poetry.config.get("virtualenvs.in-project") is not False - and venv.exists() - and venv.is_dir() - ): + if self.use_in_project_venv(): + venv = self.in_project_venv env_list.insert(0, VirtualEnv(venv)) return env_list @@ -891,6 +887,12 @@ def remove(self, python: str) -> Env: return VirtualEnv(venv_path, venv_path) + 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 + return self.in_project_venv.is_dir() + def create_venv( self, name: str | None = None, @@ -918,7 +920,7 @@ def create_venv( return env create_venv = self._poetry.config.get("virtualenvs.create") - root_venv = self._poetry.config.get("virtualenvs.in-project") + in_project_venv = self.use_in_project_venv() prefer_active_python = self._poetry.config.get( "virtualenvs.prefer-active-python" ) @@ -927,12 +929,13 @@ 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 in_project_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]]) @@ -1007,7 +1010,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)) 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")