diff --git a/docs/changelog/238.bugfix.rst b/docs/changelog/238.bugfix.rst new file mode 100644 index 0000000..4814788 --- /dev/null +++ b/docs/changelog/238.bugfix.rst @@ -0,0 +1 @@ +Reject generic Python executables when a requested implementation is unavailable. diff --git a/src/python_discovery/_discovery.py b/src/python_discovery/_discovery.py index 3a51d78..07d8684 100644 --- a/src/python_discovery/_discovery.py +++ b/src/python_discovery/_discovery.py @@ -501,8 +501,8 @@ def path_exes(path: Path) -> Generator[tuple[Path, bool], None, None]: yield direct_path, impl_must_match for exe in path.iterdir(): - if pat.fullmatch(exe.name): - yield exe.absolute(), impl_must_match + if match := pat.fullmatch(exe.name): + yield exe.absolute(), impl_must_match or match["impl"].lower() == "python" return path_exes diff --git a/tests/test_discovery.py b/tests/test_discovery.py index 4ef500b..d498fa9 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -74,6 +74,13 @@ def test_discovery_via_path_not_found(tmp_path: Path, monkeypatch: pytest.Monkey assert interpreter is None +def test_unknown_implementation_rejects_python_on_path(tmp_path: Path, session_cache: DiskCache) -> None: + env = {"PATH": str(Path(sys.executable).parent), "UV_PYTHON_INSTALL_DIR": str(tmp_path / "missing")} + + assert get_interpreter("missing", [], cache=session_cache, env=env) is None + assert list(iter_interpreters("missing", cache=session_cache, env=env)) == [] + + @pytest.mark.skipif(sys.platform == "win32", reason="POSIX symlink names") def test_discovery_via_path_literal_symlink(tmp_path: Path) -> None: link = tmp_path / "python_custom"