First running version

Not yet comparable with previous code base due to different outputs.
This commit is contained in:
Christian Wolf 2023-11-21 20:14:12 +01:00
parent 3ea5b74557
commit 43180c6e05
23 changed files with 339 additions and 263 deletions

View File

@ -26,6 +26,12 @@ class CombinedCompetitionClass:
else: else:
return f"{self.clsA}/{self.clsB}/{self.clsC}" return f"{self.clsA}/{self.clsB}/{self.clsC}"
def __eq__(self, other):
return type(self) == type(other) and self.__dict__ == other.__dict__
def __hash__(self):
return hash(("combinedClass", self.clsA, self.clsB, self.clsC))
Class_t = CompetitionClass | CombinedCompetitionClass Class_t = CompetitionClass | CombinedCompetitionClass

View File

@ -20,6 +20,12 @@ class CombinedGroup:
def __repr__(self): def __repr__(self):
return f"{self.clsA}/{self.clsB}" return f"{self.clsA}/{self.clsB}"
def __hash__(self):
return hash(("combinedGroup", self.clsA, self.clsB))
def __eq__(self, other):
return type(self) == type(other) and self.__hash__() == other.__hash__()
def getContainedGroups(self): def getContainedGroups(self):
return (self.clsA, self.clsB) return (self.clsA, self.clsB)

View File

@ -3,10 +3,11 @@ from bs4 import BeautifulSoup
import logging import logging
import re import re
from .types import HtmlPreviewParticipant, HtmlParticipant, HtmlResultTotalTable from .types import HtmlParticipant, HtmlResultTotalTable
from .types import HtmlPreviewImport as HtmlImport, HtmlResultImport from .types import HtmlResultImport
from .group import GroupParser from .group import GroupParser
from .competition_class import CompetitionClassParser from .competition_class import CompetitionClassParser
import solo_turnier
class IncompleteRoundException(Exception): class IncompleteRoundException(Exception):
@ -45,11 +46,11 @@ class HtmlParser:
return { return {
"dance": dance.strip(), "dance": dance.strip(),
"class_": str(self.classParser.parseClass(rawClass, True)), "class_": self.classParser.parseClass(rawClass, True),
"group": str(self.groupParser.parseGroup(rawGroup)), "group": self.groupParser.parseGroup(rawGroup),
} }
def parseResult(self): def parseResult(self) -> HtmlResultImport:
participants = {} participants = {}
def __parseRows(rows, finalist: bool): def __parseRows(rows, finalist: bool):
@ -111,6 +112,8 @@ class HtmlParser:
def parseIndividualResult(self, competitionGroup, competitionClass, dance): def parseIndividualResult(self, competitionGroup, competitionClass, dance):
participants = {} participants = {}
rePlaceParser = re.compile("([0-9]+)(?:-([0-9]+))?")
def __parseTable(table): def __parseTable(table):
rows = table.find_all("tr") rows = table.find_all("tr")
@ -148,7 +151,20 @@ class HtmlParser:
rawStr = tag.contents[0].strip() rawStr = tag.contents[0].strip()
if rawStr.endswith("-"): if rawStr.endswith("-"):
rawStr = rawStr[:-1] rawStr = rawStr[:-1]
return rawStr
matcher = rePlaceParser.fullmatch(rawStr)
if matcher is None:
self.l.error(
"Could not parse place string '%s' to get fixture.", rawStr
)
return None
place = int(matcher.group(1))
placeTo = matcher.group(2)
if placeTo is not None:
placeTo = int(placeTo)
return solo_turnier.types.Place(place, placeTo)
places = list(map(getSinglePlaceStr, placeTags)) places = list(map(getSinglePlaceStr, placeTags))
return places return places
@ -180,8 +196,13 @@ class HtmlParser:
cls = classes[idx] if classes is not None else None cls = classes[idx] if classes is not None else None
grp = groups[idx] if groups is not None else None grp = groups[idx] if groups is not None else None
tup = (competitionGroup, competitionClass, dance, id) tup = solo_turnier.types.CompetitionTuple(
participants[tup] = (places[idx], cls, grp) competitionGroup, competitionClass, dance, int(id)
)
fixture = solo_turnier.types.HtmlSingleCompetitionFixture(
place=places[idx], class_=cls, group=grp
)
participants[tup] = fixture
tables = self.soup.find("div", class_="extract").find_all("table") tables = self.soup.find("div", class_="extract").find_all("table")
for table in tables: for table in tables:

View File

@ -87,8 +87,8 @@ class ConsoleOutputter(AbstractOutputter):
if result is None: if result is None:
return "" return ""
placeNative = getPlace(result.placeNative, result.placeNativeTo) placeNative = str(result.nativePlace)
place = getPlace(result.place, result.placeTo) place = str(result.place)
lineOne = f"{placeNative} ({result.nativeClass})" lineOne = f"{placeNative} ({result.nativeClass})"
lineTwo = f"[{place} in {result.competitionClass}]" lineTwo = f"[{place} in {result.competitionClass}]"
@ -106,7 +106,7 @@ class ConsoleOutputter(AbstractOutputter):
print(tabulate(tableData, headers="firstrow", tablefmt="fancy_grid")) print(tabulate(tableData, headers="firstrow", tablefmt="fancy_grid"))
def output(self, data: types.State4): def output(self, data: types.State4):
for idx, group in enumerate(data.groups): for idx, group in enumerate(data.results):
if idx > 0: if idx > 0:
print() print()

View File

@ -1,20 +1,17 @@
from .place import Place from .place import Place
from .person import Person
from .htmlPreviewParticipant import HtmlPreviewParticipant from .htmlPreviewParticipant import HtmlPreviewParticipant
from .htmlParticipant import HtmlParticipant from .htmlParticipant import HtmlParticipant
from .htmlPreviewImport import HtmlPreviewImport
from .htmlResultImport import HtmlResultImport from .htmlResultImport import HtmlResultImport
from .htmlResultTotalTable import HtmlResultTotalTable from .htmlResultTotalTable import HtmlResultTotalTable
from .htmlCompetitionResultRow import HtmlCompetitionResultRow from .htmlCompetitionResultRow import HtmlCompetitionResultRow
from .competitionTuple import CompetitionTuple
from .htmlSingleCompetitionResult import HtmlSingleCompetitionResult from .htmlSingleCompetitionResult import HtmlSingleCompetitionResult
from .htmlSingleCompetitionFixture import HtmlSingleCompetitionFixture
from .htmlCompetitionTotalResults import HtmlCompetitionTotalResults from .htmlCompetitionTotalResults import HtmlCompetitionTotalResults
from .singleParticipantResult import SingleParticipantResult from .singleParticipantResult import SingleParticipantResult
from .totalGroupResult import TotalGroupResult from .totalGroupResult import TotalGroupResult
from .participant import Participant from .participant import Participant
from .participantResult import ParticipantResult
from .tableCompetitionEntry import TableCompetitionEntry
from .tableEntry import TableEntry
from .tableRow import TableRow
from .outputTable import OutputTable
from .stages import * from .stages import *

View File

@ -0,0 +1,27 @@
import solo_turnier
class CompetitionTuple:
def __init__(
self,
group: solo_turnier.group.Group_t,
class_: solo_turnier.competition_class.Class_t,
dance: str,
id: int,
):
self.group = group
self.class_ = class_
self.dance = dance
self.id = id
def __hash__(self):
return hash(("Tuple", self.group, self.class_, self.dance, self.id))
def __repr__(self):
return f"T({self.group},{self.class_},{self.dance},{self.id})"
def __eq__(self, other):
if type(other) != type(self):
return False
return self.__hash__() == other.__hash__()

View File

@ -1,11 +1,12 @@
import solo_turnier import solo_turnier
from .htmlSingleCompetitionResult import HtmlSingleCompetitionResult from .htmlSingleCompetitionResult import HtmlSingleCompetitionResult
from .competitionTuple import CompetitionTuple
class HtmlCompetitionTotalResults: class HtmlCompetitionTotalResults:
def __init__(self): def __init__(self):
self.results = {} self.results = {}
self.tabges = {} self.fixups = {}
def __getTuple( def __getTuple(
self, self,
@ -14,7 +15,7 @@ class HtmlCompetitionTotalResults:
dance: str, dance: str,
id: int, id: int,
): ):
return (group, class_, dance, id) return CompetitionTuple(group, class_, dance, id)
def get( def get(
self, self,
@ -34,16 +35,16 @@ class HtmlCompetitionTotalResults:
ret = {} ret = {}
for k in self.results: for k in self.results:
if int(k[3]) != id: if int(k.id) != id:
continue continue
# ret = ret + self.results[k] # ret = ret + self.results[k]
# Dance, Group, Class # Dance, Group, Class
key = (k[2], k[0], k[1]) key = (k.dance, k.group, k.class_)
ret[key] = self.results[k] ret[key] = self.results[k]
return ret return ret
def add(self, group, class_, dance, id, result: HtmlSingleCompetitionResult): def add(self, group, class_, dance, id: int, result: HtmlSingleCompetitionResult):
tup = self.__getTuple(group, class_, dance, id) tup = self.__getTuple(group, class_, dance, id)
l = self.results.get(tup, []) l = self.results.get(tup, [])
l.append(result) l.append(result)

View File

@ -5,7 +5,7 @@ class HtmlParticipant:
self.finalist = None self.finalist = None
def __eq__(self, o): def __eq__(self, o):
if type(o) != HtmlPreviewParticipant: if type(o) != HtmlParticipant:
return False return False
return all( return all(

View File

@ -1,18 +0,0 @@
from .htmlPreviewParticipant import HtmlPreviewParticipant
import solo_turnier
class HtmlPreviewImport:
def __init__(
self,
participants: dict[int, list[HtmlPreviewParticipant]],
results: dict[
HtmlPreviewParticipant,
dict[str, solo_turnier.competition_class.CompetitionClass],
],
):
self.participants = participants
self.results = results
def __repr__(self):
return (str(self.participants), str(self.results))

View File

@ -0,0 +1,17 @@
from .place import Place
import solo_turnier
class HtmlSingleCompetitionFixture:
def __init__(
self,
place: Place,
group: solo_turnier.group.Group,
class_: solo_turnier.competition_class.CompetitionClass,
):
self.place = place
self.group = group
self.class_ = class_
def __repr__(self):
return f"Fix({self.place},{self.group},{self.class_})"

View File

@ -1,15 +1,14 @@
from .place import Place
class HtmlSingleCompetitionResult: class HtmlSingleCompetitionResult:
def __init__(self, name, place, placeTo, finalist): def __init__(self, name: str, place: Place, finalist: bool):
self.name = name self.name = name
self.place = place self.place = place
self.placeTo = placeTo
self.finalist = finalist self.finalist = finalist
def __repr__(self): def __repr__(self):
if self.placeTo is None:
place = self.place place = self.place
else:
place = f"{self.place}-{self.placeTo}"
if self.finalist: if self.finalist:
return f"Res({self.name} [F], placed {place})" return f"Res({self.name} [F], placed {place})"

View File

@ -1,7 +0,0 @@
from .tableRow import TableRow
class OutputTable:
def __init__(self, dances: list[str], rows: list[TableRow]):
self.dances = dances
self.rows = rows

View File

@ -1,17 +1,20 @@
import solo_turnier import solo_turnier
from .person import Person
class Participant:
class Participant(Person):
def __init__( def __init__(
self, self,
firstName: str, name: str,
lastName: str, id: int,
club: str, finalist: bool = None,
group: solo_turnier.group.Group,
class_: solo_turnier.competition_class.CompetitionClass,
): ):
self.firstName = firstName super().__init__(name)
self.lastName = lastName self.id = id
self.club = club self.finalist = finalist
self.group = group
self.class_ = class_ def __repr__(self):
if self.finalist == True:
return f"Part({self.id} {self.name},F)"
return f"Part({self.id} {self.name})"

View File

@ -1,23 +0,0 @@
import solo_turnier
class ParticipantResult:
def __init__(
self,
id: int,
finalist: bool,
cancelled: bool,
group: solo_turnier.group.Group_t,
class_: solo_turnier.competition_class.Class_t,
dance: str,
place,
placeTo,
):
self.id = id
self.finalist = finalist
self.cancelled = cancelled
self.group = group
self.class_ = class_
self.dance = dance
self.place = place
self.placeTo = placeTo

View File

@ -0,0 +1,3 @@
class Person:
def __init__(self, name: str):
self.name = name

View File

@ -1,5 +1,7 @@
import solo_turnier import solo_turnier
from .place import Place
class SingleParticipantResult: class SingleParticipantResult:
def __init__( def __init__(
@ -8,38 +10,17 @@ class SingleParticipantResult:
nativeClass: solo_turnier.competition_class.CompetitionClass, nativeClass: solo_turnier.competition_class.CompetitionClass,
dance: str, dance: str,
finalist: bool, finalist: bool,
place: int, place: Place,
placeTo: int | None, nativePlace: Place = None,
): ):
self.competitionClass = competitionClass self.competitionClass = competitionClass
self.nativeClass = nativeClass self.nativeClass = nativeClass
self.dance = dance self.dance = dance
self.finalist = finalist self.finalist = finalist
self.place = place self.place = place
self.placeTo = placeTo self.nativePlace = nativePlace
if placeTo == place:
self.placeTo = None
self.placeNative = None
self.placeNativeTo = None
def __repr__(self): def __repr__(self):
asFinalist = " as finalist" if self.finalist else "" asFinalist = " as finalist" if self.finalist else ""
if self.placeTo is None: return f"SR[{self.place} in {self.dance} {self.competitionClass} ({self.nativePlace} {self.nativeClass}){asFinalist}]"
return f"SR[{self.place} in {self.dance} {self.competitionClass} ({self.placeNative}-{self.placeNativeTo}, {self.nativeClass}){asFinalist}]"
return f"SR[{self.place}-{self.placeTo} in {self.dance} {self.competitionClass} ({self.placeNative}-{self.placeNativeTo}, {self.nativeClass}){asFinalist}]"
def getPlace(self):
if self.placeTo is None:
return f"{self.place}."
else:
return f"{self.place}.-{self.placeTo}."
def getNativePlace(self):
if self.placeNativeTo is None:
return f"{self.placeNative}."
else:
return f"{self.placeNative}.-{self.placeNativeTo}."

View File

@ -2,14 +2,11 @@ import solo_turnier
from .totalGroupResult import TotalGroupResult from .totalGroupResult import TotalGroupResult
from .htmlCompetitionTotalResults import HtmlCompetitionTotalResults from .htmlCompetitionTotalResults import HtmlCompetitionTotalResults
from .participant import Participant
from .participantResult import ParticipantResult
from .outputTable import OutputTable
class State4: class State4:
def __init__( def __init__(
self, resultPerGroup: dict[solo_turnier.group.Group, TotalGroupResult] self, resultPerGroup: dict[solo_turnier.group.Group | None, TotalGroupResult]
): ):
parser = solo_turnier.group.GroupParser() parser = solo_turnier.group.GroupParser()
self.groups = parser.getGroupsAsSortedList(resultPerGroup.keys()) self.groups = parser.getGroupsAsSortedList(resultPerGroup.keys())
@ -19,16 +16,3 @@ class State4:
class State3: class State3:
def __init__(self, htmlResults: HtmlCompetitionTotalResults): def __init__(self, htmlResults: HtmlCompetitionTotalResults):
self.htmlResults = htmlResults self.htmlResults = htmlResults
class Stage2:
def __init__(self, results: dict[Participant, list[ParticipantResult]]):
self.results = results
class Stage1:
def __init__(
self,
tables: dict[solo_turnier.group.Group, OutputTable],
):
self.tables = tables

View File

@ -1,44 +0,0 @@
import solo_turnier
class TableCompetitionEntry:
def __init__(
self,
cancelled: bool,
finalist: bool,
class_: solo_turnier.competition_class.Class_t,
place: int = -1,
placeTo: int = -1,
group: solo_turnier.group.Group_t = None,
id: int = None,
):
self.finalist = finalist
self.cancelled = cancelled
self.group = group
self.class_ = class_
self.place = place
self.placeTo = placeTo
def __repr__(self):
def paramMerging(l):
return ", ".join(filter(lambda x: x is not None, l))
if self.cancelled:
params = paramMerging([self.group, self.class_, self.id])
if len(params) > 0:
return f"- ({params})"
else:
return "-"
elif not self.finalist:
params = paramMerging([self.group, self.class_, self.id])
if len(params) > 0:
return f"x ({params})"
else:
return "x"
else:
if self.place == self.placeTo:
place = f"{self.place}."
else:
place = f"{self.place}.-{self.placeTo}."
params = paramMerging([self.group, self.class_, self.id])
return f"{place} ({params})"

View File

@ -1,9 +0,0 @@
from .tableCompetitionEntry import TableCompetitionEntry
class TableEntry:
def __init__(self, competitions: list[TableCompetitionEntry]):
self.competitions = competitions
def __repr__(self):
return ", ".join(self.competitions)

View File

@ -1,16 +0,0 @@
from .participant import Participant
from .tableEntry import TableEntry
class TableRow:
def __init__(self, participant: Participant, id: int, entries: list[TableEntry]):
self.participant = participant
self.id = id
self.entries = entries
def getRowList(self):
if self.id is not None:
first = f"{self.id}. {self.participant.firstName} {self.participant.lastName} ({self.participant.club})"
else:
first = f"{self.participant.firstName} {self.participant.lastName} ({self.participant.club})"
return [first] + map(str, self.entries)

View File

@ -1,15 +1,15 @@
from .htmlPreviewParticipant import HtmlPreviewParticipant
from .singleParticipantResult import SingleParticipantResult from .singleParticipantResult import SingleParticipantResult
from .participant import Participant
class TotalGroupResult: class TotalGroupResult:
def __init__( def __init__(
self, self,
dances: list[str], dances: list[str],
results: dict[HtmlPreviewParticipant, list[SingleParticipantResult]], results: dict[Participant, list[SingleParticipantResult]],
): ):
self.dances = dances self.dances = dances
self.results = results self.results = results
def __repr__(self): def __repr__(self):
return f"TotalGroupResult({self.dances}, {self.results})" return f"TotalGrR({self.dances}, {self.results})"

View File

@ -38,13 +38,7 @@ class ResultExtractor:
) )
continue continue
try: guessedClass = data["class_"]
guessedClass = classParser.parseClass(data["class_"])
except:
self.l.error(
"Issue parsing class of file %s. Check manually.", filePair[0]
)
continue
self.l.debug( self.l.debug(
"Fetched result data: %s, guessed class %s", data, guessedClass "Fetched result data: %s, guessed class %s", data, guessedClass
@ -82,18 +76,20 @@ class ResultExtractor:
for person in result.results.keys(): for person in result.results.keys():
placeStr = result.results[person] placeStr = result.results[person]
placeObj = self._extractPlace(placeStr) place = self._extractPlace(placeStr)
place = placeObj.place
placeTo = placeObj.placeTo
competitionResult = types.HtmlSingleCompetitionResult( competitionResult = types.HtmlSingleCompetitionResult(
person.name, place, placeTo, person.finalist person.name, place, person.finalist
) )
results.add( results.add(
competitionGroup, competitionClass, dance, person.id, competitionResult competitionGroup,
competitionClass,
dance,
int(person.id),
competitionResult,
) )
# #
def _analyzeIndividualResults( def _analyzeResultFixups(
self, parser: html_parser.HtmlParser, results: types.HtmlCompetitionTotalResults self, parser: html_parser.HtmlParser, results: types.HtmlCompetitionTotalResults
): ):
data = parser.guessDataFromHtmlTitle() data = parser.guessDataFromHtmlTitle()
@ -101,9 +97,11 @@ class ResultExtractor:
competitionGroup = data["group"] competitionGroup = data["group"]
dance = data["dance"] dance = data["dance"]
result = parser.parseIndividualResult(competitionGroup, competitionClass, dance) resultFixups = parser.parseIndividualResult(
self.l.log(5, "Found individual results: %s", result.participants) competitionGroup, competitionClass, dance
results.tabges.update(result.participants) )
self.l.log(5, "Found additional result fixups: %s", resultFixups.participants)
results.fixups.update(resultFixups.participants)
def extractAllData( def extractAllData(
self, parsers: ParserList_t self, parsers: ParserList_t
@ -124,6 +122,6 @@ class ResultExtractor:
"Fetching individual result of combined competitions in %s", "Fetching individual result of combined competitions in %s",
fileName, fileName,
) )
self._analyzeIndividualResults(parsers[fileNameTuple][1], ret) self._analyzeResultFixups(parsers[fileNameTuple][1], ret)
return ret return ret

View File

@ -18,12 +18,16 @@ class Worker:
"Quickstep", "Quickstep",
] ]
self._groupParser = solo_turnier.group.GroupParser() self._groupParser = solo_turnier.group.GroupParser()
self._classParser = solo_turnier.competition_class.CompetitionClassParser()
def collectAllData(self, htmlResultsFileNames: list[str]) -> types.State3: def collectAllData(self, htmlResultsFileNames: list[str]) -> types.State3:
resultExtractor = ResultExtractor() resultExtractor = ResultExtractor()
resultParsers = resultExtractor.getAllParsers(htmlResultsFileNames) resultParsers = resultExtractor.getAllParsers(htmlResultsFileNames)
htmlResults = resultExtractor.extractAllData(resultParsers) htmlResults = resultExtractor.extractAllData(resultParsers)
self.l.debug("Overall result data extracted: %s", pformat(htmlResults.results)) self.l.log(5, "Overall result data extracted: %s", pformat(htmlResults.results))
self.l.log(
5, "Overall result fixups extracted: %s", pformat(htmlResults.fixups)
)
return types.State3(htmlResults) return types.State3(htmlResults)
@ -34,15 +38,92 @@ class Worker:
groupMapping = self._getGroupMapping(importedData) groupMapping = self._getGroupMapping(importedData)
self.l.log(5, "ID-to-group mapping of the parsed data: %s", str(groupMapping)) self.l.log(5, "ID-to-group mapping of the parsed data: %s", str(groupMapping))
# groups = self._extractGroups(importedData)
groups = self._extractGroupsFromGroupMapping(groupMapping) groups = self._extractGroupsFromGroupMapping(groupMapping)
self.l.debug("Found groups in the dataset: %s", groups) self.l.debug("Found groups in the dataset: %s", groups)
invertedGroupMapping = self._invertGroupMapping(groupMapping, groups) invertedGroupMapping = self._invertGroupMapping(groupMapping, groups)
self.l.log(5, "Inverted group maping: %s", invertedGroupMapping) self.l.log(5, "Inverted group maping: %s", invertedGroupMapping)
idToParticipantMapping = self._invertIdMapping(importedData.htmlResults)
self.l.log(5, "Id to participant mappting: %s", idToParticipantMapping)
totalResult = {} totalResult = {}
for group in invertedGroupMapping:
self.l.debug("Collecting data for group %s", group)
participants = invertedGroupMapping[group]
self.l.log(5, "Participants in group: %s", participants)
tuplesInCurrentGroup = []
for participantId in participants:
tuplesInCurrentGroup.extend(
self._filterResultKeys(importedData.htmlResults, id=participantId)
)
self.l.log(
5,
"Tuples of filtered in group %s: %s",
group,
list(tuplesInCurrentGroup),
)
dancesInGroup = self._extractAllDancesFromTuples(tuplesInCurrentGroup)
self.l.debug("Found dances in group %s: %s", group, dancesInGroup)
resultsInCurrentGroup = {}
for participantId in participants:
self.l.log(5, "Handling participant with ID %d", participantId)
# tuples = self._filterResultKeys(im)
participant = idToParticipantMapping[participantId]
self.l.log(5, "Participant in question: %s", participant)
participant.finalist = False
resultsInCurrentGroup[participant] = []
for tup in self._filterResultKeys(
importedData.htmlResults, id=participantId
):
singleHtmlResultList = importedData.htmlResults.results[tup]
if len(singleHtmlResultList) > 1:
self.l.warning(
"More than one result per tuple (%s) found.", tup
)
singleHtmlResult = singleHtmlResultList[0]
singleResult = solo_turnier.types.SingleParticipantResult(
competitionClass=tup.class_,
nativeClass=tup.class_,
dance=tup.dance,
finalist=singleHtmlResult.finalist,
place=singleHtmlResult.place,
nativePlace=singleHtmlResult.place,
)
if tup in importedData.htmlResults.fixups:
fixup = importedData.htmlResults.fixups[tup]
self.l.log(
5, "Fixture found for %s, %s: %s", participant, tup, fixup
)
self._applyFixture(singleResult, fixup)
resultsInCurrentGroup[participant].append(singleResult)
if singleHtmlResult.finalist:
participant.finalist = True
###########################################################################################################################
totalGroupResult = types.TotalGroupResult(
dancesInGroup, resultsInCurrentGroup
)
self.l.log(5, "Total group result of group %s: %s", group, totalGroupResult)
totalResult[group] = totalGroupResult
ret = types.State4(totalResult) ret = types.State4(totalResult)
return ret
for group in groups: for group in groups:
self.l.debug("Collecting data for total result of group %s", group) self.l.debug("Collecting data for total result of group %s", group)
@ -80,15 +161,9 @@ class Worker:
def _extractGroups(self, data: types.State3): def _extractGroups(self, data: types.State3):
groupSet = set([]) groupSet = set([])
# for id in data.previewImport.participants:
# participants = data.previewImport.participants[id]
# for participant in participants:
# groupSet.add(participant.group)
for tup in data.htmlResults.results.keys(): for tup in data.htmlResults.results.keys():
gr = self._groupParser.parseGroup(tup[0]) gr = self._groupParser.parseGroup(tup[0])
# groupSet.add(gr)
groupSet.update(gr.getContainedGroups()) groupSet.update(gr.getContainedGroups())
# self.l.log(5, 'Group type %s', type(gr))
self.l.log(5, "Set of active groups: %s", groupSet) self.l.log(5, "Set of active groups: %s", groupSet)
groups = self._groupParser.getGroupsAsSortedList(groupSet) groups = self._groupParser.getGroupsAsSortedList(groupSet)
@ -124,8 +199,9 @@ class Worker:
if counts[candidates[0]] > counts[candidates[1]]: if counts[candidates[0]] > counts[candidates[1]]:
if candidates[0] is None: if candidates[0] is None:
self.l.error( self.l.error(
"Majority of guessed groups is ambigous. Guessing failed for id %d. Falling back to second best guess.", "Majority of guessed groups is ambiguous. Guessing failed for id %d. Falling back to second best guess %s.",
id, id,
candidates[1],
) )
return candidates[1] return candidates[1]
@ -137,20 +213,22 @@ class Worker:
groupsPerId = {} groupsPerId = {}
for tup in importedData.htmlResults.results: for tup in importedData.htmlResults.results:
competitionGroup = self._groupParser.parseGroup(tup[0]) competitionGroup = tup.group
fixture = importedData.htmlResults.tabges.get(tup, (None, None, None)) fixture = importedData.htmlResults.fixups.get(
id = int(tup[3]) tup, solo_turnier.types.HtmlSingleCompetitionFixture(None, None, None)
if fixture[2] is not None: )
group = self._groupParser.parseGroup(fixture[2]) id = tup.id
if fixture.group is not None:
group = fixture.group
else: else:
containedGroups = competitionGroup.getContainedGroups() containedGroups = competitionGroup.getContainedGroups()
if len(containedGroups) > 1: if len(containedGroups) > 1:
self.l.error( self.l.error(
"The group for participant %d is ambiguous in (%s %s %s).", "The group for participant %d is ambiguous in (%s %s %s).",
id, id,
tup[0], tup.group,
tup[1], tup.class_,
tup[2], tup.dance,
) )
group = containedGroups group = containedGroups
else: else:
@ -193,8 +271,95 @@ class Worker:
ret[group] = [] ret[group] = []
for id in mapping: for id in mapping:
ret[mapping[id]].append(id) ret[mapping[id]].append(id)
for key in ret:
ret[key].sort()
return ret return ret
def _filterResultKeys(
self,
results: solo_turnier.types.HtmlCompetitionTotalResults,
group: solo_turnier.group.Group_t | None = None,
class_: solo_turnier.competition_class.Class_t | None = None,
dance: str | None = None,
id: int | None = None,
):
def checker(x: solo_turnier.types.CompetitionTuple) -> bool:
if group is not None and group != x.group:
return False
if class_ is not None and class_ != x.class_:
return False
if dance is not None and dance != x.dance:
return False
if id is not None and id != x.id:
return False
return True
return filter(checker, results.results.keys())
def _extractAllDancesFromTuples(
self, tuples: list[solo_turnier.types.CompetitionTuple]
) -> list[str]:
danceSet = set()
danceSet.update(map(lambda x: x.dance, tuples))
# Check for unknown dances here
setDiff = danceSet.difference(self._allDances)
if len(setDiff) > 0:
self.l.warning(
"There are dances in the data set that are not known in the program. A bug?"
)
return [x for x in self._allDances if x in danceSet] + list(setDiff)
def _invertIdMapping(
self, htmlData: solo_turnier.types.HtmlCompetitionTotalResults
):
mapping = {}
for tup in htmlData.results:
id = tup.id
results = htmlData.results[tup]
if len(results) > 1:
self.l.error(
"Non-unique results for tuple %s were found. Most probably this is a bug. The results are %s.",
tup,
results,
)
elif len(results) == 0:
self.l.error("No results for tuple %s found.", tup)
continue
if id not in mapping:
mapping[id] = solo_turnier.types.Participant(
name=results[0].name, id=id
)
else:
if mapping[id].name != results[0].name or mapping[id].id != id:
self.l.error(
"Invalid id to participant mapping found. The name of id has changed. Tuple was %s (values %s), mapping was %s",
tup,
results,
mapping[id],
)
return mapping
def _filterResultsById(
self, data: solo_turnier.types.HtmlCompetitionTotalResults, ids: list[int]
):
ret = {}
return ret
def _applyFixture(
self,
singleResult: solo_turnier.types.SingleParticipantResult,
fixture: solo_turnier.types.HtmlSingleCompetitionFixture,
):
singleResult.nativePlace = fixture.place
if fixture.class_ is not None:
singleResult.nativeClass = self._classParser.parseAbbreviatedClass(
fixture.class_
)
def _extractDancesPerGroup( def _extractDancesPerGroup(
self, data: types.State3, group: solo_turnier.group.Group self, data: types.State3, group: solo_turnier.group.Group
): ):
@ -365,34 +530,19 @@ class Worker:
pass pass
def filterOutFinalists(self, data: types.State4, filterOut: bool): def filterOutFinalists(self, data: types.State4, filterOut: bool):
if filterOut:
for group in data.results: for group in data.results:
self.l.debug("Cleaning up group %s", group.name) groupName = "unknown" if group is None else group.name
self.l.debug("Cleaning up group %s", groupName)
participants = data.results[group].results.keys() participants = data.results[group].results.keys()
droppedParticipants = [] droppedParticipants = []
for participant in participants: for participant in participants:
self.l.debug("Checking %s", participant) if participant.finalist == False:
def isFinalistInDance(x: types.HtmlSingleCompetitionResult | None):
if x is None:
return False
return x.finalist
mapped = list(
map(isFinalistInDance, data.results[group].results[participant])
)
finalist = True in mapped
self.l.log(5, "Check for finalist (in dances %s): %s", mapped, finalist)
if finalist:
participant.finalist = True
else:
participant.finalist = False
self.l.info( self.l.info(
"Dropping %s from the output as no finalist", participant "Dropping %s from the output as no finalist", participant
) )
droppedParticipants.append(participant) droppedParticipants.append(participant)
if filterOut:
for droppedParticipant in droppedParticipants: for droppedParticipant in droppedParticipants:
data.results[group].results.pop(droppedParticipant) data.results[group].results.pop(droppedParticipant)