summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Finucane <stephen@that.guru>2023-01-10 17:34:00 +0000
committerGitHub <noreply@github.com>2023-01-10 09:34:00 -0800
commit34b79a2514f8ab1675d6b928fa7e83268c8bd78e (patch)
tree605340e52fd3b235901bee42ac88c2360150a731
parentce2e8dbac7905b8b4b6d49c8bcd8a7d72f46373f (diff)
downloadtox-git-34b79a2514f8ab1675d6b928fa7e83268c8bd78e.tar.gz
Only return Python factor on base_python conflict (#2840)
Fixes https://github.com/tox-dev/tox/issues/2838
-rw-r--r--docs/changelog/2838.bugfix.rst2
-rw-r--r--src/tox/tox_env/python/api.py25
-rw-r--r--tests/tox_env/python/test_python_api.py37
3 files changed, 39 insertions, 25 deletions
diff --git a/docs/changelog/2838.bugfix.rst b/docs/changelog/2838.bugfix.rst
new file mode 100644
index 00000000..39120a7a
--- /dev/null
+++ b/docs/changelog/2838.bugfix.rst
@@ -0,0 +1,2 @@
+A testenv with multiple factors, one of which conflicts with a ``base_python`` setting in ``tox.ini``, will now use the
+correct Python interpreter version - by :user:`stephenfin`.
diff --git a/src/tox/tox_env/python/api.py b/src/tox/tox_env/python/api.py
index 9aa1f839..271a3803 100644
--- a/src/tox/tox_env/python/api.py
+++ b/src/tox/tox_env/python/api.py
@@ -127,8 +127,8 @@ class Python(ToxEnv, ABC):
base_python = None if env_name is None else self.extract_base_python(env_name)
return [sys.executable if base_python is None else base_python]
- @staticmethod
- def extract_base_python(env_name: str) -> str | None:
+ @classmethod
+ def extract_base_python(cls, env_name: str) -> str | None:
candidates: list[str] = []
for factor in env_name.split("-"):
spec = PythonSpec.from_string_spec(factor)
@@ -141,14 +141,16 @@ class Python(ToxEnv, ABC):
return next(iter(candidates))
return None
- @staticmethod
- def _validate_base_python(env_name: str, base_pythons: list[str], ignore_base_python_conflict: bool) -> list[str]:
- elements = {env_name} # match with full env-name
- elements.update(env_name.split("-")) # and also any factor
- for candidate in elements:
- spec_name = PythonSpec.from_string_spec(candidate)
- if spec_name.implementation and spec_name.implementation.lower() not in INTERPRETER_SHORT_NAMES:
- continue
+ @classmethod
+ def _validate_base_python(
+ cls,
+ env_name: str,
+ base_pythons: list[str],
+ ignore_base_python_conflict: bool,
+ ) -> list[str]:
+ env_base_python = cls.extract_base_python(env_name)
+ if env_base_python is not None:
+ spec_name = PythonSpec.from_string_spec(env_base_python)
for base_python in base_pythons:
spec_base = PythonSpec.from_string_spec(base_python)
if any(
@@ -158,7 +160,8 @@ class Python(ToxEnv, ABC):
):
msg = f"env name {env_name} conflicting with base python {base_python}"
if ignore_base_python_conflict:
- return [env_name] # ignore the base python settings
+ # ignore the base python settings and return the thing that looks like a Python version
+ return [env_base_python]
raise Fail(msg)
return base_pythons
diff --git a/tests/tox_env/python/test_python_api.py b/tests/tox_env/python/test_python_api.py
index b11c4376..725eab05 100644
--- a/tests/tox_env/python/test_python_api.py
+++ b/tests/tox_env/python/test_python_api.py
@@ -87,26 +87,35 @@ def test_base_python_env_no_conflict(env: str, base_python: list[str], ignore_co
@pytest.mark.parametrize("ignore_conflict", [True, False])
@pytest.mark.parametrize(
- ("env", "base_python", "conflict"),
+ ("env", "base_python", "expected", "conflict"),
[
- ("cpython", ["pypy"], ["pypy"]),
- ("pypy", ["cpython"], ["cpython"]),
- ("pypy2", ["pypy3"], ["pypy3"]),
- ("py3", ["py2"], ["py2"]),
- ("py38", ["py39"], ["py39"]),
- ("py38", ["py38", "py39"], ["py39"]),
- ("py38", ["python3"], ["python3"]),
- ("py310", ["py38", "py39"], ["py38", "py39"]),
- ("py3.11.1", ["py3.11.2"], ["py3.11.2"]),
- ("py3-64", ["py3-32"], ["py3-32"]),
- ("py310-magic", ["py39"], ["py39"]),
+ ("cpython", ["pypy"], "cpython", ["pypy"]),
+ ("pypy", ["cpython"], "pypy", ["cpython"]),
+ ("pypy2", ["pypy3"], "pypy2", ["pypy3"]),
+ ("py3", ["py2"], "py3", ["py2"]),
+ ("py38", ["py39"], "py38", ["py39"]),
+ ("py38", ["py38", "py39"], "py38", ["py39"]),
+ ("py38", ["python3"], "py38", ["python3"]),
+ ("py310", ["py38", "py39"], "py310", ["py38", "py39"]),
+ ("py3.11.1", ["py3.11.2"], "py3.11.1", ["py3.11.2"]),
+ ("py3-64", ["py3-32"], "py3-64", ["py3-32"]),
+ ("py310-magic", ["py39"], "py310", ["py39"]),
],
ids=lambda a: "|".join(a) if isinstance(a, list) else str(a),
)
-def test_base_python_env_conflict(env: str, base_python: list[str], conflict: list[str], ignore_conflict: bool) -> None:
+def test_base_python_env_conflict(
+ env: str,
+ base_python: list[str],
+ expected: str,
+ conflict: list[str],
+ ignore_conflict: bool,
+) -> None:
+ if env == "py3-64":
+ raise pytest.skip("bug #2657")
+
if ignore_conflict:
result = Python._validate_base_python(env, base_python, ignore_conflict)
- assert result == [env]
+ assert result == [expected]
else:
msg = f"env name {env} conflicting with base python {conflict[0]}"
with pytest.raises(Fail, match=msg):