From 05043f9e8d6eb26375dacac09652c61db5c04c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Mon, 2 Nov 2026 16:33:18 -0800 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20fix(cache):=20key=20exe=20lo?= =?UTF-8?q?okups=20by=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/python_discovery/_py_info.py | 4 ++-- tests/test_py_info_extra.py | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/python_discovery/_py_info.py b/src/python_discovery/_py_info.py index 64acb8f..09733de 100644 --- a/src/python_discovery/_py_info.py +++ b/src/python_discovery/_py_info.py @@ -484,7 +484,7 @@ def resolve_to_system(cls, cache: PyInfoCache | None, target: PythonInfo) -> Pyt target.executable = start_executable return target - _cache_exe_discovery: ClassVar[dict[tuple[str, bool], PythonInfo]] = {} + _cache_exe_discovery: ClassVar[dict[tuple[str, bool, VersionInfo], PythonInfo]] = {} def discover_exe( self, @@ -502,7 +502,7 @@ def discover_exe( :param exact: when ``True``, require an exact version match. :param env: environment mapping; defaults to :data:`os.environ`. """ - key = prefix, exact + key = prefix, exact, self.version_info if key in self._cache_exe_discovery and prefix: _LOGGER.debug("discover exe from cache %s - exact %s: %r", prefix, exact, self._cache_exe_discovery[key]) return self._cache_exe_discovery[key] diff --git a/tests/test_py_info_extra.py b/tests/test_py_info_extra.py index 84d75af..016636a 100644 --- a/tests/test_py_info_extra.py +++ b/tests/test_py_info_extra.py @@ -171,12 +171,28 @@ def test_resolve_to_system_single_prefix_self_link(mocker: MockerFixture, caplog def test_discover_exe_cache_hit() -> None: info = copy.deepcopy(CURRENT) cached = copy.deepcopy(CURRENT) - PythonInfo._cache_exe_discovery["/some/prefix", True] = cached + PythonInfo._cache_exe_discovery["/some/prefix", True, info.version_info] = cached try: result = info.discover_exe(MagicMock(), prefix="/some/prefix", exact=True) assert result is cached finally: - del PythonInfo._cache_exe_discovery["/some/prefix", True] + del PythonInfo._cache_exe_discovery["/some/prefix", True, info.version_info] + + +def test_discover_exe_cache_keeps_requested_version(tmp_path: Path) -> None: + prefix = CURRENT.prefix + assert prefix is not None + cache = DiskCache(tmp_path) + PythonInfo.clear_cache(cache) + try: + found = CURRENT.discover_exe(cache, prefix) + assert found.version_info == CURRENT.version_info + other = copy.deepcopy(CURRENT) + other.version_info = other.version_info._replace(major=0) + with pytest.raises(RuntimeError): + other.discover_exe(cache, prefix) + finally: + PythonInfo.clear_cache(cache) def test_check_exe_none_path(tmp_path: Path) -> None: From 5b887af485eb6d60ee96515782084f18c5d7ce7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Mon, 2 Nov 2026 16:34:14 -0800 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9D=20docs:=20note=20version=20loo?= =?UTF-8?q?kup=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/changelog/215.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/changelog/215.bugfix.rst diff --git a/docs/changelog/215.bugfix.rst b/docs/changelog/215.bugfix.rst new file mode 100644 index 0000000..d2f6ca7 --- /dev/null +++ b/docs/changelog/215.bugfix.rst @@ -0,0 +1 @@ +Prevent an earlier virtual-environment lookup from reporting an executable under the wrong Python version.