From 66a48130f9235816f1ef48f6b1ad7073f9f3b0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Tue, 24 Aug 2021 13:56:26 +0200 Subject: [PATCH 1/6] Fix the detection of the system environment with custom installer --- install-poetry.py | 4 ++++ poetry/utils/env.py | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/install-poetry.py b/install-poetry.py index 9980ff53cd7..2eb61b53183 100644 --- a/install-poetry.py +++ b/install-poetry.py @@ -528,6 +528,10 @@ def make_env(self, version: str) -> Path: virtualenv.cli_run([str(env_path), "--clear"]) + # We add a special file so that Poetry can detect + # its own virtual environment + env_path.joinpath("poetry_env").touch() + return env_path def make_bin(self, version: str) -> None: diff --git a/poetry/utils/env.py b/poetry/utils/env.py index fb4c2021747..ffa182f9a5c 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -1011,8 +1011,13 @@ def get_system_env(cls, naive: bool = False) -> Union["SystemEnv", "GenericEnv"] """ prefix, base_prefix = Path(sys.prefix), Path(cls.get_base_prefix()) if not naive: + if prefix.joinpath("poetry_env").exists(): + return GenericEnv(base_prefix) + + from poetry.locations import data_dir + try: - Path(__file__).relative_to(prefix) + prefix.relative_to(data_dir()) except ValueError: pass else: From c5fe5171d14e0086a88fbdfa8d9c11db2d49c99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Fri, 27 Aug 2021 13:46:33 +0200 Subject: [PATCH 2/6] Ensure the correct environment executables are used Co-authored-by: finswimmer <2164565+finswimmer@users.noreply.github.com> --- poetry/console/commands/env/info.py | 16 ++++++++-- poetry/utils/env.py | 40 +++++++++++++++++++++---- tests/console/commands/env/test_info.py | 18 ++++++++--- tests/utils/test_env.py | 37 +++++++++++++++++++++++ 4 files changed, 99 insertions(+), 12 deletions(-) diff --git a/poetry/console/commands/env/info.py b/poetry/console/commands/env/info.py index aecce3628ac..5f7f185419d 100644 --- a/poetry/console/commands/env/info.py +++ b/poetry/console/commands/env/info.py @@ -33,6 +33,8 @@ def handle(self) -> Optional[int]: self._display_complete_info(env) def _display_complete_info(self, env: "Env") -> None: + from poetry.utils.env import GenericEnv + env_python_version = ".".join(str(s) for s in env.version_info[:3]) self.line("") self.line("Virtualenv") @@ -44,6 +46,9 @@ def _display_complete_info(self, env: "Env") -> None: "Path: {}".format( env.path if env.is_venv() else "NA" ), + "Executable: {}".format( + env.python if env.is_venv() else "NA" + ), ] if env.is_venv(): listing.append( @@ -55,13 +60,18 @@ def _display_complete_info(self, env: "Env") -> None: self.line("") + system_env = GenericEnv(env.base) self.line("System") self.line( "\n".join( [ - "Platform: {}".format(env.platform), - "OS: {}".format(env.os), - "Python: {}".format(env.base), + "Platform: {}".format(env.platform), + "OS: {}".format(env.os), + "Python: {}".format( + ".".join(str(v) for v in system_env.version_info[:3]) + ), + "Path: {}".format(system_env.path), + "Executable: {}".format(system_env.python), ] ) ) diff --git a/poetry/utils/env.py b/poetry/utils/env.py index ffa182f9a5c..485a2d20420 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -1061,6 +1061,30 @@ def __init__(self, path: Path, base: Optional[Path] = None) -> None: self._path = path self._bin_dir = self._path / bin_dir + try: + python_executables = sorted( + [ + p.name + for p in self._bin_dir.glob("python*") + if re.match(r"python(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) + ] + ) + self._executable = python_executables[0].rstrip(".exe") + except IndexError: + self._executable = "python" + (".exe" if self._is_windows else "") + + try: + pip_executables = sorted( + [ + p.name + for p in self._bin_dir.glob("pip*") + if re.match(r"pip(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) + ] + ) + self._pip_executable = pip_executables[0].rstrip(".exe") + except IndexError: + self._pip_executable = "pip" + (".exe" if self._is_windows else "") + self._base = base or path self._marker_env = None @@ -1095,7 +1119,7 @@ def python(self) -> str: """ Path to current python executable """ - return self._bin("python") + return self._bin(self._executable) @property def marker_env(self) -> Dict[str, Any]: @@ -1121,7 +1145,7 @@ def pip(self) -> str: Path to current pip executable """ # we do not use as_posix() here due to issues with windows pathlib2 implementation - path = self._bin("pip") + path = self._bin(self._pip_executable) if not Path(path).exists(): return str(self.pip_embedded) return path @@ -1267,7 +1291,7 @@ def run_pip(self, *args: str, **kwargs: Any) -> Union[int, str]: return self._run(cmd, **kwargs) def run_python_script(self, content: str, **kwargs: Any) -> str: - return self.run("python", "-W", "ignore", "-", input_=content, **kwargs) + return self.run(self._executable, "-W", "ignore", "-", input_=content, **kwargs) def _run(self, cmd: List[str], **kwargs: Any) -> Union[int, str]: """ @@ -1489,7 +1513,10 @@ def get_python_implementation(self) -> str: def get_pip_command(self, embedded: bool = False) -> List[str]: # We're in a virtualenv that is known to be sane, # so assume that we have a functional pip - return [self._bin("python"), self.pip_embedded if embedded else self.pip] + return [ + self._bin(self._executable), + self.pip_embedded if embedded else self.pip, + ] def get_supported_tags(self) -> List[Tag]: file_path = Path(packaging.tags.__file__) @@ -1607,7 +1634,10 @@ def __init__( self.executed = [] def get_pip_command(self, embedded: bool = False) -> List[str]: - return [self._bin("python"), self.pip_embedded if embedded else self.pip] + return [ + self._bin(self._executable), + self.pip_embedded if embedded else self.pip, + ] def _run(self, cmd: List[str], **kwargs: Any) -> int: self.executed.append(cmd) diff --git a/tests/console/commands/env/test_info.py b/tests/console/commands/env/test_info.py index 123835ba7b9..7212004b418 100644 --- a/tests/console/commands/env/test_info.py +++ b/tests/console/commands/env/test_info.py @@ -1,7 +1,10 @@ +import sys + from pathlib import Path import pytest +from poetry.utils._compat import WINDOWS from poetry.utils.env import MockEnv @@ -28,14 +31,21 @@ def test_env_info_displays_complete_info(tester): Python: 3.7.0 Implementation: CPython Path: {prefix} +Executable: {executable} Valid: True System -Platform: darwin -OS: posix -Python: {base_prefix} +Platform: darwin +OS: posix +Python: {base_version} +Path: {base_prefix} +Executable: {base_executable} """.format( - prefix=str(Path("/prefix")), base_prefix=str(Path("/base/prefix")) + prefix=str(Path("/prefix")), + base_prefix=str(Path("/base/prefix")), + base_version=".".join(str(v) for v in sys.version_info[:3]), + executable=sys.executable, + base_executable="python" + (".exe" if WINDOWS else ""), ) assert expected == tester.io.fetch_output() diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index d09012c821f..3fa57ec7aba 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -15,6 +15,7 @@ from poetry.core.semver.version import Version from poetry.core.toml.file import TOMLFile from poetry.factory import Factory +from poetry.utils._compat import WINDOWS from poetry.utils.env import GET_BASE_PREFIX from poetry.utils.env import EnvCommandError from poetry.utils.env import EnvManager @@ -964,3 +965,39 @@ def test_env_system_packages(tmp_path, config): assert not venv_path.joinpath( "lib", "python2.7", "no-global-site-packages.txt" ).exists() + + +def test_env_finds_the_correct_executables(tmp_dir, manager): + venv_path = Path(tmp_dir) / "Virtual Env" + manager.build_venv(str(venv_path), with_pip=True) + venv = VirtualEnv(venv_path) + + default_executable = expected_executable = "python" + (".exe" if WINDOWS else "") + default_pip_executable = expected_pip_executable = "pip" + ( + ".exe" if WINDOWS else "" + ) + major_executable = "python{}{}".format( + sys.version_info[0], ".exe" if WINDOWS else "" + ) + major_pip_executable = "pip{}{}".format( + sys.version_info[0], ".exe" if WINDOWS else "" + ) + + if ( + venv._bin_dir.joinpath(default_executable).exists() + and venv._bin_dir.joinpath(major_executable).exists() + ): + venv._bin_dir.joinpath(default_executable).unlink() + expected_executable = major_executable + + if ( + venv._bin_dir.joinpath(default_pip_executable).exists() + and venv._bin_dir.joinpath(major_pip_executable).exists() + ): + venv._bin_dir.joinpath(default_pip_executable).unlink() + expected_pip_executable = major_pip_executable + + venv = VirtualEnv(venv_path) + + assert Path(venv.python).name == expected_executable + assert Path(venv.pip).name == expected_pip_executable From d526348c6c094c01245744076d4f7f26275016bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Fri, 27 Aug 2021 17:44:04 +0200 Subject: [PATCH 3/6] Ensure correct paths are used for generic envs --- poetry/utils/env.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/poetry/utils/env.py b/poetry/utils/env.py index 485a2d20420..29bb7238a41 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -152,6 +152,38 @@ def _version_nodot(version): print(json.dumps(sysconfig.get_paths())) """ +GET_PATHS_FOR_GENERIC_ENVS = """\ +# We can't use sysconfig.get_paths() because +# on some distributions it does not return the proper paths +# (those used by pip for instance). We go through distutils +# to get the proper ones. +import json +import site +import sysconfig + +from distutils.command.install import SCHEME_KEYS # noqa +from distutils.core import Distribution + +d = Distribution() +d.parse_config_files() +obj = d.get_command_obj("install", create=True) +obj.finalize_options() + +paths = sysconfig.get_paths().copy() +for key in SCHEME_KEYS: + if key == "headers": + # headers is not a path returned by sysconfig.get_paths() + continue + + paths[key] = getattr(obj, f"install_{key}") + +if site.check_enableusersite() and hasattr(obj, "install_usersite"): + paths["usersite"] = getattr(obj, "install_usersite") + paths["userbase"] = getattr(obj, "install_userbase") + +print(json.dumps(paths)) +""" + class SitePackages: def __init__( @@ -1617,6 +1649,11 @@ def _updated_path(self) -> str: class GenericEnv(VirtualEnv): + def get_paths(self) -> Dict[str, str]: + output = self.run_python_script(GET_PATHS_FOR_GENERIC_ENVS) + + return json.loads(output) + def is_venv(self) -> bool: return self._path != self._base From c7342e45824e2ed136645a7f59e103fda4ca7425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Mon, 6 Sep 2021 18:17:32 +0200 Subject: [PATCH 4/6] Fix executables discovery for generic environments --- poetry/utils/env.py | 155 +++++++++++++++++++++++++++++++--------- tests/utils/test_env.py | 82 +++++++++++++++++++++ 2 files changed, 203 insertions(+), 34 deletions(-) diff --git a/poetry/utils/env.py b/poetry/utils/env.py index 29bb7238a41..c9f3a780401 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -1042,20 +1042,21 @@ def get_system_env(cls, naive: bool = False) -> Union["SystemEnv", "GenericEnv"] (e.g. plugin installation or self update). """ prefix, base_prefix = Path(sys.prefix), Path(cls.get_base_prefix()) + env = SystemEnv(prefix) if not naive: if prefix.joinpath("poetry_env").exists(): - return GenericEnv(base_prefix) - - from poetry.locations import data_dir - - try: - prefix.relative_to(data_dir()) - except ValueError: - pass + env = GenericEnv(base_prefix, child_env=env) else: - return GenericEnv(base_prefix) + from poetry.locations import data_dir - return SystemEnv(prefix) + try: + prefix.relative_to(data_dir()) + except ValueError: + pass + else: + env = GenericEnv(base_prefix, child_env=env) + + return env @classmethod def get_base_prefix(cls) -> Path: @@ -1093,29 +1094,10 @@ def __init__(self, path: Path, base: Optional[Path] = None) -> None: self._path = path self._bin_dir = self._path / bin_dir - try: - python_executables = sorted( - [ - p.name - for p in self._bin_dir.glob("python*") - if re.match(r"python(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) - ] - ) - self._executable = python_executables[0].rstrip(".exe") - except IndexError: - self._executable = "python" + (".exe" if self._is_windows else "") + self._executable = "python" + self._pip_executable = "pip" - try: - pip_executables = sorted( - [ - p.name - for p in self._bin_dir.glob("pip*") - if re.match(r"pip(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) - ] - ) - self._pip_executable = pip_executables[0].rstrip(".exe") - except IndexError: - self._pip_executable = "pip" + (".exe" if self._is_windows else "") + self.find_executables() self._base = base or path @@ -1160,6 +1142,39 @@ def marker_env(self) -> Dict[str, Any]: return self._marker_env + @property + def parent_env(self) -> "GenericEnv": + return GenericEnv(self.base, child_env=self) + + def find_executables(self) -> None: + python_executables = sorted( + [ + p.name + for p in self._bin_dir.glob("python*") + if re.match(r"python(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) + ] + ) + if python_executables: + executable = python_executables[0] + if executable.endswith(".exe"): + executable = executable[:-4] + + self._executable = executable + + pip_executables = sorted( + [ + p.name + for p in self._bin_dir.glob("pip*") + if re.match(r"pip(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) + ] + ) + if pip_executables: + pip_executable = pip_executables[0] + if pip_executable.endswith(".exe"): + pip_executable = pip_executable[:-4] + + self._pip_executable = pip_executable + def get_embedded_wheel(self, distribution): return get_embed_wheel( distribution, "{}.{}".format(self.version_info[0], self.version_info[1]) @@ -1390,7 +1405,11 @@ def _bin(self, bin: str) -> str: """ Return path to the given executable. """ - bin_path = (self._bin_dir / bin).with_suffix(".exe" if self._is_windows else "") + if self._is_windows and not bin.endswith(".exe"): + bin_path = self._bin_dir / (bin + ".exe") + else: + bin_path = self._bin_dir / bin + if not bin_path.exists(): # On Windows, some executables can be in the base path # This is especially true when installing Python with @@ -1401,7 +1420,11 @@ def _bin(self, bin: str) -> str: # that creates a fake virtual environment pointing to # a base Python install. if self._is_windows: - bin_path = (self._path / bin).with_suffix(".exe") + if not bin.endswith(".exe"): + bin_path = self._bin_dir / (bin + ".exe") + else: + bin_path = self._path / bin + if bin_path.exists(): return str(bin_path) @@ -1649,6 +1672,70 @@ def _updated_path(self) -> str: class GenericEnv(VirtualEnv): + def __init__( + self, path: Path, base: Optional[Path] = None, child_env: Optional["Env"] = None + ) -> None: + self._child_env = child_env + + super().__init__(path, base=base) + + def find_executables(self) -> None: + patterns = [("python*", "pip*")] + + if self._child_env: + minor_version = "{}.{}".format( + self._child_env.version_info[0], self._child_env.version_info[1] + ) + major_version = "{}".format(self._child_env.version_info[0]) + patterns = [ + ("python{}".format(minor_version), "pip{}".format(minor_version)), + ("python{}".format(major_version), "pip{}".format(major_version)), + ] + + python_executable = None + pip_executable = None + + for python_pattern, pip_pattern in patterns: + if python_executable and pip_executable: + break + + if not python_executable: + python_executables = sorted( + [ + p.name + for p in self._bin_dir.glob(python_pattern) + if re.match(r"python(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) + ] + ) + + if python_executables: + executable = python_executables[0] + if executable.endswith(".exe"): + executable = executable[:-4] + + python_executable = executable + + if not pip_executable: + pip_executables = sorted( + [ + p.name + for p in self._bin_dir.glob(pip_pattern) + if re.match(r"pip(?:\d+(?:\.\d+)?)?(?:\.exe)?$", p.name) + ] + ) + if pip_executables: + pip_executable = pip_executables[0] + if pip_executable.endswith(".exe"): + pip_executable = pip_executable[:-4] + + pip_executable = pip_executable + + if python_executable: + self._executable = python_executable + + if pip_executable: + self._pip_executable = pip_executable + def get_paths(self) -> Dict[str, str]: output = self.run_python_script(GET_PATHS_FOR_GENERIC_ENVS) diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index 3fa57ec7aba..ded0f16f819 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -19,6 +19,7 @@ from poetry.utils.env import GET_BASE_PREFIX from poetry.utils.env import EnvCommandError from poetry.utils.env import EnvManager +from poetry.utils.env import GenericEnv from poetry.utils.env import NoCompatiblePythonVersionFound from poetry.utils.env import SystemEnv from poetry.utils.env import VirtualEnv @@ -1001,3 +1002,84 @@ def test_env_finds_the_correct_executables(tmp_dir, manager): assert Path(venv.python).name == expected_executable assert Path(venv.pip).name == expected_pip_executable + + +def test_env_finds_the_correct_executables_for_generic_env(tmp_dir, manager): + venv_path = Path(tmp_dir) / "Virtual Env" + child_venv_path = Path(tmp_dir) / "Child Virtual Env" + manager.build_venv(str(venv_path), with_pip=True) + parent_venv = VirtualEnv(venv_path) + manager.build_venv( + str(child_venv_path), executable=parent_venv.python, with_pip=True + ) + venv = GenericEnv(parent_venv.path, child_env=VirtualEnv(child_venv_path)) + + expected_executable = "python{}.{}{}".format( + sys.version_info[0], sys.version_info[1], ".exe" if WINDOWS else "" + ) + expected_pip_executable = "pip{}.{}{}".format( + sys.version_info[0], sys.version_info[1], ".exe" if WINDOWS else "" + ) + + assert Path(venv.python).name == expected_executable + assert Path(venv.pip).name == expected_pip_executable + + +def test_env_finds_fallback_executables_for_generic_env(tmp_dir, manager): + venv_path = Path(tmp_dir) / "Virtual Env" + child_venv_path = Path(tmp_dir) / "Child Virtual Env" + manager.build_venv(str(venv_path), with_pip=True) + parent_venv = VirtualEnv(venv_path) + manager.build_venv( + str(child_venv_path), executable=parent_venv.python, with_pip=True + ) + venv = GenericEnv(parent_venv.path, child_env=VirtualEnv(child_venv_path)) + + default_executable = "python" + (".exe" if WINDOWS else "") + major_executable = "python{}{}".format( + sys.version_info[0], ".exe" if WINDOWS else "" + ) + minor_executable = "python{}.{}{}".format( + sys.version_info[0], sys.version_info[1], ".exe" if WINDOWS else "" + ) + expected_executable = minor_executable + if ( + venv._bin_dir.joinpath(expected_executable).exists() + and venv._bin_dir.joinpath(major_executable).exists() + ): + venv._bin_dir.joinpath(expected_executable).unlink() + expected_executable = major_executable + + if ( + venv._bin_dir.joinpath(expected_executable).exists() + and venv._bin_dir.joinpath(default_executable).exists() + ): + venv._bin_dir.joinpath(expected_executable).unlink() + expected_executable = default_executable + + default_pip_executable = "pip" + (".exe" if WINDOWS else "") + major_pip_executable = "pip{}{}".format( + sys.version_info[0], ".exe" if WINDOWS else "" + ) + minor_pip_executable = "pip{}.{}{}".format( + sys.version_info[0], sys.version_info[1], ".exe" if WINDOWS else "" + ) + expected_pip_executable = minor_pip_executable + if ( + venv._bin_dir.joinpath(expected_pip_executable).exists() + and venv._bin_dir.joinpath(major_pip_executable).exists() + ): + venv._bin_dir.joinpath(expected_pip_executable).unlink() + expected_pip_executable = major_pip_executable + + if ( + venv._bin_dir.joinpath(expected_pip_executable).exists() + and venv._bin_dir.joinpath(default_pip_executable).exists() + ): + venv._bin_dir.joinpath(expected_pip_executable).unlink() + expected_pip_executable = default_pip_executable + + venv = GenericEnv(parent_venv.path, child_env=VirtualEnv(child_venv_path)) + + assert Path(venv.python).name == expected_executable + assert Path(venv.pip).name == expected_pip_executable From 041e10f73c8fcaa64f535f04d8b7ed25bbbce0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Tue, 7 Sep 2021 15:26:03 +0200 Subject: [PATCH 5/6] Fix generic environments command execution --- poetry/console/commands/env/info.py | 4 +--- poetry/utils/env.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/poetry/console/commands/env/info.py b/poetry/console/commands/env/info.py index 5f7f185419d..791c71a175c 100644 --- a/poetry/console/commands/env/info.py +++ b/poetry/console/commands/env/info.py @@ -33,8 +33,6 @@ def handle(self) -> Optional[int]: self._display_complete_info(env) def _display_complete_info(self, env: "Env") -> None: - from poetry.utils.env import GenericEnv - env_python_version = ".".join(str(s) for s in env.version_info[:3]) self.line("") self.line("Virtualenv") @@ -60,7 +58,7 @@ def _display_complete_info(self, env: "Env") -> None: self.line("") - system_env = GenericEnv(env.base) + system_env = env.parent_env self.line("System") self.line( "\n".join( diff --git a/poetry/utils/env.py b/poetry/utils/env.py index c9f3a780401..4a6f42291ac 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -762,7 +762,7 @@ def remove(self, python: str) -> "Env": self.remove_venv(venv) - return VirtualEnv(venv) + return VirtualEnv(venv, venv) def create_venv( self, @@ -1741,6 +1741,21 @@ def get_paths(self) -> Dict[str, str]: return json.loads(output) + def execute(self, bin: str, *args: str, **kwargs: Any) -> Optional[int]: + command = self.get_command_from_bin(bin) + list(args) + env = kwargs.pop("env", {k: v for k, v in os.environ.items()}) + + if not self._is_windows: + return os.execvpe(command[0], command, env=env) + else: + exe = subprocess.Popen([command[0]] + command[1:], env=env, **kwargs) + exe.communicate() + + return exe.returncode + + def _run(self, cmd: List[str], **kwargs: Any) -> Optional[int]: + return super(VirtualEnv, self)._run(cmd, **kwargs) + def is_venv(self) -> bool: return self._path != self._base From 96bc4ee3a4d6cc009c5032bd7d6559f8c16c7eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Mon, 13 Sep 2021 23:35:25 +0200 Subject: [PATCH 6/6] Fix tests on windows --- tests/console/commands/env/test_info.py | 3 +-- tests/utils/test_env.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/console/commands/env/test_info.py b/tests/console/commands/env/test_info.py index 7212004b418..f57960af039 100644 --- a/tests/console/commands/env/test_info.py +++ b/tests/console/commands/env/test_info.py @@ -4,7 +4,6 @@ import pytest -from poetry.utils._compat import WINDOWS from poetry.utils.env import MockEnv @@ -45,7 +44,7 @@ def test_env_info_displays_complete_info(tester): base_prefix=str(Path("/base/prefix")), base_version=".".join(str(v) for v in sys.version_info[:3]), executable=sys.executable, - base_executable="python" + (".exe" if WINDOWS else ""), + base_executable="python", ) assert expected == tester.io.fetch_output() diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index ded0f16f819..d7535553758 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -1001,7 +1001,7 @@ def test_env_finds_the_correct_executables(tmp_dir, manager): venv = VirtualEnv(venv_path) assert Path(venv.python).name == expected_executable - assert Path(venv.pip).name == expected_pip_executable + assert Path(venv.pip).name.startswith(expected_pip_executable.split(".")[0]) def test_env_finds_the_correct_executables_for_generic_env(tmp_dir, manager): @@ -1021,6 +1021,10 @@ def test_env_finds_the_correct_executables_for_generic_env(tmp_dir, manager): sys.version_info[0], sys.version_info[1], ".exe" if WINDOWS else "" ) + if WINDOWS: + expected_executable = "python.exe" + expected_pip_executable = "pip.exe" + assert Path(venv.python).name == expected_executable assert Path(venv.pip).name == expected_pip_executable @@ -1079,6 +1083,12 @@ def test_env_finds_fallback_executables_for_generic_env(tmp_dir, manager): venv._bin_dir.joinpath(expected_pip_executable).unlink() expected_pip_executable = default_pip_executable + if not venv._bin_dir.joinpath(expected_executable).exists(): + expected_executable = default_executable + + if not venv._bin_dir.joinpath(expected_pip_executable).exists(): + expected_pip_executable = default_pip_executable + venv = GenericEnv(parent_venv.path, child_env=VirtualEnv(child_venv_path)) assert Path(venv.python).name == expected_executable