Compare commits

..

3 Commits

Author SHA1 Message Date
88ba0c9da9 Kommandoverktøy som kan bruke alle otime funksjoner 2022-05-29 22:45:13 +02:00
a037abe820 Event metoder bruker filobjekt istedet for paths nå 2022-05-29 22:43:08 +02:00
e11e25ea81 La til import og eksport av json .otime filer
Alle import metoder og funksjoner tar nå filobjekter istedet for paths.
Runner objektet bruker nå kwargs.
2022-05-29 22:36:50 +02:00
3 changed files with 407 additions and 43 deletions

30
cli.py
View File

@ -14,6 +14,8 @@ def print_runners(Runners):
table.add_column("club", style="magenta") table.add_column("club", style="magenta")
table.add_column("card", style="red") table.add_column("card", style="red")
table.add_column("class", justify="right", style="green") table.add_column("class", justify="right", style="green")
table.add_column("start_time", justify="right", style="green")
table.add_column("fork", justify="right", style="green")
table.add_column("Status", justify="right", style="blue") table.add_column("Status", justify="right", style="blue")
for i in Runners: for i in Runners:
@ -21,7 +23,7 @@ def print_runners(Runners):
o_class = i.o_class.name o_class = i.o_class.name
except: except:
o_class = '' o_class = ''
table.add_row(i.fullname(), i.club ,str(i.card), o_class, i.status()) table.add_row(i.fullname(), i.club ,str(i.card), o_class, i.start_time, str(i.fork), i.status())
console = Console() console = Console()
console.print(table) console.print(table)
@ -147,16 +149,16 @@ def main():
args = parser.parse_args() args = parser.parse_args()
if args.command == 'show_runners': if args.command == 'show_runners':
event = otime.Event(0, 'NoName') event = otime.Event(0, 'NoName')
event.import_ttime_cnf(args.ttcnf) event.import_ttime_cnf(open(args.ttcnf, encoding='latin-1'))
event.import_ttime_db(args.ttdb) event.import_ttime_db(open(args.ttdb, encoding='latin-1'))
event.import_mtr_file(args.mtr) event.import_mtr_file(open(args.mtr, encoding='latin-1'))
event.match_runners_cards() event.match_runners_cards()
print_runners(event.runners) print_runners(event.runners)
elif args.command == 'show_runner': elif args.command == 'show_runner':
event = otime.Event(0, 'NoName') event = otime.Event(0, 'NoName')
event.import_ttime_cnf(args.ttcnf) event.import_ttime_cnf(open(args.ttcnf, encoding='latin-1'))
event.import_ttime_db(args.ttdb) event.import_ttime_db(open(args.ttdb, encoding='latin-1'))
event.import_mtr_file(args.mtr) event.import_mtr_file(open(args.mtr, encoding='latin-1'))
event.match_runners_cards() event.match_runners_cards()
for n in event.runners: for n in event.runners:
if args.runner == n.fullname(): if args.runner == n.fullname():
@ -168,9 +170,9 @@ def main():
elif args.command == 'show_result': elif args.command == 'show_result':
event = otime.Event(0, 'NoName') event = otime.Event(0, 'NoName')
event.import_ttime_cnf(args.ttcnf) event.import_ttime_cnf(open(args.ttcnf, encoding='latin-1'))
event.import_ttime_db(args.ttdb) event.import_ttime_db(open(args.ttdb, encoding='latin-1'))
event.import_mtr_file(args.mtr) event.import_mtr_file(open(args.mtr, encoding='latin-1'))
event.match_runners_cards() event.match_runners_cards()
for n in event.o_classes: for n in event.o_classes:
if args.o_class_str == n.name: if args.o_class_str == n.name:
@ -185,14 +187,14 @@ def main():
print_class_result(event.runners, o_class) print_class_result(event.runners, o_class)
elif args.command == 'show_classes': elif args.command == 'show_classes':
event = otime.Event(0, 'NoName') event = otime.Event(0, 'NoName')
event.import_ttime_cnf(args.ttcnf) event.import_ttime_cnf(open(args.ttcnf, encoding='latin-1'))
print_o_classes(event.o_classes) print_o_classes(event.o_classes)
elif args.command == 'create_xml': elif args.command == 'create_xml':
event = otime.Event(0, 'NoName') event = otime.Event(0, 'NoName')
event.import_ttime_cnf(args.ttcnf) event.import_ttime_cnf(open(args.ttcnf, encoding='latin-1'))
event.import_ttime_db(args.ttdb) event.import_ttime_db(open(args.ttdb, encoding='latin-1'))
event.import_mtr_file(args.mtr) event.import_mtr_file(open(args.mtr, encoding='latin-1'))
event.match_runners_cards() event.match_runners_cards()
event.get_xml_res().write(args.file) event.get_xml_res().write(args.file)

231
otime.py
View File

@ -1,21 +1,37 @@
import copy
import datetime import datetime
import csv import csv
import re import re
import json
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from fpdf import FPDF from fpdf import FPDF
# The event object stores all the event data. # 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: class Event:
def __init__(self, eventid, name, **kwargs): def __init__(self, eventid, name, **kwargs):
self.id = eventid self.id = eventid
self.name = name self.name = name
self.courses = []
self.o_classes = [] try:
self.runners = [] self.courses = kwargs['courses']
self.card_dumps = [] 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): def add_course(self, *args):
for n in args: for n in args:
@ -29,12 +45,16 @@ class Event:
for n in args: for n in args:
self.runners.append(n) 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): def import_ttime_cnf(self, ttime_file):
self.add_course(*courses_from_ttime_conf(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)) self.add_o_class(*classes_from_ttime_conf(ttime_file, self.courses))
def import_ttime_db(self, ttime_file): 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 = [] runnerarray = []
for row in csvreader: for row in csvreader:
if len(row) == 0 or row[1] == '': if len(row) == 0 or row[1] == '':
@ -46,10 +66,25 @@ class Event:
self.card_dumps = CardDump.list_from_mtr_f(mtr_file) self.card_dumps = CardDump.list_from_mtr_f(mtr_file)
def match_runners_cards(self): def match_runners_cards(self):
for n in self.runners: for r in self.runners:
for i in self.card_dumps: for d in self.card_dumps:
if n.card == i.card: if r.card == d.card:
n.card_r = i 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): def get_xml_res(self):
root = ET.Element('ResultList') root = ET.Element('ResultList')
@ -135,6 +170,54 @@ class Event:
ET.indent(root, space=' ', level=0) ET.indent(root, space=' ', level=0)
return tree 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): def create_start_list_pdf(self, file_name):
pdf = FPDF() pdf = FPDF()
pdf.add_page() pdf.add_page()
@ -155,16 +238,52 @@ class Event:
# The runner object stores all the data specific to a runner. # The runner object stores all the data specific to a runner.
class 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.id = runner_id
self.first = first self.first = first
self.last = last self.last = last
self.club = club try:
self.club_id = club_id self.club = kwargs['club']
self.country = country except KeyError:
self.card = card self.club = None
self.o_class = o_class
self.start_time = start_time 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): def from_string(tt_line, o_classes):
#https://web.archive.org/web/20191229124046/http://wiki.ttime.no/index.php/Developer #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] start_time = options[options.index('U')+1]
except: except:
start_time = None 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): def fullname(self):
return '{} {}'.format(self.first, self.last) return '{} {}'.format(self.first, self.last)
@ -244,7 +365,21 @@ class Runner:
index = self.card_r.controls.index(control) index = self.card_r.controls.index(control)
split = self.card_r.splits[index] split = self.card_r.splits[index]
splits_cpy.remove(split) 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: class CardDump:
def __init__(self, card, controls, splits, read_time, s_time, f_time): 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)) return(CardDump(card, controls, splits, read_time, s_time, f_time))
def list_from_mtr_f(mtr_f): def list_from_mtr_f(mtr_f):
csvreader = csv.reader(open(mtr_f)) csvreader = csv.reader(mtr_f)
rows = [] rows = []
cards = [] cards = []
@ -333,7 +468,7 @@ class CardDump:
tl[1][2] = float(tl[1][2]) tl[1][2] = float(tl[1][2])
tl[1] = list(map(int, tl[1])) 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]) 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]) s_time = read_time - datetime.timedelta(seconds = splits[-1])
f_time = read_time - (datetime.timedelta(seconds = splits[-1]) + datetime.timedelta(seconds = splits[-2])) f_time = read_time - (datetime.timedelta(seconds = splits[-1]) + datetime.timedelta(seconds = splits[-2]))
else: else:
@ -342,26 +477,61 @@ class CardDump:
cards.append(CardDump(int(row[6]), controls, splits, read_time, s_time, f_time)) cards.append(CardDump(int(row[6]), controls, splits, read_time, s_time, f_time))
return cards 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 # Stored in Event.courses
class Course: class Course:
def __init__(self, name, codes): def __init__(self, name, codes, **kwargs):
self.name = name self.name = name
self.codes = codes self.codes = codes
try:
forked = kwargs['forked']
except KeyError:
forked = False
try:
variations = kwargs['variations']
except KeyError:
variations = None
def __repr__(self): def __repr__(self):
return f'name({self.name})' return f'name({self.name})'
def asdict(self):
return {
'name': self.name,
'codes': self.codes
}
# Stored in Event.o_classes # Stored in Event.o_classes
class OClass: class OClass:
def __init__(self, name, course): def __init__(self, name, course_str, course):
self.name = name self.name = name
self.course_str = course_str
self.course = course self.course = course
def __repr__(self): def __repr__(self):
return f'name({self.name})' return f'name({self.name})'
def asdict(self):
return {
'name': self.name,
'course_str': self.course_str
}
# TODO: Take string instead of file. # TODO: Take string instead of file.
def courses_from_ttime_conf(ttime_file): def courses_from_ttime_conf(ttime_file):
courses = [] courses = []
conf = open(ttime_file, 'r', encoding='latin_1').readlines() conf = ttime_file.readlines()
for line in conf: for line in conf:
if '-codes' in line: if '-codes' in line:
code_list = re.search(r'(?<=\")(.*?)(?=\")', line).group().split(';') 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): def classes_from_ttime_conf(ttime_file, courses):
o_classes = [] o_classes = []
conf = open(ttime_file, 'r', encoding='latin_1').readlines() conf = ttime_file.readlines()
for line in conf: for line in conf:
if '-courses' in line: if '-courses' in line:
raw_courselist = re.search(r'(?<=\")(.*?)(?=\")', line).group().split(';') 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: for n in raw_courselist:
split = n.split(',') split = n.split(',')
for i in split: for i in split:
o_classes.append(OClass(i,courses[loops])) o_classes.append(OClass(i, courses[loops].name, courses[loops]))
loops += 1 loops += 1
return o_classes return o_classes
@ -406,6 +576,7 @@ def runners_from_xml_entries(xml_file, o_classes=[]):
card = int(person_root[3].text) card = int(person_root[3].text)
except: except:
card = 0 card = 0
runner_o_class = None
try: try:
xml_class_str = person_root[4][1].text xml_class_str = person_root[4][1].text
except: 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 # Gjør sånn at den lager nye o klasser om den ikke finnes fra før
start_time = None start_time = None
runnerarray.append(Runner(rid, first, last, club, club_id, country, card, runner_o_class, start_time)) runnerarray.append(Runner(rid, first, last, club=club, club_id=club_id,
print(rid, first, last, club_id, club, card, xml_class_str) 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 return runnerarray

189
wizard.py Normal file
View File

@ -0,0 +1,189 @@
import otime
import cli
import sys
from rich import inspect
def main():
global event
while True:
print(''' 1. import
2. export
3. edit
4. view tables
5. exit''')
try:
opt = int(input('Choose an option (1-4): '))
except ValueError:
print('Not a valid option!')
continue
match opt:
case 1:
import_menu()
case 2:
print('export')
case 3:
print('edit')
case 4:
table_menu()
case 5:
print('Goodbye!')
sys.exit()
def import_menu():
global event
while True:
try:
print(''' 1. import otime file
2. Import xml EntryList
3. Import mtr file (Latin-1)
4. Import mtr file (utf-8)
5. Import ttime db (Latin-1)
6. Import ttime db (utf-8)
7. Import ttime config (Latin-1)
8. Import ttime config (utf-8)
9. Match runners with cards and classes, and o_classes with courses
10. Back''')
try:
opt = int(input('Choose an option (1-10): '))
except ValueError:
print('Not a valid option!')
continue
match opt:
case 1:
n = len(event.runners)
filename = input('File: ')
f = open(filename, 'r')
event = otime.Event.from_json(f)
nn = len(event.runners)
print('Added '+ str(nn-n) +' runners')
case 2:
n = len(event.runners)
filename = input('File: ')
f = open(filename, 'r')
event.import_xml_entries(f)
nn = len(event.runners)
print('Added '+ str(nn-n) +' runners')
case 3:
n = len(event.card_dumps)
filename = input('File: ')
f = open(filename, 'r', encoding='latin_1')
event.import_mtr_file(f)
nn = len(event.card_dumps)
print('Added '+ str(nn-n) +' cards')
case 4:
n = len(event.card_dumps)
filename = input('File: ')
f = open(filename, 'r')
event.import_mtr_file(f)
nn = len(event.card_dumps)
print('Added '+ str(nn-n) +' cards')
case 5:
n = len(event.runners)
filename = input('File: ')
f = open(filename, 'r', encoding='latin_1')
event.import_ttime_db(f)
nn = len(event.runners)
print('Added '+ str(nn-n) +' runners')
case 6:
n = len(event.runners)
filename = input('File: ')
f = open(filename, 'r')
event.import_ttime_db(f)
nn = len(event.runners)
print('Added '+ str(nn-n) +' runners')
case 7:
n = len(event.courses)
k = len(event.o_classes)
filename = input('File: ')
f = open(filename, 'r', encoding='latin-1')
event.import_ttime_cnf(f)
nn = len(event.courses)
kk = len(event.o_classes)
print('Added '+ str(nn-n) +' courses and '+ str(kk-k) +' classes')
case 8:
n = len(event.courses)
k = len(event.o_classes)
filename = input('File: ')
f = open(filename, 'r')
event.import_ttime_cnf(f)
nn = len(event.courses)
kk = len(event.o_classes)
print('Added '+ str(nn-n) +' courses and '+ str(kk-k) +' classes')
case 9:
event.match_all()
case 10:
break
except FileNotFoundError:
print('No such file or directory!')
except IsADirectoryError:
print('This is a directory, not a file!')
def export_menu():
global event
while True:
try:
print(''' 1. export otime file
2. Back''')
try:
opt = int(input('Choose an option (1-2): '))
except ValueError:
print('Not a valid option!')
continue
match opt:
case 1:
filename = input('File: ')
f = open(filename, 'w')
f.write(event.create_json_file)
case 2:
break
except FileNotFoundError:
print('No such file or directory!')
except IsADirectoryError:
print('This is a directory, not a file!')
def table_menu():
global event
while True:
print(''' 1. View runners
2. View courses and classes
3. Show result
4. Show splits
5. back''')
try:
opt = int(input('Choose an option (1-6): '))
except ValueError:
print('Not a valid option!')
continue
match opt:
case 1:
cli.print_runners(event.runners)
case 2:
cli.print_o_classes(event.o_classes)
case 3:
for o_class in event.o_classes:
cli.print_class_result(event.runners, o_class)
case 4:
for o_class in event.o_classes:
cli.print_class_splits(event.runners, o_class)
case 5:
break
if __name__ == "__main__":
global event
event = otime.Event('0','NoName')
main()