From e0a50b7f4f54fa58db4a82f42b4b8bf1c38a4351 Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Thu, 5 Dec 2024 10:39:34 -0600 Subject: [PATCH] Fix `pypyNone` interpreter spec when major version unspecified (#136) * Demonstrate `pypyNone` interpreter spec when major version unspecified * Fix `pypyNone` interpreter spec when major version unspecified This resolves the following error that occurs when the tox environment is simply named `pypy`: ``` pypy: skipped because could not find python interpreter with spec(s): pypyNone ``` --- src/tox_uv/_venv.py | 7 ++++++- tests/test_tox_uv_venv.py | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/tox_uv/_venv.py b/src/tox_uv/_venv.py index 4f3d44c..8ff19ca 100644 --- a/src/tox_uv/_venv.py +++ b/src/tox_uv/_venv.py @@ -183,7 +183,12 @@ def create_python_env(self) -> None: version_spec = sys.executable else: uv_imp = "" if (imp and imp == "cpython") else imp - version_spec = f"{uv_imp or ''}{base.major}.{base.minor}" if base.minor else f"{uv_imp or ''}{base.major}" + if not base.major: + version_spec = f"{uv_imp or ''}" + elif not base.minor: + version_spec = f"{uv_imp or ''}{base.major}" + else: + version_spec = f"{uv_imp or ''}{base.major}.{base.minor}" cmd: list[str] = [self.uv, "venv", "-p", version_spec, "--allow-existing"] if self.options.verbosity > 3: # noqa: PLR2004 diff --git a/tests/test_tox_uv_venv.py b/tests/test_tox_uv_venv.py index ed8b0b1..2466f3d 100644 --- a/tests/test_tox_uv_venv.py +++ b/tests/test_tox_uv_venv.py @@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, get_args import pytest +import tox.tox_env.errors from tox_uv._venv import PythonPreference @@ -54,6 +55,48 @@ def test_uv_venv_spec_major_only(tox_project: ToxProjectCreator) -> None: result.assert_success() +@pytest.mark.parametrize( + ("pypy", "expected_uv_pypy"), + [ + ("pypy", "pypy"), + ("pypy9", "pypy9"), + ("pypy999", "pypy9.99"), + ("pypy9.99", "pypy9.99"), + ], +) +def test_uv_venv_spec_pypy( + capfd: pytest.CaptureFixture[str], + tox_project: ToxProjectCreator, + pypy: str, + expected_uv_pypy: str, +) -> None: + """Validate that major and minor versions are correctly applied to implementations. + + This test prevents a regression that occurred when the testenv name was "pypy": + the uv runner was asked to use "pypyNone" as the Python version. + + The test is dependent on what PyPy interpreters are installed on the system; + if any PyPy is available then the "pypy" value will not raise a Skip exception, + and STDOUT will be captured in `result.out`. + + However, it is expected that no system will have PyPy v9.x installed, + so STDOUT must be read from `capfd` after the Skip exception is caught. + + Since it is unknown whether any PyPy interpreter will be installed, + the `else` block's branch coverage is disabled. + """ + + project = tox_project({"tox.ini": f"[tox]\nenv_list = {pypy}"}) + try: + result = project.run("config", "-vv") + except tox.tox_env.errors.Skip: + stdout, _ = capfd.readouterr() + else: # pragma: no cover (PyPy might not be available on the system) + stdout = result.out + assert "pypyNone" not in stdout + assert f"-p {expected_uv_pypy} " in stdout + + @pytest.fixture def other_interpreter_exe() -> pathlib.Path: # pragma: no cover """Returns an interpreter executable path that is not the exact same as `sys.executable`.