diff --git a/docs/changelog/147.bugfix.rst b/docs/changelog/147.bugfix.rst new file mode 100644 index 0000000..8ada1d9 --- /dev/null +++ b/docs/changelog/147.bugfix.rst @@ -0,0 +1,2 @@ +Treat specs with dot-only version components, such as ``python.``, as literal executable paths instead of raising +``IndexError`` - by :user:`harbinresearcher`. diff --git a/src/python_discovery/_py_spec.py b/src/python_discovery/_py_spec.py index d389ad6..8928318 100644 --- a/src/python_discovery/_py_spec.py +++ b/src/python_discovery/_py_spec.py @@ -50,6 +50,9 @@ def _int_or_none(val: str | None) -> int | None: def _parse_version_parts(version: str) -> tuple[int | None, int | None, int | None]: versions = tuple(int(i) for i in version.split(".") if i) + if not versions: + msg = "version must contain a numeric component" + raise ValueError(msg) if len(versions) > _MAX_VERSION_PARTS: msg = "too many version parts" raise ValueError(msg) diff --git a/tests/test_discovery.py b/tests/test_discovery.py index ff278a8..af13847 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -100,9 +100,10 @@ def test_discovery_fallback_fail(session_cache: DiskCache, caplog: pytest.LogCap assert "accepted" not in caplog.text -def test_discovery_fallback_ok(session_cache: DiskCache, caplog: pytest.LogCaptureFixture) -> None: +@pytest.mark.parametrize("missing", ["magic-one", "python."]) +def test_discovery_fallback_ok(missing: str, session_cache: DiskCache, caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.DEBUG) - result = get_interpreter(["magic-one", sys.executable], cache=session_cache) + result = get_interpreter([missing, sys.executable], cache=session_cache) assert result is not None, caplog.text assert result.executable == sys.executable, caplog.text assert "accepted" in caplog.text diff --git a/tests/test_py_spec.py b/tests/test_py_spec.py index d4e6b1f..e7f4d83 100644 --- a/tests/test_py_spec.py +++ b/tests/test_py_spec.py @@ -13,8 +13,8 @@ from pathlib import Path -def test_bad_py_spec() -> None: - text = "python2.3.4.5" +@pytest.mark.parametrize("text", ["python2.3.4.5", ".", "..", "...", "python.", "cpython..", "pypy..."]) +def test_bad_py_spec(text: str) -> None: spec = PythonSpec.from_string_spec(text) assert text in repr(spec) assert spec.str_spec == text