diff --git a/otime.py b/otime.py index 0b85f9c..86fc326 100644 --- a/otime.py +++ b/otime.py @@ -1,21 +1,37 @@ -import copy import datetime import csv import re +import json import xml.etree.ElementTree as ET from fpdf import FPDF # The event object stores all the event data. -# A .otime file is just a pickle dump of an event object. +# A .otime file is more or less just a json dump of the Event object. class Event: def __init__(self, eventid, name, **kwargs): self.id = eventid self.name = name - self.courses = [] - self.o_classes = [] - self.runners = [] - self.card_dumps = [] + + try: + self.courses = kwargs['courses'] + except KeyError: + self.courses = [] + + try: + self.o_classes = kwargs['o_classes'] + except KeyError: + self.o_classes = [] + + try: + self.runners = kwargs['runners'] + except KeyError: + self.runners = [] + + try: + self.card_dumps = kwargs['card_dumps'] + except KeyError: + self.card_dumps = [] def add_course(self, *args): for n in args: @@ -29,12 +45,16 @@ class Event: for n in args: self.runners.append(n) + def import_xml_entries(self, xml_file): + self.add_runners(*runners_from_xml_entries(xml_file, self.o_classes)) + def import_ttime_cnf(self, ttime_file): self.add_course(*courses_from_ttime_conf(ttime_file)) + ttime_file.seek(0) self.add_o_class(*classes_from_ttime_conf(ttime_file, self.courses)) def import_ttime_db(self, ttime_file): - csvreader = csv.reader(open(ttime_file, 'r', encoding='latin_1'), delimiter=';',) + csvreader = csv.reader(ttime_file, delimiter=';',) runnerarray = [] for row in csvreader: if len(row) == 0 or row[1] == '': @@ -46,10 +66,25 @@ class Event: self.card_dumps = CardDump.list_from_mtr_f(mtr_file) def match_runners_cards(self): - for n in self.runners: - for i in self.card_dumps: - if n.card == i.card: - n.card_r = i + for r in self.runners: + for d in self.card_dumps: + if r.card == d.card: + r.card_r = d + def match_runners_o_classes(self): + for r in self.runners: + for c in self.o_classes: + if r.o_class_str == c.name: + r.o_class = c + + def match_o_classes_courses(self): + for oc in self.o_classes: + for c in self.courses: + if oc.course_str == c.name: + oc.course = c + def match_all(self): + self.match_runners_cards() + self.match_runners_o_classes() + self.match_o_classes_courses() def get_xml_res(self): root = ET.Element('ResultList') @@ -135,6 +170,54 @@ class Event: ET.indent(root, space=' ', level=0) return tree + def create_json_file(self): + rdicts = [] + for runner in self.runners: + rdicts.append(runner.asdict()) + + cdicts = [] + for course in self.courses: + cdicts.append(course.asdict()) + + ocdicts = [] + for o_class in self.o_classes: + ocdicts.append(o_class.asdict()) + + ddicts = [] + for dump in self.card_dumps: + ddicts.append(dump.asdict()) + + json_data = { + 'id': self.id, + 'name': self.name, + 'runners': rdicts, + 'courses': cdicts, + 'o_classes': ocdicts, + 'card_dumps': ddicts + } + return json.dumps(json_data, sort_keys=True, indent=4) + + # Get event object from .otime json file + def from_json(f): + data = json.load(f) + runners = [] + for r in data['runners']: + runners.append(Runner(r['id'], r['first'], r['last'], club_id=r['club_id'], club=r['club'], country=r['country'], card=r['card'], o_class_str=r['o_class_str'], fork=r['fork'],start_time=r['start_time'])) + + courses = [] + for c in data['courses']: + courses.append(Course(c['name'], c['codes'])) + + o_classes = [] + for c in data['o_classes']: + o_classes.append(OClass(c['name'], c['course_str'], None)) + + card_dumps = [] + for d in data['card_dumps']: + card_dumps.append(CardDump(d['card'], d['controls'], d['splits'], datetime.datetime.fromisoformat(d['read_time']), datetime.datetime.fromisoformat(d['s_time']), datetime.datetime.fromisoformat(d['f_time']))) + + return Event(data['id'], data['name'], runners=runners, courses=courses, o_classes=o_classes, card_dumps=card_dumps) + def create_start_list_pdf(self, file_name): pdf = FPDF() pdf.add_page() @@ -155,16 +238,52 @@ class Event: # The runner object stores all the data specific to a runner. class Runner: - def __init__(self, runner_id, first, last, club, club_id, country, card, o_class, start_time): + def __init__(self, runner_id, first, last, **kwargs): self.id = runner_id self.first = first self.last = last - self.club = club - self.club_id = club_id - self.country = country - self.card = card - self.o_class = o_class - self.start_time = start_time + try: + self.club = kwargs['club'] + except KeyError: + self.club = None + + try: + self.club_id = kwargs['club_id'] + except KeyError: + self.club_id = None + + try: + self.country = kwargs['country'] + except KeyError: + self.country = None + + try: + self.card = kwargs['card'] + except KeyError: + self.card = 0 + + try: + self.o_class_str = kwargs['o_class_str'] + except KeyError: + self.o_class = None + + try: + self.o_class = kwargs['o_class'] + except KeyError: + self.o_class = None + + try: + self.fork = kwargs['fork'] + except KeyError: + self.fork = 0 + + try: + self.start_time = kwargs['start_time'] + except KeyError: + self.start_time = None + + #self.o_class = o_class + #self.start_time = start_time def from_string(tt_line, o_classes): #https://web.archive.org/web/20191229124046/http://wiki.ttime.no/index.php/Developer @@ -208,7 +327,9 @@ class Runner: start_time = options[options.index('U')+1] except: start_time = None - return Runner(eventorid, first, last, club, club_id, country, card, runner_o_class, start_time) + return Runner(eventorid, first, last, club=club, club_id=club_id, + country=country, card=card, o_class_str=raw_class_str, + o_class=runner_o_class, start_time=start_time) def fullname(self): return '{} {}'.format(self.first, self.last) @@ -244,7 +365,21 @@ class Runner: index = self.card_r.controls.index(control) split = self.card_r.splits[index] splits_cpy.remove(split) - return splits_cpy + return splits_cpy # list + + def asdict(self): + return { + 'id': self.id, + 'first': self.first, + 'last': self.last, + 'club_id': self.club_id, + 'club': self.club_id, + 'country': self.country, + 'card': self.card, + 'o_class_str': self.o_class_str, + 'fork' : self.fork, + 'start_time': self.start_time + } class CardDump: def __init__(self, card, controls, splits, read_time, s_time, f_time): @@ -297,7 +432,7 @@ class CardDump: return(CardDump(card, controls, splits, read_time, s_time, f_time)) def list_from_mtr_f(mtr_f): - csvreader = csv.reader(open(mtr_f)) + csvreader = csv.reader(mtr_f) rows = [] cards = [] @@ -333,7 +468,7 @@ class CardDump: tl[1][2] = float(tl[1][2]) tl[1] = list(map(int, tl[1])) read_time = datetime.datetime(tl[0][2], tl[0][1], tl[0][0], tl[1][0], tl[1][1], tl[1][2]) - if len(controls) > 2: + if len(controls) > 2 and len(splits) > 2: s_time = read_time - datetime.timedelta(seconds = splits[-1]) f_time = read_time - (datetime.timedelta(seconds = splits[-1]) + datetime.timedelta(seconds = splits[-2])) else: @@ -342,26 +477,61 @@ class CardDump: cards.append(CardDump(int(row[6]), controls, splits, read_time, s_time, f_time)) return cards + def asdict(self): + return { + 'card': self.card, + 'controls': self.controls, + 'splits': self.splits, + 'read_time': self.read_time.isoformat(), + 's_time': self.s_time.isoformat(), + 'f_time': self.f_time.isoformat() + } + # Stored in Event.courses class Course: - def __init__(self, name, codes): + def __init__(self, name, codes, **kwargs): self.name = name self.codes = codes + + try: + forked = kwargs['forked'] + except KeyError: + forked = False + + try: + variations = kwargs['variations'] + except KeyError: + variations = None + def __repr__(self): return f'name({self.name})' + def asdict(self): + return { + 'name': self.name, + 'codes': self.codes + } + # Stored in Event.o_classes class OClass: - def __init__(self, name, course): + def __init__(self, name, course_str, course): self.name = name + self.course_str = course_str self.course = course + def __repr__(self): return f'name({self.name})' + def asdict(self): + return { + 'name': self.name, + 'course_str': self.course_str + } + # TODO: Take string instead of file. def courses_from_ttime_conf(ttime_file): courses = [] - conf = open(ttime_file, 'r', encoding='latin_1').readlines() + conf = ttime_file.readlines() for line in conf: if '-codes' in line: code_list = re.search(r'(?<=\")(.*?)(?=\")', line).group().split(';') @@ -375,7 +545,7 @@ def courses_from_ttime_conf(ttime_file): def classes_from_ttime_conf(ttime_file, courses): o_classes = [] - conf = open(ttime_file, 'r', encoding='latin_1').readlines() + conf = ttime_file.readlines() for line in conf: if '-courses' in line: raw_courselist = re.search(r'(?<=\")(.*?)(?=\")', line).group().split(';') @@ -383,7 +553,7 @@ def classes_from_ttime_conf(ttime_file, courses): for n in raw_courselist: split = n.split(',') for i in split: - o_classes.append(OClass(i,courses[loops])) + o_classes.append(OClass(i, courses[loops].name, courses[loops])) loops += 1 return o_classes @@ -406,6 +576,7 @@ def runners_from_xml_entries(xml_file, o_classes=[]): card = int(person_root[3].text) except: card = 0 + runner_o_class = None try: xml_class_str = person_root[4][1].text except: @@ -419,8 +590,10 @@ def runners_from_xml_entries(xml_file, o_classes=[]): # Gjør sånn at den lager nye o klasser om den ikke finnes fra før start_time = None - runnerarray.append(Runner(rid, first, last, club, club_id, country, card, runner_o_class, start_time)) - print(rid, first, last, club_id, club, card, xml_class_str) + runnerarray.append(Runner(rid, first, last, club=club, club_id=club_id, + country=country,card=card, o_class_str=xml_class_str, + o_class=runner_o_class, start_time=start_time)) + #print(rid, first, last, club_id, club, card, xml_class_str) return runnerarray