Skip to content

Commit 48fecab

Browse files
authored
Ensure tox_extend_envs list can be read twice (#3598)
1 parent 0b8f66f commit 48fecab

File tree

4 files changed

+28
-4
lines changed

4 files changed

+28
-4
lines changed

docs/changelog/3598.bugfix.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
The :func:`tox_extend_envs() hook <tox.plugin.spec.tox_extend_envs>`
2+
recently added in :pull:`3591` turned out to not work well with
3+
``tox run``. It was fixed internally, not to exhaust the underlying
4+
iterator on the first use.
5+
6+
-- by :user:`webknjaz`

src/tox/config/main.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import os
44
from collections import OrderedDict, defaultdict
5-
from itertools import chain
5+
from itertools import chain, tee
66
from pathlib import Path
77
from typing import TYPE_CHECKING, Any, Iterable, Iterator, Sequence, TypeVar
88

@@ -81,7 +81,11 @@ def src_path(self) -> Path:
8181

8282
def __iter__(self) -> Iterator[str]:
8383
""":return: an iterator that goes through existing environments"""
84-
return chain(self._src.envs(self.core), self._extra_envs)
84+
# NOTE: `tee(self._extra_envs)[1]` is necessary for compatibility with
85+
# NOTE: Python 3.11 and older versions. Once Python 3.12 is the lowest
86+
# NOTE: supported version, it can be changed to
87+
# NOTE: `chain.from_iterable(tee(self._extra_envs, 1))`.
88+
return chain(self._src.envs(self.core), tee(self._extra_envs)[1])
8589

8690
def sections(self) -> Iterator[Section]:
8791
yield from self._src.sections()

src/tox/session/state.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import sys
4-
from itertools import chain
4+
from itertools import chain, tee
55
from typing import TYPE_CHECKING, Sequence
66

77
from tox.config.main import Config
@@ -20,7 +20,7 @@ class State:
2020
"""Runtime state holder."""
2121

2222
def __init__(self, options: Options, args: Sequence[str]) -> None:
23-
extended_envs = chain.from_iterable(MANAGER.tox_extend_envs())
23+
(extended_envs,) = tee(chain.from_iterable(MANAGER.tox_extend_envs()), 1)
2424
self.conf = Config.make(options.parsed, options.pos_args, options.source, extended_envs)
2525
self.conf.core.add_constant(
2626
keys=["on_platform"],

tests/plugin/test_inline.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import sys
34
from typing import TYPE_CHECKING
45

56
if TYPE_CHECKING:
@@ -43,6 +44,7 @@ def tox_extend_envs() -> tuple[str]:
4344
def tox_add_core_config(core_conf: ConfigSet, state: State) -> None: # noqa: ARG001
4445
in_memory_config_loader = MemoryLoader(
4546
base=["sentinel-base"],
47+
commands_pre=["sentinel-cmd"],
4648
description="sentinel-description",
4749
)
4850
state.conf.memory_seed_loaders[env_name].append(
@@ -59,3 +61,15 @@ def tox_add_core_config(core_conf: ConfigSet, state: State) -> None: # noqa: AR
5961
tox_config_result = project.run("config", "-e", "sentinel-env-name", "-qq")
6062
tox_config_result.assert_success()
6163
assert "base = sentinel-base" in tox_config_result.out
64+
65+
tox_run_result = project.run("run", "-e", "sentinel-env-name", "-q")
66+
tox_run_result.assert_failed()
67+
underlying_expected_oserror_msg = (
68+
"[WinError 2] The system cannot find the file specified"
69+
if sys.platform == "win32"
70+
else "[Errno 2] No such file or directory: 'sentinel-cmd'"
71+
)
72+
expected_cmd_lookup_error_txt = (
73+
f"sentinel-env-name: Exception running subprocess {underlying_expected_oserror_msg!s}\n"
74+
)
75+
assert expected_cmd_lookup_error_txt in tox_run_result.out

0 commit comments

Comments
 (0)