diff --git a/src/ducktools/pythonfinder/shared.py b/src/ducktools/pythonfinder/shared.py index 3048329..9aebbc2 100644 --- a/src/ducktools/pythonfinder/shared.py +++ b/src/ducktools/pythonfinder/shared.py @@ -278,6 +278,10 @@ def query_install( if metadata: output["metadata"].update(metadata) + if exe_path != output["executable"]: + output["metadata"]["sys_executable"] = output["executable"] + output["executable"] = exe_path + install = PythonInstall.from_json(**output, managed_by=managed_by) return install diff --git a/tests/test_cache.py b/tests/test_cache.py index 5e5bb1e..b7492b3 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -1,18 +1,18 @@ # ducktools-pythonfinder # MIT License -# +# # Copyright (c) 2025 David C Ellis -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -20,6 +20,8 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +import re +import sys import os.path from types import SimpleNamespace from unittest.mock import patch @@ -28,15 +30,16 @@ from ducktools.pythonfinder.shared import DetailFinder, PythonInstall -fake_python_path = "/path/to/python" -example_json = """ -{ - "version": [3, 13, 2, "final", 0], - "executable": "/path/to/python", - "architecture": "64bit", - "implementation": "cpython", - "metadata": {"freethreaded": false} -} +fake_python_path = "/path/to/python" if sys.platform != "win32" else r"X:\path\to\python" +json_python_path = re.escape(fake_python_path) +example_json = f""" +{{ + "version": [3, 13, 2, "final", 0], + "executable": "{json_python_path}", + "architecture": "64bit", + "implementation": "cpython", + "metadata": {{"freethreaded": false}} +}} """.strip() example_install = PythonInstall( @@ -160,7 +163,7 @@ def test_clear_invalid_runtimes(run_mock, stat_mock, temp_finder): with temp_finder, patch("os.path.exists") as exists_patch: exists_patch.return_value = True temp_finder.clear_invalid_runtimes() - + save_mock.assert_not_called() assert os.path.abspath(fake_python_path) in temp_finder.raw_cache @@ -224,4 +227,4 @@ def test_changed_stat_invalidates(run_mock, temp_finder): details = temp_finder.get_install_details(fake_python_path) assert temp_finder.raw_cache[fake_abspath]["mtime"] == 1739886572 - querymock.assert_called() \ No newline at end of file + querymock.assert_called() diff --git a/tests/test_pyenv.py b/tests/test_pyenv.py index 5dfc436..4b41a16 100644 --- a/tests/test_pyenv.py +++ b/tests/test_pyenv.py @@ -249,6 +249,7 @@ def test_pypy_version(fs, temp_finder): ver_folder = "pypy3.10-7.3.15" tmpdir = os.path.expanduser("~/.pyenv/versions") + homedir = os.path.expanduser("~") mock_output = textwrap.dedent( """ @@ -282,10 +283,13 @@ def test_pypy_version(fs, temp_finder): out_version = PythonInstall( version=(3, 10, 13, "final", 0), - executable="~/.pyenv/versions/pypy3.10-7.3.15/bin/pypy", + executable=f"{homedir}/.pyenv/versions/pypy3.10-7.3.15/bin/python", architecture="64bit", implementation="pypy", - metadata={"pypy_version": (7, 3, 15, "final", 0)}, + metadata={ + "pypy_version": (7, 3, 15, "final", 0), + "sys_executable": "~/.pyenv/versions/pypy3.10-7.3.15/bin/pypy" + }, managed_by="pyenv", )