First running version
Not yet comparable with previous code base due to different outputs.
This commit is contained in:
parent
3ea5b74557
commit
43180c6e05
@ -26,6 +26,12 @@ class CombinedCompetitionClass:
|
||||
else:
|
||||
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
|
||||
|
||||
|
@ -20,6 +20,12 @@ class CombinedGroup:
|
||||
def __repr__(self):
|
||||
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):
|
||||
return (self.clsA, self.clsB)
|
||||
|
||||
|
@ -3,10 +3,11 @@ from bs4 import BeautifulSoup
|
||||
import logging
|
||||
import re
|
||||
|
||||
from .types import HtmlPreviewParticipant, HtmlParticipant, HtmlResultTotalTable
|
||||
from .types import HtmlPreviewImport as HtmlImport, HtmlResultImport
|
||||
from .types import HtmlParticipant, HtmlResultTotalTable
|
||||
from .types import HtmlResultImport
|
||||
from .group import GroupParser
|
||||
from .competition_class import CompetitionClassParser
|
||||
import solo_turnier
|
||||
|
||||
|
||||
class IncompleteRoundException(Exception):
|
||||
@ -45,11 +46,11 @@ class HtmlParser:
|
||||
|
||||
return {
|
||||
"dance": dance.strip(),
|
||||
"class_": str(self.classParser.parseClass(rawClass, True)),
|
||||
"group": str(self.groupParser.parseGroup(rawGroup)),
|
||||
"class_": self.classParser.parseClass(rawClass, True),
|
||||
"group": self.groupParser.parseGroup(rawGroup),
|
||||
}
|
||||
|
||||
def parseResult(self):
|
||||
def parseResult(self) -> HtmlResultImport:
|
||||
participants = {}
|
||||
|
||||
def __parseRows(rows, finalist: bool):
|
||||
@ -111,6 +112,8 @@ class HtmlParser:
|
||||
def parseIndividualResult(self, competitionGroup, competitionClass, dance):
|
||||
participants = {}
|
||||
|
||||
rePlaceParser = re.compile("([0-9]+)(?:-([0-9]+))?")
|
||||
|
||||
def __parseTable(table):
|
||||
rows = table.find_all("tr")
|
||||
|
||||
@ -148,7 +151,20 @@ class HtmlParser:
|
||||
rawStr = tag.contents[0].strip()
|
||||
if rawStr.endswith("-"):
|
||||
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))
|
||||
return places
|
||||
@ -180,8 +196,13 @@ class HtmlParser:
|
||||
cls = classes[idx] if classes is not None else None
|
||||
grp = groups[idx] if groups is not None else None
|
||||
|
||||
tup = (competitionGroup, competitionClass, dance, id)
|
||||
participants[tup] = (places[idx], cls, grp)
|
||||
tup = solo_turnier.types.CompetitionTuple(
|
||||
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")
|
||||
for table in tables:
|
||||
|
@ -87,8 +87,8 @@ class ConsoleOutputter(AbstractOutputter):
|
||||
if result is None:
|
||||
return ""
|
||||
|
||||
placeNative = getPlace(result.placeNative, result.placeNativeTo)
|
||||
place = getPlace(result.place, result.placeTo)
|
||||
placeNative = str(result.nativePlace)
|
||||
place = str(result.place)
|
||||
lineOne = f"{placeNative} ({result.nativeClass})"
|
||||
lineTwo = f"[{place} in {result.competitionClass}]"
|
||||
|
||||
@ -106,7 +106,7 @@ class ConsoleOutputter(AbstractOutputter):
|
||||
print(tabulate(tableData, headers="firstrow", tablefmt="fancy_grid"))
|
||||
|
||||
def output(self, data: types.State4):
|
||||
for idx, group in enumerate(data.groups):
|
||||
for idx, group in enumerate(data.results):
|
||||
if idx > 0:
|
||||
print()
|
||||
|
||||
|
@ -1,20 +1,17 @@
|
||||
from .place import Place
|
||||
|
||||
from .person import Person
|
||||
from .htmlPreviewParticipant import HtmlPreviewParticipant
|
||||
from .htmlParticipant import HtmlParticipant
|
||||
from .htmlPreviewImport import HtmlPreviewImport
|
||||
from .htmlResultImport import HtmlResultImport
|
||||
from .htmlResultTotalTable import HtmlResultTotalTable
|
||||
from .htmlCompetitionResultRow import HtmlCompetitionResultRow
|
||||
from .competitionTuple import CompetitionTuple
|
||||
from .htmlSingleCompetitionResult import HtmlSingleCompetitionResult
|
||||
from .htmlSingleCompetitionFixture import HtmlSingleCompetitionFixture
|
||||
from .htmlCompetitionTotalResults import HtmlCompetitionTotalResults
|
||||
from .singleParticipantResult import SingleParticipantResult
|
||||
from .totalGroupResult import TotalGroupResult
|
||||
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 *
|
||||
|
27
src/solo_turnier/types/competitionTuple.py
Normal file
27
src/solo_turnier/types/competitionTuple.py
Normal 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__()
|
@ -1,11 +1,12 @@
|
||||
import solo_turnier
|
||||
from .htmlSingleCompetitionResult import HtmlSingleCompetitionResult
|
||||
from .competitionTuple import CompetitionTuple
|
||||
|
||||
|
||||
class HtmlCompetitionTotalResults:
|
||||
def __init__(self):
|
||||
self.results = {}
|
||||
self.tabges = {}
|
||||
self.fixups = {}
|
||||
|
||||
def __getTuple(
|
||||
self,
|
||||
@ -14,7 +15,7 @@ class HtmlCompetitionTotalResults:
|
||||
dance: str,
|
||||
id: int,
|
||||
):
|
||||
return (group, class_, dance, id)
|
||||
return CompetitionTuple(group, class_, dance, id)
|
||||
|
||||
def get(
|
||||
self,
|
||||
@ -34,16 +35,16 @@ class HtmlCompetitionTotalResults:
|
||||
ret = {}
|
||||
|
||||
for k in self.results:
|
||||
if int(k[3]) != id:
|
||||
if int(k.id) != id:
|
||||
continue
|
||||
# ret = ret + self.results[k]
|
||||
# Dance, Group, Class
|
||||
key = (k[2], k[0], k[1])
|
||||
key = (k.dance, k.group, k.class_)
|
||||
ret[key] = self.results[k]
|
||||
|
||||
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)
|
||||
l = self.results.get(tup, [])
|
||||
l.append(result)
|
||||
|
@ -5,7 +5,7 @@ class HtmlParticipant:
|
||||
self.finalist = None
|
||||
|
||||
def __eq__(self, o):
|
||||
if type(o) != HtmlPreviewParticipant:
|
||||
if type(o) != HtmlParticipant:
|
||||
return False
|
||||
|
||||
return all(
|
||||
|
@ -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))
|
17
src/solo_turnier/types/htmlSingleCompetitionFixture.py
Normal file
17
src/solo_turnier/types/htmlSingleCompetitionFixture.py
Normal 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_})"
|
@ -1,15 +1,14 @@
|
||||
from .place import Place
|
||||
|
||||
|
||||
class HtmlSingleCompetitionResult:
|
||||
def __init__(self, name, place, placeTo, finalist):
|
||||
def __init__(self, name: str, place: Place, finalist: bool):
|
||||
self.name = name
|
||||
self.place = place
|
||||
self.placeTo = placeTo
|
||||
self.finalist = finalist
|
||||
|
||||
def __repr__(self):
|
||||
if self.placeTo is None:
|
||||
place = self.place
|
||||
else:
|
||||
place = f"{self.place}-{self.placeTo}"
|
||||
|
||||
if self.finalist:
|
||||
return f"Res({self.name} [F], placed {place})"
|
||||
|
@ -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
|
@ -1,17 +1,20 @@
|
||||
import solo_turnier
|
||||
|
||||
from .person import Person
|
||||
|
||||
class Participant:
|
||||
|
||||
class Participant(Person):
|
||||
def __init__(
|
||||
self,
|
||||
firstName: str,
|
||||
lastName: str,
|
||||
club: str,
|
||||
group: solo_turnier.group.Group,
|
||||
class_: solo_turnier.competition_class.CompetitionClass,
|
||||
name: str,
|
||||
id: int,
|
||||
finalist: bool = None,
|
||||
):
|
||||
self.firstName = firstName
|
||||
self.lastName = lastName
|
||||
self.club = club
|
||||
self.group = group
|
||||
self.class_ = class_
|
||||
super().__init__(name)
|
||||
self.id = id
|
||||
self.finalist = finalist
|
||||
|
||||
def __repr__(self):
|
||||
if self.finalist == True:
|
||||
return f"Part({self.id} {self.name},F)"
|
||||
return f"Part({self.id} {self.name})"
|
||||
|
@ -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
|
3
src/solo_turnier/types/person.py
Normal file
3
src/solo_turnier/types/person.py
Normal file
@ -0,0 +1,3 @@
|
||||
class Person:
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
@ -1,5 +1,7 @@
|
||||
import solo_turnier
|
||||
|
||||
from .place import Place
|
||||
|
||||
|
||||
class SingleParticipantResult:
|
||||
def __init__(
|
||||
@ -8,38 +10,17 @@ class SingleParticipantResult:
|
||||
nativeClass: solo_turnier.competition_class.CompetitionClass,
|
||||
dance: str,
|
||||
finalist: bool,
|
||||
place: int,
|
||||
placeTo: int | None,
|
||||
place: Place,
|
||||
nativePlace: Place = None,
|
||||
):
|
||||
self.competitionClass = competitionClass
|
||||
self.nativeClass = nativeClass
|
||||
self.dance = dance
|
||||
self.finalist = finalist
|
||||
self.place = place
|
||||
self.placeTo = placeTo
|
||||
|
||||
if placeTo == place:
|
||||
self.placeTo = None
|
||||
|
||||
self.placeNative = None
|
||||
self.placeNativeTo = None
|
||||
self.nativePlace = nativePlace
|
||||
|
||||
def __repr__(self):
|
||||
asFinalist = " as finalist" if self.finalist else ""
|
||||
|
||||
if self.placeTo is None:
|
||||
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}."
|
||||
return f"SR[{self.place} in {self.dance} {self.competitionClass} ({self.nativePlace} {self.nativeClass}){asFinalist}]"
|
||||
|
@ -2,14 +2,11 @@ import solo_turnier
|
||||
|
||||
from .totalGroupResult import TotalGroupResult
|
||||
from .htmlCompetitionTotalResults import HtmlCompetitionTotalResults
|
||||
from .participant import Participant
|
||||
from .participantResult import ParticipantResult
|
||||
from .outputTable import OutputTable
|
||||
|
||||
|
||||
class State4:
|
||||
def __init__(
|
||||
self, resultPerGroup: dict[solo_turnier.group.Group, TotalGroupResult]
|
||||
self, resultPerGroup: dict[solo_turnier.group.Group | None, TotalGroupResult]
|
||||
):
|
||||
parser = solo_turnier.group.GroupParser()
|
||||
self.groups = parser.getGroupsAsSortedList(resultPerGroup.keys())
|
||||
@ -19,16 +16,3 @@ class State4:
|
||||
class State3:
|
||||
def __init__(self, htmlResults: HtmlCompetitionTotalResults):
|
||||
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
|
||||
|
@ -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})"
|
@ -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)
|
@ -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)
|
@ -1,15 +1,15 @@
|
||||
from .htmlPreviewParticipant import HtmlPreviewParticipant
|
||||
from .singleParticipantResult import SingleParticipantResult
|
||||
from .participant import Participant
|
||||
|
||||
|
||||
class TotalGroupResult:
|
||||
def __init__(
|
||||
self,
|
||||
dances: list[str],
|
||||
results: dict[HtmlPreviewParticipant, list[SingleParticipantResult]],
|
||||
results: dict[Participant, list[SingleParticipantResult]],
|
||||
):
|
||||
self.dances = dances
|
||||
self.results = results
|
||||
|
||||
def __repr__(self):
|
||||
return f"TotalGroupResult({self.dances}, {self.results})"
|
||||
return f"TotalGrR({self.dances}, {self.results})"
|
||||
|
@ -38,13 +38,7 @@ class ResultExtractor:
|
||||
)
|
||||
continue
|
||||
|
||||
try:
|
||||
guessedClass = classParser.parseClass(data["class_"])
|
||||
except:
|
||||
self.l.error(
|
||||
"Issue parsing class of file %s. Check manually.", filePair[0]
|
||||
)
|
||||
continue
|
||||
guessedClass = data["class_"]
|
||||
|
||||
self.l.debug(
|
||||
"Fetched result data: %s, guessed class %s", data, guessedClass
|
||||
@ -82,18 +76,20 @@ class ResultExtractor:
|
||||
|
||||
for person in result.results.keys():
|
||||
placeStr = result.results[person]
|
||||
placeObj = self._extractPlace(placeStr)
|
||||
place = placeObj.place
|
||||
placeTo = placeObj.placeTo
|
||||
place = self._extractPlace(placeStr)
|
||||
competitionResult = types.HtmlSingleCompetitionResult(
|
||||
person.name, place, placeTo, person.finalist
|
||||
person.name, place, person.finalist
|
||||
)
|
||||
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
|
||||
):
|
||||
data = parser.guessDataFromHtmlTitle()
|
||||
@ -101,9 +97,11 @@ class ResultExtractor:
|
||||
competitionGroup = data["group"]
|
||||
dance = data["dance"]
|
||||
|
||||
result = parser.parseIndividualResult(competitionGroup, competitionClass, dance)
|
||||
self.l.log(5, "Found individual results: %s", result.participants)
|
||||
results.tabges.update(result.participants)
|
||||
resultFixups = parser.parseIndividualResult(
|
||||
competitionGroup, competitionClass, dance
|
||||
)
|
||||
self.l.log(5, "Found additional result fixups: %s", resultFixups.participants)
|
||||
results.fixups.update(resultFixups.participants)
|
||||
|
||||
def extractAllData(
|
||||
self, parsers: ParserList_t
|
||||
@ -124,6 +122,6 @@ class ResultExtractor:
|
||||
"Fetching individual result of combined competitions in %s",
|
||||
fileName,
|
||||
)
|
||||
self._analyzeIndividualResults(parsers[fileNameTuple][1], ret)
|
||||
self._analyzeResultFixups(parsers[fileNameTuple][1], ret)
|
||||
|
||||
return ret
|
||||
|
@ -18,12 +18,16 @@ class Worker:
|
||||
"Quickstep",
|
||||
]
|
||||
self._groupParser = solo_turnier.group.GroupParser()
|
||||
self._classParser = solo_turnier.competition_class.CompetitionClassParser()
|
||||
|
||||
def collectAllData(self, htmlResultsFileNames: list[str]) -> types.State3:
|
||||
resultExtractor = ResultExtractor()
|
||||
resultParsers = resultExtractor.getAllParsers(htmlResultsFileNames)
|
||||
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)
|
||||
|
||||
@ -34,15 +38,92 @@ class Worker:
|
||||
groupMapping = self._getGroupMapping(importedData)
|
||||
self.l.log(5, "ID-to-group mapping of the parsed data: %s", str(groupMapping))
|
||||
|
||||
# groups = self._extractGroups(importedData)
|
||||
groups = self._extractGroupsFromGroupMapping(groupMapping)
|
||||
self.l.debug("Found groups in the dataset: %s", groups)
|
||||
|
||||
invertedGroupMapping = self._invertGroupMapping(groupMapping, groups)
|
||||
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 = {}
|
||||
|
||||
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)
|
||||
return ret
|
||||
|
||||
for group in groups:
|
||||
self.l.debug("Collecting data for total result of group %s", group)
|
||||
@ -80,15 +161,9 @@ class Worker:
|
||||
|
||||
def _extractGroups(self, data: types.State3):
|
||||
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():
|
||||
gr = self._groupParser.parseGroup(tup[0])
|
||||
# groupSet.add(gr)
|
||||
groupSet.update(gr.getContainedGroups())
|
||||
# self.l.log(5, 'Group type %s', type(gr))
|
||||
|
||||
self.l.log(5, "Set of active groups: %s", groupSet)
|
||||
groups = self._groupParser.getGroupsAsSortedList(groupSet)
|
||||
@ -124,8 +199,9 @@ class Worker:
|
||||
if counts[candidates[0]] > counts[candidates[1]]:
|
||||
if candidates[0] is None:
|
||||
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,
|
||||
candidates[1],
|
||||
)
|
||||
return candidates[1]
|
||||
|
||||
@ -137,20 +213,22 @@ class Worker:
|
||||
|
||||
groupsPerId = {}
|
||||
for tup in importedData.htmlResults.results:
|
||||
competitionGroup = self._groupParser.parseGroup(tup[0])
|
||||
fixture = importedData.htmlResults.tabges.get(tup, (None, None, None))
|
||||
id = int(tup[3])
|
||||
if fixture[2] is not None:
|
||||
group = self._groupParser.parseGroup(fixture[2])
|
||||
competitionGroup = tup.group
|
||||
fixture = importedData.htmlResults.fixups.get(
|
||||
tup, solo_turnier.types.HtmlSingleCompetitionFixture(None, None, None)
|
||||
)
|
||||
id = tup.id
|
||||
if fixture.group is not None:
|
||||
group = fixture.group
|
||||
else:
|
||||
containedGroups = competitionGroup.getContainedGroups()
|
||||
if len(containedGroups) > 1:
|
||||
self.l.error(
|
||||
"The group for participant %d is ambiguous in (%s %s %s).",
|
||||
id,
|
||||
tup[0],
|
||||
tup[1],
|
||||
tup[2],
|
||||
tup.group,
|
||||
tup.class_,
|
||||
tup.dance,
|
||||
)
|
||||
group = containedGroups
|
||||
else:
|
||||
@ -193,8 +271,95 @@ class Worker:
|
||||
ret[group] = []
|
||||
for id in mapping:
|
||||
ret[mapping[id]].append(id)
|
||||
for key in ret:
|
||||
ret[key].sort()
|
||||
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(
|
||||
self, data: types.State3, group: solo_turnier.group.Group
|
||||
):
|
||||
@ -365,34 +530,19 @@ class Worker:
|
||||
pass
|
||||
|
||||
def filterOutFinalists(self, data: types.State4, filterOut: bool):
|
||||
if filterOut:
|
||||
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()
|
||||
droppedParticipants = []
|
||||
|
||||
for participant in participants:
|
||||
self.l.debug("Checking %s", participant)
|
||||
|
||||
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
|
||||
if participant.finalist == False:
|
||||
self.l.info(
|
||||
"Dropping %s from the output as no finalist", participant
|
||||
)
|
||||
droppedParticipants.append(participant)
|
||||
|
||||
if filterOut:
|
||||
for droppedParticipant in droppedParticipants:
|
||||
data.results[group].results.pop(droppedParticipant)
|
||||
|
Loading…
Reference in New Issue
Block a user