summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBernát Gábor <bgabor8@bloomberg.net>2021-02-13 16:40:10 +0000
committerGitHub <noreply@github.com>2021-02-13 16:40:10 +0000
commitefed58a8c02f3c11dd21de2d61f0df80ac65c116 (patch)
tree4c9c50702c9d3384f6bc4a129e4827a174da5bc3 /src
parent15605d0696c8468f593b334264dab9fd698b0f50 (diff)
downloadtox-git-efed58a8c02f3c11dd21de2d61f0df80ac65c116.tar.gz
Smarter tox env finish status report (#1910)
- do not report when interrupted - do not report for the final env Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
Diffstat (limited to 'src')
-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
4 files changed, 43 insertions, 26 deletions
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():