Skip to content

Commit

Permalink
fix "env use python" to use Python in PATH (#10187)
Browse files Browse the repository at this point in the history
  • Loading branch information
radoering authored Feb 16, 2025
1 parent 36e1c63 commit 1791aa4
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 13 deletions.
15 changes: 4 additions & 11 deletions src/poetry/utils/env/python/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,6 @@ def get_active_python(cls) -> Python | None:

return None

@classmethod
def from_executable(cls, path: Path | str) -> Python:
try:
return cls(python=findpython.PythonVersion(executable=Path(path)))
except (FileNotFoundError, NotADirectoryError, ValueError):
raise ValueError(f"{path} is not a valid Python executable")

@classmethod
def get_system_python(cls) -> Python:
"""
Expand All @@ -252,10 +245,10 @@ def get_system_python(cls) -> Python:

@classmethod
def get_by_name(cls, python_name: str) -> Python | None:
if Path(python_name).exists():
with contextlib.suppress(ValueError):
# if it is a path try assuming it is an executable
return cls.from_executable(python_name)
# Ignore broken installations.
with contextlib.suppress(ValueError):
if python := ShutilWhichPythonProvider.find_python_by_name(python_name):
return cls(python=python)

if python := findpython.find(python_name):
return cls(python=python)
Expand Down
10 changes: 8 additions & 2 deletions src/poetry/utils/env/python/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ def create(cls) -> Self | None:
return cls()

def find_pythons(self) -> Iterable[findpython.PythonVersion]:
if path := shutil.which("python"):
return [findpython.PythonVersion(executable=Path(path))]
if python := self.find_python_by_name("python"):
return [python]
return []

@classmethod
def find_python_by_name(cls, name: str) -> findpython.PythonVersion | None:
if path := shutil.which(name):
return findpython.PythonVersion(executable=Path(path))
return None


@dataclasses.dataclass
class PoetryPythonPathProvider(PathProvider): # type: ignore[misc]
Expand Down
37 changes: 37 additions & 0 deletions tests/utils/env/python/test_manager.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import platform
import sys

from typing import TYPE_CHECKING

Expand Down Expand Up @@ -95,3 +96,39 @@ def find_downloadable_versions_include_incompatible() -> None:
assert len(
list(Python.find_downloadable_versions(include_incompatible=True))
) > len(list(Python.find_downloadable_versions()))


@pytest.mark.parametrize(
("name", "expected_minor"),
[
("3.9", 9),
("3.10", 10),
("3.11", None),
],
)
def test_get_by_name_version(
mocked_python_register: MockedPythonRegister, name: str, expected_minor: int | None
) -> None:
mocked_python_register("3.9.1", implementation="CPython", parent="a")
mocked_python_register("3.10.3", implementation="CPython", parent="b")

python = Python.get_by_name(name)
if expected_minor is None:
assert python is None
else:
assert python is not None
assert python.minor == expected_minor


def test_get_by_name_python(without_mocked_findpython: None) -> None:
python = Python.get_by_name("python")
assert python is not None
assert python.version.major == 3
assert python.version.minor == sys.version_info.minor


def test_get_by_name_path(without_mocked_findpython: None) -> None:
python = Python.get_by_name(sys.executable)
assert python is not None
assert python.version.major == 3
assert python.version.minor == sys.version_info.minor
11 changes: 11 additions & 0 deletions tests/utils/env/python/test_python_providers.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
from __future__ import annotations

import sys

from typing import TYPE_CHECKING

from poetry.core.constraints.version import Version

from poetry.utils.env.python.providers import PoetryPythonPathProvider
from poetry.utils.env.python.providers import ShutilWhichPythonProvider


if TYPE_CHECKING:
from tests.types import MockedPoetryPythonRegister


def test_shutil_which_python_provider() -> None:
provider = ShutilWhichPythonProvider.create()
assert provider
pythons = list(provider.find_pythons())
assert len(pythons) == 1
assert pythons[0].minor == sys.version_info.minor


def test_poetry_python_path_provider_no_pythons() -> None:
provider = PoetryPythonPathProvider.create()
assert provider
Expand Down

0 comments on commit 1791aa4

Please sign in to comment.