Initial commit
This commit is contained in:
commit
c10f5a8774
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
__pycache__/
|
11
auswertung.code-workspace
Normal file
11
auswertung.code-workspace
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../../../../nextcloud/Documents/Projekte/SLT/Auswertungsskript Solo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
20
src/main.py
Normal file
20
src/main.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import solo_turnier
|
||||||
|
import logging
|
||||||
|
|
||||||
|
def __initLogging():
|
||||||
|
logging.basicConfig()
|
||||||
|
logging.root.setLevel(logging.NOTSET)
|
||||||
|
return logging.getLogger('solo_turnier')
|
||||||
|
|
||||||
|
def main():
|
||||||
|
l = __initLogging()
|
||||||
|
cli = solo_turnier.cli.Cli(l)
|
||||||
|
|
||||||
|
if cli.showGUI():
|
||||||
|
raise Exception('Not yet implemented')
|
||||||
|
else:
|
||||||
|
batchWorker = solo_turnier.batch.BatchWorker(cli)
|
||||||
|
batchWorker.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
5
src/solo_turnier/__init__.py
Normal file
5
src/solo_turnier/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
from . import cli
|
||||||
|
from . import reader
|
||||||
|
from . import participant
|
||||||
|
from . import batch
|
163
src/solo_turnier/batch.py
Normal file
163
src/solo_turnier/batch.py
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
import solo_turnier
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
class BatchWorker:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: solo_turnier.cli.Cli
|
||||||
|
):
|
||||||
|
self.l = logging.getLogger('solo_turnier.batch')
|
||||||
|
self.config = config
|
||||||
|
|
||||||
|
self.__groupMap = {
|
||||||
|
'Kin.': 0,
|
||||||
|
'Kin./Jun.': 1,
|
||||||
|
'Jun.': 10,
|
||||||
|
'Jun./Jug.': 11,
|
||||||
|
'Jug.': 20
|
||||||
|
}
|
||||||
|
self.__danceMap = {
|
||||||
|
'Samba': 1,
|
||||||
|
'Cha Cha': 2,
|
||||||
|
'Rumba': 3,
|
||||||
|
'Paso Doble': 4,
|
||||||
|
'Jive': 5,
|
||||||
|
'Langs. Walzer': 11,
|
||||||
|
'Tango': 12,
|
||||||
|
'Wiener Walzer': 13,
|
||||||
|
'Slowfox': 14,
|
||||||
|
'Quickstep': 15
|
||||||
|
}
|
||||||
|
|
||||||
|
def __extractDataFromFiles(self):
|
||||||
|
allResultName = os.path.join(self.config.importPath(), 'allresults.csv')
|
||||||
|
readerAllResults = solo_turnier.reader.AllResultReader(allResultName)
|
||||||
|
allResults = readerAllResults.readFile()
|
||||||
|
|
||||||
|
finals = []
|
||||||
|
|
||||||
|
# Do this in a loop
|
||||||
|
# finalName = os.path.join(self.config.importPath(), 'wert_er.txt')
|
||||||
|
# readerFinal = solo_turnier.reader.ERReader(finalName)
|
||||||
|
# result = readerFinal.readFile()
|
||||||
|
# finals.append(result)
|
||||||
|
|
||||||
|
return (allResults, finals)
|
||||||
|
|
||||||
|
def __convertFinalToTuple(self, result):
|
||||||
|
return (
|
||||||
|
result['gruppe'],
|
||||||
|
result['klasse'],
|
||||||
|
result['tanz'],
|
||||||
|
result['finalisten']
|
||||||
|
)
|
||||||
|
|
||||||
|
def __extractAllData(self, r):
|
||||||
|
return {
|
||||||
|
'date': r[1],
|
||||||
|
'group': r[2],
|
||||||
|
'class': r[3],
|
||||||
|
'dance': r[4],
|
||||||
|
'id': int(r[5]),
|
||||||
|
'firstName': r[6],
|
||||||
|
'lastName': r[7],
|
||||||
|
'club': r[10],
|
||||||
|
'ltv': r[11],
|
||||||
|
'place': r[12],
|
||||||
|
'placeTo': r[13],
|
||||||
|
'points': r[14],
|
||||||
|
'personGroup': r[15],
|
||||||
|
'personClass': r[16],
|
||||||
|
'remarks': r[17]
|
||||||
|
}
|
||||||
|
|
||||||
|
def __extractPersonData(self, r):
|
||||||
|
data = self.__extractAllData(r)
|
||||||
|
person = solo_turnier.participant.Person(
|
||||||
|
firstName=data['firstName'],
|
||||||
|
lastName=data['lastName'],
|
||||||
|
club=data['club'],
|
||||||
|
group=data['personGroup']
|
||||||
|
)
|
||||||
|
return person
|
||||||
|
|
||||||
|
def __extractPersons(self, allResults):
|
||||||
|
personRows = [self.__extractPersonData(r) for r in allResults['data']]
|
||||||
|
return list(set(personRows))
|
||||||
|
|
||||||
|
def __extractDanceResult(self, r):
|
||||||
|
data = self.__extractAllData(r)
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
'dance': data['dance'],
|
||||||
|
'class': data['personClass'],
|
||||||
|
'place': int(data['place']),
|
||||||
|
'placeTo': int(data['placeTo']),
|
||||||
|
'id': data['id']
|
||||||
|
}
|
||||||
|
except ValueError:
|
||||||
|
self.l.debug('Issue found with data %s.', data)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __extractAllResults(self, allResults, persons: list[solo_turnier.participant.Person]):
|
||||||
|
ret = {}
|
||||||
|
for row in allResults['data']:
|
||||||
|
danceResult = self.__extractDanceResult(row)
|
||||||
|
if danceResult is not None:
|
||||||
|
person = self.__extractPersonData(row)
|
||||||
|
if person not in ret:
|
||||||
|
ret[person] = []
|
||||||
|
|
||||||
|
ret[person].append(danceResult)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def __extractCompetitionEntries(self, r):
|
||||||
|
data = self.__extractAllData(r)
|
||||||
|
return (data['personGroup'], data['dance'])
|
||||||
|
|
||||||
|
def __extractCompetitions(self, allResults):
|
||||||
|
def __decorate(r):
|
||||||
|
return (self.__groupMap[r[0]], self.__danceMap[r[1]],r)
|
||||||
|
competitionsRows = [self.__extractCompetitionEntries(r) for r in allResults['data']]
|
||||||
|
# competitions = list(set([self.__extractDanceResult(r) for r in allResults['data']]))
|
||||||
|
competitions = [__decorate(r) for r in list(set(competitionsRows))]
|
||||||
|
competitions.sort()
|
||||||
|
competitions = [r[2] for r in competitions]
|
||||||
|
return competitions
|
||||||
|
|
||||||
|
def __extarctBasicData(self, allResults):
|
||||||
|
def __extractRow(r):
|
||||||
|
ret = {
|
||||||
|
'firstName': r[6],
|
||||||
|
'lastName': r[7],
|
||||||
|
'number': int(r[5]),
|
||||||
|
'club': r[10],
|
||||||
|
'place': int(r[12]),
|
||||||
|
'placeTo': int(r[13]),
|
||||||
|
'group': r[15],
|
||||||
|
'class': r[16]
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
|
||||||
|
return [__extractRow(r) for r in allResults['data'][0:2]]
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
allResults, finals = self.__extractDataFromFiles()
|
||||||
|
|
||||||
|
persons = self.__extractPersons(allResults)
|
||||||
|
self.l.debug('Found persons: %s', persons)
|
||||||
|
|
||||||
|
totalResults = self.__extractAllResults(allResults, persons)
|
||||||
|
self.l.debug('Total results: %s', totalResults)
|
||||||
|
|
||||||
|
competitions = self.__extractCompetitions(allResults)
|
||||||
|
self.l.debug('Competitions: %s', competitions)
|
||||||
|
|
||||||
|
# basicData = self.__extarctBasicData(allResults)
|
||||||
|
# self.l.debug('Basic extracted data: %s', basicData)
|
||||||
|
|
||||||
|
# finalTuples = [self.__convertFinalToTuple(r) for r in finals]
|
||||||
|
# self.l.debug('Mapped to tuples: %s', finalTuples)
|
||||||
|
|
34
src/solo_turnier/cli.py
Normal file
34
src/solo_turnier/cli.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
|
||||||
|
class Cli:
|
||||||
|
def __init__(self, l: logging.Logger):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--gui', help='Show the GUI', action='store_true')
|
||||||
|
|
||||||
|
parser.add_argument('-i', '--import-from', help='Set the path to load the TopTurnier exports from', nargs=1, default=['.'])
|
||||||
|
parser.add_argument('-o', '--output', help='Set the output path of the script', nargs=1)
|
||||||
|
|
||||||
|
parser.add_argument('-v', '--verbose', help='Increase verbosity', action='count', default=0)
|
||||||
|
self.__args = parser.parse_args()
|
||||||
|
|
||||||
|
map = {
|
||||||
|
0: logging.ERROR,
|
||||||
|
1: logging.WARN,
|
||||||
|
2: logging.INFO,
|
||||||
|
3: logging.DEBUG
|
||||||
|
}
|
||||||
|
logLevel = map.get(self.__args.verbose, logging.DEBUG)
|
||||||
|
l.setLevel(logLevel)
|
||||||
|
|
||||||
|
def showGUI(self):
|
||||||
|
return self.__args.gui
|
||||||
|
|
||||||
|
def importPath(self):
|
||||||
|
return self.__args.import_from[0]
|
||||||
|
|
||||||
|
def output(self):
|
||||||
|
return self.__args.output[0]
|
||||||
|
|
||||||
|
def getLogLevel(self):
|
||||||
|
return self.__args.verbose
|
31
src/solo_turnier/participant.py
Normal file
31
src/solo_turnier/participant.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
class Person:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
firstName: str,
|
||||||
|
lastName: str,
|
||||||
|
club: str,
|
||||||
|
group: str
|
||||||
|
):
|
||||||
|
self.firstName = firstName
|
||||||
|
self.lastName = lastName
|
||||||
|
self.club = club
|
||||||
|
self.group = group
|
||||||
|
|
||||||
|
def __eq__(self, o):
|
||||||
|
return (
|
||||||
|
self.firstName == o.firstName and
|
||||||
|
self.lastName == o.lastName and
|
||||||
|
self.club == o.club and
|
||||||
|
self.group == o.group
|
||||||
|
)
|
||||||
|
|
||||||
|
def getTuple(self):
|
||||||
|
return (self.firstName, self.lastName, self.club)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'{self.firstName} {self.lastName} ({self.club}, {self.group})'
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return self.firstName.__hash__() + self.lastName.__hash__() + self.club.__hash__()
|
||||||
|
|
81
src/solo_turnier/reader.py
Normal file
81
src/solo_turnier/reader.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
import solo_turnier
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
class AllResultReader:
|
||||||
|
def __init__(self, fileName: str):
|
||||||
|
self.fileName = fileName
|
||||||
|
|
||||||
|
def readFile(self):
|
||||||
|
with open(self.fileName, 'r') as fp:
|
||||||
|
dialect = csv.Sniffer().sniff(fp.read(1024))
|
||||||
|
fp.seek(0)
|
||||||
|
|
||||||
|
csvReader = csv.reader(fp, dialect)
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for row in csvReader:
|
||||||
|
rows.append(row)
|
||||||
|
|
||||||
|
ret = {
|
||||||
|
'header': rows[0],
|
||||||
|
'data': rows[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
logging.getLogger('solo_turnier.reader.all_results').debug('Imported results from allresults.csv file: %s', ret)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
class ERReader:
|
||||||
|
def __init__(self, fileName: str):
|
||||||
|
self.fileName = fileName
|
||||||
|
self.l = logging.getLogger('solo_turnier.reader.wert_er')
|
||||||
|
|
||||||
|
def __parseFileContent(self, lines):
|
||||||
|
gruppe = re.compile('Startgruppe:\W(.+)').search(lines[2]).group(1).strip()
|
||||||
|
klasse = re.compile('Startklasse:\W(.+)').search(lines[3]).group(1).strip()
|
||||||
|
tanz = re.compile('Turnierart:\W(.+)').search(lines[4]).group(1).strip()
|
||||||
|
|
||||||
|
restLines = lines[5:]
|
||||||
|
|
||||||
|
# Search for first line with the name of the dance
|
||||||
|
found = -1
|
||||||
|
for i in range(len(restLines)):
|
||||||
|
if restLines[i].startswith(tanz):
|
||||||
|
found = i
|
||||||
|
break
|
||||||
|
|
||||||
|
if found == -1:
|
||||||
|
raise Exception(f'Could not find the dance in the result file.')
|
||||||
|
|
||||||
|
# Extract the finalists
|
||||||
|
finalists = []
|
||||||
|
for i in range(found + 1, len(restLines)):
|
||||||
|
if restLines[i].startswith('TopTurnier'):
|
||||||
|
break
|
||||||
|
|
||||||
|
match = re.compile('[0-9]+').match(restLines[i].strip())
|
||||||
|
if match is None:
|
||||||
|
raise Exception('Could not parse starter number for end result table.')
|
||||||
|
else:
|
||||||
|
finalists.append(int(match.group(0)))
|
||||||
|
|
||||||
|
ret = {
|
||||||
|
'gruppe': gruppe,
|
||||||
|
'klasse': klasse,
|
||||||
|
'tanz': tanz,
|
||||||
|
'finalisten': finalists
|
||||||
|
}
|
||||||
|
self.l.debug('Extracted data for final: %s', ret)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def readFile(self):
|
||||||
|
with open(self.fileName, 'r') as fp:
|
||||||
|
lines = fp.readlines()
|
||||||
|
lines = [l.strip('\n') for l in lines]
|
||||||
|
lines = [l for l in lines if l != '']
|
||||||
|
self.l.debug('Read lines for final: %s', lines)
|
||||||
|
|
||||||
|
return self.__parseFileContent(lines)
|
Loading…
Reference in New Issue
Block a user