17db96d56Sopenharmony_ci 27db96d56Sopenharmony_cidef iter_clean_lines(lines): 37db96d56Sopenharmony_ci lines = iter(lines) 47db96d56Sopenharmony_ci for line in lines: 57db96d56Sopenharmony_ci line = line.strip() 67db96d56Sopenharmony_ci if line.startswith('# XXX'): 77db96d56Sopenharmony_ci continue 87db96d56Sopenharmony_ci yield line 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_cidef parse_table_lines(lines): 127db96d56Sopenharmony_ci lines = iter_clean_lines(lines) 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci for line in lines: 157db96d56Sopenharmony_ci if line.startswith(('####', '#----')): 167db96d56Sopenharmony_ci kind = 0 if line[1] == '#' else 1 177db96d56Sopenharmony_ci try: 187db96d56Sopenharmony_ci line = next(lines).strip() 197db96d56Sopenharmony_ci except StopIteration: 207db96d56Sopenharmony_ci line = '' 217db96d56Sopenharmony_ci if not line.startswith('# '): 227db96d56Sopenharmony_ci raise NotImplementedError(line) 237db96d56Sopenharmony_ci yield kind, line[2:].lstrip() 247db96d56Sopenharmony_ci continue 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci maybe = None 277db96d56Sopenharmony_ci while line.startswith('#'): 287db96d56Sopenharmony_ci if line != '#' and line[1] == ' ': 297db96d56Sopenharmony_ci maybe = line[2:].lstrip() 307db96d56Sopenharmony_ci try: 317db96d56Sopenharmony_ci line = next(lines).strip() 327db96d56Sopenharmony_ci except StopIteration: 337db96d56Sopenharmony_ci return 347db96d56Sopenharmony_ci if not line: 357db96d56Sopenharmony_ci break 367db96d56Sopenharmony_ci else: 377db96d56Sopenharmony_ci if line: 387db96d56Sopenharmony_ci if maybe: 397db96d56Sopenharmony_ci yield 2, maybe 407db96d56Sopenharmony_ci yield 'row', line 417db96d56Sopenharmony_ci 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_cidef iter_sections(lines): 447db96d56Sopenharmony_ci header = None 457db96d56Sopenharmony_ci section = [] 467db96d56Sopenharmony_ci for kind, value in parse_table_lines(lines): 477db96d56Sopenharmony_ci if kind == 'row': 487db96d56Sopenharmony_ci if not section: 497db96d56Sopenharmony_ci if header is None: 507db96d56Sopenharmony_ci header = value 517db96d56Sopenharmony_ci continue 527db96d56Sopenharmony_ci raise NotImplementedError(value) 537db96d56Sopenharmony_ci yield tuple(section), value 547db96d56Sopenharmony_ci else: 557db96d56Sopenharmony_ci if header is None: 567db96d56Sopenharmony_ci header = False 577db96d56Sopenharmony_ci section[kind:] = [value] 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_cidef collect_sections(lines): 617db96d56Sopenharmony_ci sections = {} 627db96d56Sopenharmony_ci for section, row in iter_sections(lines): 637db96d56Sopenharmony_ci if section not in sections: 647db96d56Sopenharmony_ci sections[section] = [row] 657db96d56Sopenharmony_ci else: 667db96d56Sopenharmony_ci sections[section].append(row) 677db96d56Sopenharmony_ci return sections 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_cidef collate_sections(lines): 717db96d56Sopenharmony_ci collated = {} 727db96d56Sopenharmony_ci for section, rows in collect_sections(lines).items(): 737db96d56Sopenharmony_ci parent = collated 747db96d56Sopenharmony_ci current = () 757db96d56Sopenharmony_ci for name in section: 767db96d56Sopenharmony_ci current += (name,) 777db96d56Sopenharmony_ci try: 787db96d56Sopenharmony_ci child, secrows, totalrows = parent[name] 797db96d56Sopenharmony_ci except KeyError: 807db96d56Sopenharmony_ci child = {} 817db96d56Sopenharmony_ci secrows = [] 827db96d56Sopenharmony_ci totalrows = [] 837db96d56Sopenharmony_ci parent[name] = (child, secrows, totalrows) 847db96d56Sopenharmony_ci parent = child 857db96d56Sopenharmony_ci if current == section: 867db96d56Sopenharmony_ci secrows.extend(rows) 877db96d56Sopenharmony_ci totalrows.extend(rows) 887db96d56Sopenharmony_ci return collated 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci############################# 927db96d56Sopenharmony_ci# the commands 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_cidef cmd_count_by_section(lines): 957db96d56Sopenharmony_ci div = ' ' + '-' * 50 967db96d56Sopenharmony_ci total = 0 977db96d56Sopenharmony_ci def render_tree(root, depth=0): 987db96d56Sopenharmony_ci nonlocal total 997db96d56Sopenharmony_ci indent = ' ' * depth 1007db96d56Sopenharmony_ci for name, data in root.items(): 1017db96d56Sopenharmony_ci subroot, rows, totalrows = data 1027db96d56Sopenharmony_ci sectotal = f'({len(totalrows)})' if totalrows != rows else '' 1037db96d56Sopenharmony_ci count = len(rows) if rows else '' 1047db96d56Sopenharmony_ci if depth == 0: 1057db96d56Sopenharmony_ci yield div 1067db96d56Sopenharmony_ci yield f'{sectotal:>7} {count:>4} {indent}{name}' 1077db96d56Sopenharmony_ci yield from render_tree(subroot, depth+1) 1087db96d56Sopenharmony_ci total += len(rows) 1097db96d56Sopenharmony_ci sections = collate_sections(lines) 1107db96d56Sopenharmony_ci yield from render_tree(sections) 1117db96d56Sopenharmony_ci yield div 1127db96d56Sopenharmony_ci yield f'(total: {total})' 1137db96d56Sopenharmony_ci 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci############################# 1167db96d56Sopenharmony_ci# the script 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_cidef parse_args(argv=None, prog=None): 1197db96d56Sopenharmony_ci import argparse 1207db96d56Sopenharmony_ci parser = argparse.ArgumentParser(prog=prog) 1217db96d56Sopenharmony_ci parser.add_argument('filename') 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci args = parser.parse_args(argv) 1247db96d56Sopenharmony_ci ns = vars(args) 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci return ns 1277db96d56Sopenharmony_ci 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_cidef main(filename): 1307db96d56Sopenharmony_ci with open(filename) as infile: 1317db96d56Sopenharmony_ci for line in cmd_count_by_section(infile): 1327db96d56Sopenharmony_ci print(line) 1337db96d56Sopenharmony_ci 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ciif __name__ == '__main__': 1367db96d56Sopenharmony_ci kwargs = parse_args() 1377db96d56Sopenharmony_ci main(**kwargs) 138