import argparse from collections import Counter, defaultdict import shelve from typing import Counter, Dict, List, Optional import simfile from smoketest import SimfileError def analyze( simfile_errors: Dict[str, List[SimfileError]], *, traceback_substring: str, verbose: bool, number: Optional[int] ) -> None: error_counter = Counter() error_occurrences = defaultdict(list) for filename, errors in simfile_errors.items(): for error in errors: line = error.traceback.splitlines()[-1] if not traceback_substring or traceback_substring in line: error_counter[line] += 1 error_occurrences[line].append((filename, error.context)) for line, count in error_counter.most_common(number): print(f'=== {line} ({count} occurrences) ===') if verbose: for filename, context in error_occurrences[line]: print(f' * "{filename}" (during {repr(context)})') print() def main(): argparser = argparse.ArgumentParser() argparser.add_argument( '-s', '--shelf', help='shelf file to use', default=f'shelf-{simfile.__version__}', ) argparser.add_argument( '-t', '--traceback-substring', help='filter tracebacks by substring', ) argparser.add_argument( '-n', '--number', type=int, default=10, help='number of most common errors to print', ) argparser.add_argument( '-v', '--verbose', help='enable verbose output', default=False, action='store_true', ) args = argparser.parse_args() with shelve.open(args.shelf) as simfile_errors: analyze( simfile_errors, traceback_substring=args.traceback_substring, verbose=args.verbose, number=args.number, ) if __name__ == '__main__': main()