Created
January 10, 2020 08:43
-
-
Save atronah/f161289163ca5d682dd289d438c1210e to your computer and use it in GitHub Desktop.
Eternity log parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import csv | |
import datetime | |
import time | |
from itertools import groupby, chain | |
from functools import reduce | |
import click | |
def make_tree(data, group_indexes): | |
if group_indexes: | |
result = {} | |
group_column = group_indexes.pop(0) | |
key_func = lambda row: row[group_column] | |
for key, group in groupby(sorted(data, key=key_func), key=key_func): | |
result[key] = make_tree(group, list(group_indexes)) | |
return result | |
return list(data) | |
def get_child_rows(node): | |
if isinstance(node, dict): | |
return chain.from_iterable(map(get_child_rows, node.values())) | |
else: | |
return node | |
def calculate_total_for_tree(node, column_index): | |
duration_values = (time.strptime(row[column_index], '%H:%M:%S') for row in get_child_rows(node)) | |
return reduce(lambda x, y: x + datetime.timedelta(hours=y.tm_hour, minutes=y.tm_min, seconds=y.tm_sec), | |
duration_values, | |
datetime.timedelta()) | |
def print_tree(tree, total_column_index, tags_column_index, indent=''): | |
if isinstance(tree, dict): | |
for key, node in tree.items(): | |
total = calculate_total_for_tree(node, total_column_index) | |
if total.seconds == 0: | |
continue | |
tags_key_func = lambda row: row[tags_column_index] | |
tag_groups = groupby(sorted(get_child_rows(node), key=tags_key_func), key=tags_key_func) | |
totals = [('total', total)] + [(tag_name.strip(), calculate_total_for_tree(tag_rows, total_column_index)) | |
for tag_name, tag_rows in tag_groups if tag_name.strip()] | |
print(f'{indent}- {key} ({", ".join([tag_name + ": " + str(tag_total) for tag_name, tag_total in totals])})') | |
print_tree(node, total_column_index, tags_column_index, indent + '\t') | |
@click.command() | |
@click.argument('filename') | |
@click.option('-c', '--columns', | |
default='date,start,end,duration,client,task,comment,tags', | |
help='specifies columns names (in accordance with their order in the file) for using in other params', | |
show_default=True) | |
@click.option('-g', '--grouping', | |
default='client,task,date,comment', | |
help='specifies column names for grouping and calculate total time', | |
show_default=True) | |
@click.option('-d', '--duration-column', | |
default='duration', | |
help='column name with duration time to calculate total', | |
show_default=True) | |
@click.option('-t', '--tags-column', | |
default='tags', | |
help='column name with tags to calculate totals by tags', | |
show_default=True) | |
def main(filename, columns, grouping, duration_column, tags_column): | |
columns = columns.split(',') | |
grouping = grouping.split(',') | |
with open(filename, newline='', encoding='utf-8') as cf: | |
cr = csv.reader(cf) | |
tree = make_tree((row for n, row in enumerate(cr) if n > 0), [columns.index(column_name) for column_name in grouping]) | |
print_tree(tree, columns.index(duration_column), columns.index(tags_column)) | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment