summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/changelog/1909.feature.rst2
-rw-r--r--src/tox/session/cmd/run/common.py51
-rw-r--r--src/tox/session/cmd/run/parallel.py2
-rw-r--r--src/tox/session/cmd/run/sequential.py2
-rw-r--r--src/tox/util/spinner.py14
-rw-r--r--tests/session/cmd/test_parallel.py10
-rw-r--r--tests/tox_env/python/virtual_env/test_setuptools.py2
7 files changed, 53 insertions, 30 deletions
diff --git a/docs/changelog/1909.feature.rst b/docs/changelog/1909.feature.rst
new file mode 100644
index 00000000..a48f2757
--- /dev/null
+++ b/docs/changelog/1909.feature.rst
@@ -0,0 +1,2 @@
+Do not display status update environment reports when interrupted or for the final environment ran (because at the
+final report will be soon printed and makes the status update redundant) - by :user:`gaborbernat`.
diff --git a/src/tox/session/cmd/run/common.py b/src/tox/session/cmd/run/common.py
index fcfdd49d..d39b0279 100644
--- a/src/tox/session/cmd/run/common.py
+++ b/src/tox/session/cmd/run/common.py
@@ -163,7 +163,7 @@ def report(start: float, runs: List[ToxEnvRunResult], is_colored: bool) -> int:
logger = logging.getLogger(__name__)
-def execute(state: State, max_workers: Optional[int], spinner: bool, live: bool) -> int:
+def execute(state: State, max_workers: Optional[int], has_spinner: bool, live: bool) -> int:
interrupt, done = Event(), Event()
results: List[ToxEnvRunResult] = []
future_to_env: Dict["Future[ToxEnvRunResult]", ToxEnv] = {}
@@ -173,6 +173,7 @@ def execute(state: State, max_workers: Optional[int], spinner: bool, live: bool)
to_run_list.append(env)
previous, has_previous = None, False
try:
+ spinner = ToxSpinner(has_spinner, state, len(to_run_list))
try:
thread = Thread(
target=_queue_and_wait,
@@ -183,6 +184,7 @@ def execute(state: State, max_workers: Optional[int], spinner: bool, live: bool)
thread.join()
except KeyboardInterrupt:
previous, has_previous = signal(SIGINT, Handlers.SIG_IGN), True
+ spinner.print_report = False # no need to print reports at this point, final report coming up
logger.error(f"[{os.getpid()}] KeyboardInterrupt - teardown started")
interrupt.set()
for future, tox_env in list(future_to_env.items()):
@@ -236,12 +238,12 @@ def _queue_and_wait(
interrupt: Event,
done: Event,
max_workers: Optional[int],
- has_spinner: bool,
+ spinner: ToxSpinner,
live: bool,
) -> None:
try:
options = state.options
- with ToxSpinner(has_spinner, state, len(to_run_list)) as spinner:
+ with spinner:
max_workers = len(to_run_list) if max_workers is None else max_workers
completed: Set[str] = set()
envs_to_run_generator = ready_to_run_envs(state, to_run_list, completed)
@@ -252,11 +254,8 @@ def _queue_and_wait(
try:
executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="tox-driver")
+ env_list: List[str] = []
while True:
- env_list: List[str] = next(envs_to_run_generator, [])
- if not env_list and not future_to_env:
- break
-
for env in env_list: # queue all available
tox_env_to_run = state.tox_env(env)
if interrupt.is_set(): # queue the rest as failed upfront
@@ -267,17 +266,33 @@ def _queue_and_wait(
else:
future = executor.submit(_run, tox_env_to_run)
future_to_env[future] = tox_env_to_run
- future = next(as_completed(future_to_env))
- tox_env_done = future_to_env.pop(future)
- try:
- result: ToxEnvRunResult = future.result()
- except CancelledError:
- tox_env_done.teardown()
- name = tox_env_done.conf.name
- result = ToxEnvRunResult(name=name, skipped=False, code=-3, outcomes=[], duration=MISS_DURATION)
- results.append(result)
- completed.add(result.name)
- _handle_one_run_done(result, spinner, state, live)
+
+ if not future_to_env:
+ result: Optional[ToxEnvRunResult] = None
+ else: # if we have queued wait for completed
+ future = next(as_completed(future_to_env))
+ tox_env_done = future_to_env.pop(future)
+ try:
+ result = future.result()
+ except CancelledError:
+ tox_env_done.teardown()
+ name = tox_env_done.conf.name
+ result = ToxEnvRunResult(
+ name=name, skipped=False, code=-3, outcomes=[], duration=MISS_DURATION
+ )
+ results.append(result)
+ completed.add(result.name)
+
+ env_list = next(envs_to_run_generator, [])
+ # if nothing running and nothing more to run we're done
+ final_run = not env_list and not future_to_env
+ if final_run: # disable report on final env
+ spinner.print_report = False
+ if result is not None:
+ _handle_one_run_done(result, spinner, state, live)
+ if final_run:
+ break
+
except BaseException: # pragma: no cover # noqa
logging.exception("Internal Error") # pragma: no cover
raise # pragma: no cover
diff --git a/src/tox/session/cmd/run/parallel.py b/src/tox/session/cmd/run/parallel.py
index ffab1a3e..d68d84ba 100644
--- a/src/tox/session/cmd/run/parallel.py
+++ b/src/tox/session/cmd/run/parallel.py
@@ -74,6 +74,6 @@ def run_parallel(state: State) -> int:
return execute(
state,
max_workers=state.options.parallel,
- spinner=state.options.parallel_no_spinner is False and state.options.parallel_live is False,
+ has_spinner=state.options.parallel_no_spinner is False and state.options.parallel_live is False,
live=state.options.parallel_live,
)
diff --git a/src/tox/session/cmd/run/sequential.py b/src/tox/session/cmd/run/sequential.py
index e2f1ef8e..ee935e56 100644
--- a/src/tox/session/cmd/run/sequential.py
+++ b/src/tox/session/cmd/run/sequential.py
@@ -17,4 +17,4 @@ def tox_add_option(parser: ToxParser) -> None:
def run_sequential(state: State) -> int:
- return execute(state, max_workers=1, spinner=False, live=True)
+ return execute(state, max_workers=1, has_spinner=False, live=True)
diff --git a/src/tox/util/spinner.py b/src/tox/util/spinner.py
index 527e2914..19cb0e33 100644
--- a/src/tox/util/spinner.py
+++ b/src/tox/util/spinner.py
@@ -54,6 +54,7 @@ class Spinner:
self.frames = self.UNICODE_FRAMES if _file_support_encoding(self.UNICODE_FRAMES, stream) else self.ASCII_FRAMES
self.stream = stream
self.total = total
+ self.print_report = True
self._envs: Dict[str, float] = OrderedDict()
self._frame_index = 0
@@ -128,12 +129,13 @@ class Spinner:
start_at = self._envs.pop(key, None)
if self.enabled:
self.clear()
- duration = MISS_DURATION if start_at is None else time.monotonic() - start_at
- base = f"{key}: {status} in {td_human_readable(duration)}"
- if self.is_colored:
- base = f"{color}{base}{Fore.RESET}"
- base += os.linesep
- self.stream.write(base)
+ if self.print_report:
+ duration = MISS_DURATION if start_at is None else time.monotonic() - start_at
+ base = f"{key}: {status} in {td_human_readable(duration)}"
+ if self.is_colored:
+ base = f"{color}{base}{Fore.RESET}"
+ base += os.linesep
+ self.stream.write(base)
def disable_cursor(self) -> None:
if self.stream.isatty():
diff --git a/tests/session/cmd/test_parallel.py b/tests/session/cmd/test_parallel.py
index 4b590c9c..79d8dc25 100644
--- a/tests/session/cmd/test_parallel.py
+++ b/tests/session/cmd/test_parallel.py
@@ -63,6 +63,7 @@ def test_parallel_general(tox_project: ToxProjectCreator, monkeypatch: MonkeyPat
out = outcome.out
oks, skips, fails = {"a", "b", "c"}, {"d"}, {"e", "f"}
+ missing = set()
for env in "a", "b", "c", "d", "e", "f":
if env in ("c", "e"):
assert "run c" in out, out
@@ -73,11 +74,14 @@ def test_parallel_general(tox_project: ToxProjectCreator, monkeypatch: MonkeyPat
of_type = "OK" if env in oks else ("SKIP" if env in skips else "FAIL")
of_type_icon = "✔" if env in oks else ("⚠" if env in skips else "✖")
env_done = f"{env}: {of_type} {of_type_icon}"
- assert env_done in out, out
-
+ is_missing = env_done not in out
+ if is_missing:
+ missing.add(env_done)
env_report = f" {env}: {of_type} {'code 1 ' if env in fails else ''}("
assert env_report in out, out
- assert out.index(env_done) < out.index(env_report), out
+ if not is_missing:
+ assert out.index(env_done) < out.index(env_report), out
+ assert len(missing) == 1, out
def test_parallel_run_live_out(tox_project: ToxProjectCreator) -> None:
diff --git a/tests/tox_env/python/virtual_env/test_setuptools.py b/tests/tox_env/python/virtual_env/test_setuptools.py
index f7bdfe0a..33d0aecb 100644
--- a/tests/tox_env/python/virtual_env/test_setuptools.py
+++ b/tests/tox_env/python/virtual_env/test_setuptools.py
@@ -40,7 +40,7 @@ def test_setuptools_package(
result = outcome.out.split("\n")
py_messages = [i for i in result if "py: " in i]
- assert len(py_messages) == 6, "\n".join(py_messages) # 1 install wheel + 3 command + 1 report + 1 final report
+ assert len(py_messages) == 5, "\n".join(py_messages) # 1 install wheel + 3 command + 1 final report
package_messages = [i for i in result if ".pkg: " in i]
# 1 install requires + 1 build requires + 1 build meta + 1 build isolated + 1 exit