def __call__(self, event): # noqa: D102 data = event[0] if isinstance(data, JobStarted): print('Starting >>> {data.identifier}'.format_map(locals()), flush=True) self._start_times[data.identifier] = time.monotonic() elif isinstance(data, TestFailure): job = event[1] self._with_test_failures.add(job) elif isinstance(data, JobEnded): if not data.rc: duration = \ time.monotonic() - self._start_times[data.identifier] duration_string = format_duration(duration) msg = 'Finished <<< {data.identifier} [{duration_string}]' \ .format_map(locals()) job = event[1] if job in self._with_test_failures: msg += '\t[ with test failures ]' writable = sys.stdout elif data.rc == SIGINT_RESULT: msg = 'Aborted <<< {data.identifier}'.format_map(locals()) writable = sys.stdout else: msg = 'Failed <<< {data.identifier}\t' \ '[ Exited with code {data.rc} ]'.format_map(locals()) writable = sys.stderr print(msg, file=writable, flush=True)
def __call__(self, event): # noqa: D102 data = event[0] if isinstance(data, JobStarted): msg_template = bcolors.START + 'Starting ' + bcolors.STARTBR + '>>>' + bcolors.PKG_NAME + ' {data.identifier}' + bcolors.ENDC print(msg_template.format_map(locals()), flush=True) self._start_times[data.identifier] = time.time() elif isinstance(data, TestFailure): job = event[1] self._with_test_failures.add(job) elif isinstance(data, JobEnded): if not data.rc: duration = time.time() - self._start_times[data.identifier] duration_string = format_duration(duration) msg_template = bcolors.FIN + 'Finished ' + bcolors.FINBR + '<<<' + bcolors.PKG_NAME + ' {data.identifier}' + bcolors.ENDC + ' [' + bcolors.TIME + '{duration_string}' + bcolors.ENDC + ']' msg = msg_template.format_map(locals()) job = event[1] if job in self._with_test_failures: msg += '\t[ with test failures ]' writable = sys.stdout elif data.rc == SIGINT_RESULT: msg_template = bcolors.WARNING + 'Aborted ' + '<<<' + bcolors.PKG_NAME + ' {data.identifier}' + bcolors.ENDC msg = msg_template.format_map(locals()) writable = sys.stdout else: msg_template = bcolors.FAIL + 'Failed ' + '<<<' + bcolors.PKG_NAME + ' {data.identifier}' + bcolors.ENDC + ' [' + bcolors.FAIL + 'Exited with code {data.rc}' + bcolors.ENDC + ']' msg = msg_template.format_map(locals()) writable = sys.stderr print(msg, file=writable, flush=True)
def _print_summary(self): # separate the summary from the previous output print() duration = time.monotonic() - self._start_time duration_string = format_duration(duration) count, job_type, _ = _msg_arguments(self._ended - self._interrupted - self._failed) print('Summary: {count} {job_type} finished ' '[{duration_string}]'.format_map(locals())) if self._failed: count, job_type, names = _msg_arguments(self._failed) print(' {count} {job_type} failed: {names}'.format_map(locals())) if self._interrupted: count, job_type, names = _msg_arguments(self._interrupted) print(' {count} {job_type} aborted: {names}'.format_map(locals())) if self._with_stderr: count, job_type, names = _msg_arguments(self._with_stderr) print(' {count} {job_type} had stderr output: {names}'.format_map( locals())) if self._with_test_failures: count, job_type, names = _msg_arguments(self._with_test_failures) print(' {count} {job_type} had test failures: {names}'.format_map( locals())) if len(self._queued) > len(self._ended): count = len(self._queued - self._ended) job_type = get_job_type_word_form(count) print(' {count} {job_type} not processed'.format_map(locals()))
def _print_summary(self): # separate the summary from the previous output print() duration = time.time() - self._start_time duration_string = format_duration(duration) count, plural_suffix, _ = _msg_arguments(self._ended - self._interrupted - self._failed) print('Summary: {count} package{plural_suffix} finished ' '[{duration_string}]'.format_map(locals())) if self._failed: count, plural_suffix, names = _msg_arguments(self._failed) print( ' {count} package{plural_suffix} failed: {names}'.format_map( locals())) if self._interrupted: count, plural_suffix, names = _msg_arguments(self._interrupted) print( ' {count} package{plural_suffix} aborted: {names}'.format_map( locals())) if self._with_stderr: count, plural_suffix, names = _msg_arguments(self._with_stderr) print( ' {count} package{plural_suffix} had stderr output: {names}'. format_map(locals())) if self._with_test_failures: count, plural_suffix, names = _msg_arguments( self._with_test_failures) print( ' {count} package{plural_suffix} had test failures: {names}'. format_map(locals())) if len(self._queued) > len(self._ended): count = len(self._queued - self._ended) plural_suffix = 's' if count != 1 else '' print(' {count} package{plural_suffix} not processed'.format_map( locals()))
def __call__(self, event): # noqa: D102 data = event[0] if isinstance(data, JobQueued): self._queued_count += 1 elif isinstance(data, JobStarted): job = event[1] assert job not in self._running self._running[job] = {'start_time': time.monotonic()} elif isinstance(data, JobProgress): job = event[1] self._running[job]['progress'] = [data.progress] elif isinstance(data, StdoutLine): line = data.line if isinstance(line, bytes): line = line.decode(errors='replace') match = self._progress_pattern.match(line) if not match: return job = event[1] progress = self._running[job].get('progress', []) while len(progress) > 1: progress.pop() progress.append(match.group(1).lstrip() + '%') elif isinstance(data, JobEnded): job = event[1] self._ended[job] = self._running[job] self._ended[job]['end_time'] = time.monotonic() self._ended[job]['rc'] = data.rc del self._running[job] elif isinstance(data, TimerEvent): now = time.monotonic() blocks = [] # runtime in seconds duration_string = format_duration( now - self._start_time, fixed_decimal_points=1) blocks.append('[{duration_string}]'.format_map(locals())) # number of completed jobs / number of jobs blocks.append( '[%d/%d complete]' % (len(self._ended), self._queued_count)) # number of failed jobs if not zero failed_jobs = [ j for j, d in self._ended.items() if d['rc'] and d['rc'] != SIGINT_RESULT] if failed_jobs: blocks.append('[%d failed]' % len(failed_jobs)) # number of ongoing jobs if greater one if len(self._running) > 1: blocks.append('[%d ongoing]' % len(self._running)) # job identifier, label and time for ongoing jobs for job, d in self._running.items(): msg = job.task.context.pkg.name if 'progress' in d: msg += ':%s' % ' '.join(d['progress']) duration_string = format_duration( now - d['start_time'], fixed_decimal_points=1) blocks.append( '[{msg} - {duration_string}]'.format_map(locals())) # determine blocks which fit into terminal width max_width = shutil.get_terminal_size().columns for i in reversed(range(len(blocks))): msg = ' '.join(blocks[0:i + 1]) # append dots when skipping at least one block if i < len(blocks) - 1: msg += ' ...' if len(msg) < max_width: break else: return print(msg, end='\r') self._last_status_line_length = len(msg) elif isinstance(data, EventReactorShutdown): self._clear_last_status_line() atexit.unregister(self._clear_last_status_line)
def test_format_duration(): # seconds below 10 with two decimal points assert format_duration(0) == '0.00s' assert format_duration(0.001) == '0.00s' assert format_duration(0.004999) == '0.00s' assert format_duration(0.005) == '0.01s' assert format_duration(9.99) == '9.99s' assert format_duration(9.994999) == '9.99s' assert format_duration(9.995) == '9.99s' # floating point imprecision # seconds between 10 and 60 with one decimal points assert format_duration(9.995001) == '10.0s' assert format_duration(10) == '10.0s' assert format_duration(59.94) == '59.9s' # seconds above one minute with no decimal points assert format_duration(59.95) == '1min 0s' assert format_duration(83.45) == '1min 23s' assert format_duration(119.49) == '1min 59s' assert format_duration(119.5) == '2min 0s' assert format_duration(3599.4) == '59min 59s' # seconds above one hour with no decimal points assert format_duration(3599.5) == '1h 0min 0s' assert format_duration(5025.123) == '1h 23min 45s' assert format_duration(3599999) == '999h 59min 59s' # zero fixed decimal point assert format_duration(1.5, fixed_decimal_points=0) == '2s' assert format_duration(12.345, fixed_decimal_points=0) == '12s' # one fixed decimal points assert format_duration(1.5, fixed_decimal_points=1) == '1.5s' assert format_duration(12.345, fixed_decimal_points=1) == '12.3s' assert format_duration(34.5, fixed_decimal_points=1) == '34.5s' assert format_duration(3599.4, fixed_decimal_points=1) == '59min 59.4s' assert format_duration(4984.5, fixed_decimal_points=1) == '1h 23min 4.5s' # raise for negative parameter with pytest.raises(ValueError): format_duration(-1.0)