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..96c81714778 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,27 @@ 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 = "python" + (".exe" if WINDOWS else "") + default_pip_executable = "pip" + (".exe" if WINDOWS else "") + + if venv._bin_dir.joinpath(default_executable).exists(): + venv._bin_dir.joinpath(default_executable).unlink() + + if venv._bin_dir.joinpath(default_pip_executable).exists(): + venv._bin_dir.joinpath(default_pip_executable).unlink() + + venv = VirtualEnv(venv_path) + + assert Path(venv.python).name == "python{}{}".format( + sys.version_info[0], ".exe" if WINDOWS else "" + ) + assert Path(venv.pip).name == "pip{}{}".format( + sys.version_info[0], ".exe" if WINDOWS else "" + )