Skip to content

Commit 34b79a2

Browse files
authored
Only return Python factor on base_python conflict (#2840)
Fixes #2838
1 parent ce2e8db commit 34b79a2

File tree

3 files changed

+39
-25
lines changed

3 files changed

+39
-25
lines changed

docs/changelog/2838.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
A testenv with multiple factors, one of which conflicts with a ``base_python`` setting in ``tox.ini``, will now use the
2+
correct Python interpreter version - by :user:`stephenfin`.

src/tox/tox_env/python/api.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ def default_base_python(self, conf: Config, env_name: str | None) -> list[str]:
127127
base_python = None if env_name is None else self.extract_base_python(env_name)
128128
return [sys.executable if base_python is None else base_python]
129129

130-
@staticmethod
131-
def extract_base_python(env_name: str) -> str | None:
130+
@classmethod
131+
def extract_base_python(cls, env_name: str) -> str | None:
132132
candidates: list[str] = []
133133
for factor in env_name.split("-"):
134134
spec = PythonSpec.from_string_spec(factor)
@@ -141,14 +141,16 @@ def extract_base_python(env_name: str) -> str | None:
141141
return next(iter(candidates))
142142
return None
143143

144-
@staticmethod
145-
def _validate_base_python(env_name: str, base_pythons: list[str], ignore_base_python_conflict: bool) -> list[str]:
146-
elements = {env_name} # match with full env-name
147-
elements.update(env_name.split("-")) # and also any factor
148-
for candidate in elements:
149-
spec_name = PythonSpec.from_string_spec(candidate)
150-
if spec_name.implementation and spec_name.implementation.lower() not in INTERPRETER_SHORT_NAMES:
151-
continue
144+
@classmethod
145+
def _validate_base_python(
146+
cls,
147+
env_name: str,
148+
base_pythons: list[str],
149+
ignore_base_python_conflict: bool,
150+
) -> list[str]:
151+
env_base_python = cls.extract_base_python(env_name)
152+
if env_base_python is not None:
153+
spec_name = PythonSpec.from_string_spec(env_base_python)
152154
for base_python in base_pythons:
153155
spec_base = PythonSpec.from_string_spec(base_python)
154156
if any(
@@ -158,7 +160,8 @@ def _validate_base_python(env_name: str, base_pythons: list[str], ignore_base_py
158160
):
159161
msg = f"env name {env_name} conflicting with base python {base_python}"
160162
if ignore_base_python_conflict:
161-
return [env_name] # ignore the base python settings
163+
# ignore the base python settings and return the thing that looks like a Python version
164+
return [env_base_python]
162165
raise Fail(msg)
163166
return base_pythons
164167

tests/tox_env/python/test_python_api.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,26 +87,35 @@ def test_base_python_env_no_conflict(env: str, base_python: list[str], ignore_co
8787

8888
@pytest.mark.parametrize("ignore_conflict", [True, False])
8989
@pytest.mark.parametrize(
90-
("env", "base_python", "conflict"),
90+
("env", "base_python", "expected", "conflict"),
9191
[
92-
("cpython", ["pypy"], ["pypy"]),
93-
("pypy", ["cpython"], ["cpython"]),
94-
("pypy2", ["pypy3"], ["pypy3"]),
95-
("py3", ["py2"], ["py2"]),
96-
("py38", ["py39"], ["py39"]),
97-
("py38", ["py38", "py39"], ["py39"]),
98-
("py38", ["python3"], ["python3"]),
99-
("py310", ["py38", "py39"], ["py38", "py39"]),
100-
("py3.11.1", ["py3.11.2"], ["py3.11.2"]),
101-
("py3-64", ["py3-32"], ["py3-32"]),
102-
("py310-magic", ["py39"], ["py39"]),
92+
("cpython", ["pypy"], "cpython", ["pypy"]),
93+
("pypy", ["cpython"], "pypy", ["cpython"]),
94+
("pypy2", ["pypy3"], "pypy2", ["pypy3"]),
95+
("py3", ["py2"], "py3", ["py2"]),
96+
("py38", ["py39"], "py38", ["py39"]),
97+
("py38", ["py38", "py39"], "py38", ["py39"]),
98+
("py38", ["python3"], "py38", ["python3"]),
99+
("py310", ["py38", "py39"], "py310", ["py38", "py39"]),
100+
("py3.11.1", ["py3.11.2"], "py3.11.1", ["py3.11.2"]),
101+
("py3-64", ["py3-32"], "py3-64", ["py3-32"]),
102+
("py310-magic", ["py39"], "py310", ["py39"]),
103103
],
104104
ids=lambda a: "|".join(a) if isinstance(a, list) else str(a),
105105
)
106-
def test_base_python_env_conflict(env: str, base_python: list[str], conflict: list[str], ignore_conflict: bool) -> None:
106+
def test_base_python_env_conflict(
107+
env: str,
108+
base_python: list[str],
109+
expected: str,
110+
conflict: list[str],
111+
ignore_conflict: bool,
112+
) -> None:
113+
if env == "py3-64":
114+
raise pytest.skip("bug #2657")
115+
107116
if ignore_conflict:
108117
result = Python._validate_base_python(env, base_python, ignore_conflict)
109-
assert result == [env]
118+
assert result == [expected]
110119
else:
111120
msg = f"env name {env} conflicting with base python {conflict[0]}"
112121
with pytest.raises(Fail, match=msg):

0 commit comments

Comments
 (0)