Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions news/158.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Fix full-version matching for Python installations discovered via the Windows
py launcher.

``py --list-paths`` only reports ``major.minor`` (e.g. ``3.11``), so
``PyLauncherFinder`` was storing ``patch=None`` for every entry. Callers that
searched for a specific full version such as ``3.11.9`` (e.g. from
``python_full_version`` in a Pipfile) received no match because
``matches(patch=9)`` evaluated ``None == 9 → False``.

The finder now queries each discovered executable for its real version string
(e.g. ``3.11.9``) via ``get_python_version()`` after the py-launcher lookup,
so that full-version searches succeed. If the executable cannot be queried the
code falls back gracefully to the ``major.minor`` string reported by the py
launcher.

23 changes: 21 additions & 2 deletions src/pythonfinder/finders/py_launcher_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ def _create_python_info_from_py_launcher(
Create a PythonInfo object from py launcher information.

Args:
version: The Python version (e.g. "3.11").
version: The Python version reported by the py launcher (e.g. "3.11").
This is typically only major.minor; the full patch version is
resolved by querying the executable so that searches for a
specific full version (e.g. "3.11.9") succeed.
path: The path to the Python executable.
is_default: "*" if this is the default version, "" otherwise.

Expand All @@ -102,14 +105,30 @@ def _create_python_info_from_py_launcher(
if not path or not os.path.exists(path):
return None

# Parse the version
# Parse the version reported by the py launcher (usually major.minor only).
try:
version_data = parse_python_version(version)
except InvalidPythonVersion:
if not self.ignore_unsupported:
raise
return None

# `py --list-paths` only reports major.minor (e.g. "3.11"). Resolve the
# real patch version by querying the executable so that callers searching
# for a full version string like "3.11.9" can match correctly.
if version_data.get("patch") is None:
try:
from ..utils.version_utils import get_python_version

full_version = get_python_version(path)
full_version_data = parse_python_version(full_version)
version_data = full_version_data
version = full_version
except Exception:
# If we can't run the executable, fall back to the major.minor
# version string provided by the py launcher.
pass

# Create the PythonInfo object
return PythonInfo(
path=Path(path),
Expand Down
Loading