2022-11-14 19:01:32 +00:00
import logging
2022-11-15 15:52:19 +00:00
from solo_turnier import html_parser
2022-11-15 17:11:40 +00:00
2022-11-14 19:01:32 +00:00
class ResultRow :
2022-11-15 15:50:08 +00:00
def __init__ ( self , firstName , lastName , club , id , group , class_ , dance , place , placeTo , competitionGroup , competitionClass ) :
2022-11-14 19:01:32 +00:00
self . firstName = firstName
self . lastName = lastName
self . name = f ' { firstName } { lastName } '
self . club = club
self . id = id
self . group = group
self . class_ = class_
self . dance = dance
self . place = place
self . placeTo = placeTo
2022-11-15 15:50:08 +00:00
self . competitionGroup = competitionGroup
self . competitionClass = competitionClass
2022-11-16 09:22:09 +00:00
def __str__ ( self ) :
return f ' { self . name } ( { self . id } , { self . club } ) are in { self . group } { self . class_ } and danced the { self . dance } in { self . competitionGroup } { self . competitionClass } getting place { self . place } - { self . placeTo } '
2022-11-14 19:01:32 +00:00
class ResultPerson :
2022-11-15 09:48:50 +00:00
def __init__ ( self , firstName , lastName , club , id = None , group = None ) :
2022-11-14 19:01:32 +00:00
self . firstName = firstName
self . lastName = lastName
self . name = f ' { firstName } { lastName } '
self . club = club
self . id = id
2022-11-15 09:48:50 +00:00
self . group = group
2022-11-14 19:01:32 +00:00
@staticmethod
def extractFromResultRow ( row : ResultRow ) :
return ResultPerson (
firstName = row . firstName ,
lastName = row . lastName ,
club = row . club
)
2022-11-15 09:48:50 +00:00
def __eq__ ( self , o ) :
if not isinstance ( o , ResultPerson ) :
return False
return (
self . firstName == o . firstName and
self . lastName == o . lastName and
self . club == o . club and
self . id == o . id
)
def __repr__ ( self ) :
if self . id is None :
return f ' { self . name } ( { self . club } ) '
else :
return f ' { self . name } ( { self . club } ) [ { self . id } ] '
def __hash__ ( self ) :
text = str ( self )
return text . __hash__ ( )
2022-11-14 19:01:32 +00:00
class CompetitionResult :
2022-11-15 15:50:08 +00:00
def __init__ ( self , dance , group , class_ , place , placeTo , id , competitionGroup , competitionClass ) :
2022-11-14 19:01:32 +00:00
self . dance = dance
2022-11-15 09:48:50 +00:00
self . group = group
2022-11-14 19:01:32 +00:00
self . class_ = class_
self . place = place
self . placeTo = placeTo
self . id = int ( id )
2022-11-15 15:50:08 +00:00
self . competitionGroup = competitionGroup
self . competitionClass = competitionClass
2022-11-15 13:38:46 +00:00
self . finalist = None
2022-11-14 19:01:32 +00:00
@staticmethod
def extractFromResultRow ( row : ResultRow ) :
return CompetitionResult (
dance = row . dance ,
2022-11-15 09:48:50 +00:00
group = row . group ,
2022-11-14 19:01:32 +00:00
class_ = row . class_ ,
place = row . place , placeTo = row . placeTo ,
2022-11-15 15:50:08 +00:00
id = row . id ,
competitionGroup = row . competitionGroup ,
competitionClass = row . competitionClass
2022-11-14 19:01:32 +00:00
)
2022-11-15 09:48:50 +00:00
def __repr__ ( self ) :
if self . place == self . placeTo :
result = f ' { self . place } . '
else :
result = f ' { self . place } .- { self . placeTo } . '
2022-11-15 13:38:46 +00:00
if self . finalist == True :
finalist = ' [F] '
else :
finalist = ' '
return f ' Result[ { self . id } ]( { self . group } { self . class_ } { self . dance } as { result } { finalist } ) '
2022-11-15 09:48:50 +00:00
def __eq__ ( self , o ) :
if not isinstance ( o , CompetitionResult ) :
return False
return (
self . dance == o . dance and
2022-11-15 15:50:08 +00:00
self . competitionClass == o . competitionClass and
self . competitionGroup == o . competitionGroup and
2022-11-15 09:48:50 +00:00
self . place == o . place and self . placeTo == o . placeTo and
self . id == o . id
)
2022-11-14 19:01:32 +00:00
class CSVExtractor :
def __init__ ( self ) :
self . l = logging . getLogger ( ' solo_turnier.worker ' )
def mapCSVImport ( self , imported ) - > list [ ResultRow ] :
ret = [ ]
def __processRow ( row ) :
result = ResultRow (
2022-11-15 15:50:08 +00:00
competitionGroup = row [ 2 ] ,
competitionClass = row [ 3 ] ,
2022-11-14 19:01:32 +00:00
dance = row [ 4 ] ,
id = row [ 5 ] ,
firstName = row [ 6 ] , lastName = row [ 7 ] ,
club = row [ 10 ] ,
place = row [ 12 ] , placeTo = row [ 13 ] ,
group = row [ 15 ] , class_ = row [ 16 ]
)
ret . append ( result )
2022-11-16 09:22:09 +00:00
self . l . debug ( ' Found row in CSV: %s ' , result )
2022-11-14 19:01:32 +00:00
for row in imported [ ' data ' ] :
__processRow ( row )
return ret
2022-11-15 09:48:50 +00:00
class DataWorker :
def __init__ ( self ) :
self . l = logging . getLogger ( ' solo_turnier.worker ' )
def combineRowsByPerson ( self , rows : list [ ResultRow ] ) - > dict [ ResultPerson , list [ CompetitionResult ] ] :
ret = { }
for row in rows :
result = CompetitionResult . extractFromResultRow ( row )
if result . place == ' - ' or result . placeTo == ' - ' :
continue
person = ResultPerson . extractFromResultRow ( row )
if person not in ret :
ret [ person ] = [ ]
ret [ person ] . append ( result )
return ret
def checkUniqueIds ( self , data : dict [ ResultPerson , list [ CompetitionResult ] ] ) - > bool :
unique = True
for person in data :
ids = set ( [ c . id for c in data [ person ] ] )
if len ( ids ) == 1 :
person . id = list ( ids ) [ 0 ]
else :
unique = False
return unique
2022-11-15 12:00:17 +00:00
"""
Return a tuple
The first one is True , if all persons could be unambiguously identified a group
The second one is True if there was the need to override a group but it was possible to extract from other data
The second one can be seen as a warning
"""
def consolidateGroups ( self , data : dict [ ResultPerson , list [ CompetitionResult ] ] ) - > tuple [ bool , bool ] :
ambiguous = False
warnChange = False
unambiguousGroups = set ( [ ' Kin. ' , ' Jun. ' , ' Jug. ' ] )
combinations = set ( [ ' Kin./Jun. ' , ' Jun./Jug. ' ] )
for person in data :
groupsRaw = set ( [ c . group for c in data [ person ] ] )
unknown = groupsRaw . difference ( unambiguousGroups ) . difference ( combinations )
if len ( unknown ) > 0 :
raise Exception ( f ' There were unknown groups found for { person } : { unknown } ' )
numUnambiguousGroups = len ( groupsRaw . intersection ( unambiguousGroups ) )
if numUnambiguousGroups == 0 :
if len ( groupsRaw ) == 2 :
warnChange = True
person . group = ' Jun. '
else :
ambiguous = True
if len ( groupsRaw ) == 1 :
person . group = list ( groupsRaw ) [ 0 ]
elif numUnambiguousGroups == 1 :
if len ( groupsRaw . intersection ( combinations ) ) > 0 :
warnChange = True
person . group = list ( groupsRaw . intersection ( unambiguousGroups ) ) [ 0 ]
else :
raise Exception ( f ' { person } cannot have different groups. ' )
return ( not ambiguous , warnChange )
2022-11-15 15:52:19 +00:00
def _createHtmlLUT ( self , htmlImports : list [ html_parser . HtmlImport ] ) :
ret = { }
parser = html_parser . HtmlParser ( )
for imp in htmlImports :
parsed = parser . guessDataFromHtmlTitle ( imp . title )
key = ( parsed [ ' group ' ] , parsed [ ' class_ ' ] , parsed [ ' dance ' ] )
ret [ key ] = imp
2022-11-16 09:22:09 +00:00
self . l . debug ( ' LUT[ %s ] = %s ' , key , imp )
self . l . debug ( ' LUT completed ' )
2022-11-15 15:52:19 +00:00
return ret
2022-11-15 17:11:40 +00:00
def mergeHtmlData ( self , data : dict [ ResultPerson , list [ CompetitionResult ] ] , htmlImports : list [ html_parser . HtmlImport ] ) :
lut = self . _createHtmlLUT ( htmlImports )
for person in data :
for competition in data [ person ] :
key = ( competition . competitionGroup , competition . competitionClass , competition . dance )
htmlImport = lut [ key ]
participant = htmlImport . participants [ str ( competition . id ) ]
if participant . name != person . name :
self . l . error ( f ' Names for { person } and participant in HTML import ( { participant } ) do not match. Please check carefully. ' )
competition . finalist = participant . finalist
2022-11-15 17:39:41 +00:00
def getAllDancesInCompetitions ( self , data : dict [ ResultPerson , list [ CompetitionResult ] ] ) - > list [ str ] :
allDances = [
' Samba ' , ' Cha Cha ' , ' Rumba ' , ' Paso Doble ' , ' Jive ' ,
' Langs. Walzer ' , ' Tango ' , ' Wiener Walzer ' , ' Slowfox ' , ' Quickstep '
]
dancesPresent = { d : False for d in allDances }
for person in data :
for competition in data [ person ] :
dancesPresent [ competition . dance ] = True
return [ d for d in allDances if dancesPresent [ d ] ]
2022-11-15 18:03:24 +00:00
def collectPersonsInGroups ( self , data : dict [ ResultPerson , list [ CompetitionResult ] ] ) - > list [ tuple [ str , list [ ResultPerson ] ] ] :
groups = {
' Kin. ' : [ p for p in data . keys ( ) if p . group == ' Kin. ' ] ,
' Jun. ' : [ p for p in data . keys ( ) if p . group == ' Jun. ' ] ,
' Jug. ' : [ p for p in data . keys ( ) if p . group == ' Jug. ' ] ,
}
found = groups [ ' Kin. ' ] + groups [ ' Jun. ' ] + groups [ ' Jug. ' ]
groups [ ' Sonst ' ] = [ p for p in data . keys ( ) if p not in found ]
return groups
2022-11-15 18:36:04 +00:00
def sortPersonsInGroup ( self , persons : list [ ResultPerson ] ) - > list [ ResultPerson ] :
ids = [ p . id for p in persons ]
def decorateByName ( p : ResultPerson ) :
return ( f ' { p . name } ( { p . club } ) ' , p )
def decorateById ( p : ResultPerson ) :
return ( p . id , p )
if any ( [ id == None for id in ids ] ) :
# We need to sort by name
decorated = [ decorateByName ( p ) for p in persons ]
showIds = False
else :
decorated = [ decorateById ( p ) for p in persons ]
showIds = True
decorated . sort ( )
return ( [ d [ 1 ] for d in decorated ] , showIds )
2022-11-15 18:37:08 +00:00
def mapPersonResultsToDanceList ( self , results : list [ CompetitionResult ] , dances : list [ str ] ) - > list [ CompetitionResult | None ] :
ret = [ ]
for dance in dances :
competitions = [ c for c in results if c . dance == dance ]
if len ( competitions ) == 0 :
ret . append ( None )
elif len ( competitions ) > 1 :
raise Exception ( f ' Multiple competitions with the same dance " { dance } " found. ' )
else :
ret . append ( competitions [ 0 ] )
return ret