Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0198ecf752 | |||
| 801c7f2bbd | |||
| 16ed0280cd | |||
| 5712c3da63 | |||
| 3b98cef590 | |||
| 4bc626b163 | |||
| 533f3ef237 | |||
| 61a607e516 | |||
| cd8ab716b8 | |||
| a7f8bad0ec | |||
| 7ec359d2f2 | |||
| 5c4b0106fc |
@@ -1,6 +1,6 @@
|
|||||||
[Application]
|
[Application]
|
||||||
name=Solo Auswertung
|
name=Solo Auswertung
|
||||||
version=2.0.0
|
version=2.1.1
|
||||||
# How to launch the app - this calls the 'main' function from the 'myapp' package:
|
# How to launch the app - this calls the 'main' function from the 'myapp' package:
|
||||||
entry_point=main:main
|
entry_point=main:main
|
||||||
# icon=myapp.ico
|
# icon=myapp.ico
|
||||||
@@ -17,10 +17,18 @@ console=true
|
|||||||
# Packages from PyPI that your application requires, one per line
|
# Packages from PyPI that your application requires, one per line
|
||||||
# These must have wheels on PyPI:
|
# These must have wheels on PyPI:
|
||||||
pypi_wheels = beautifulsoup4==4.12.3
|
pypi_wheels = beautifulsoup4==4.12.3
|
||||||
coloredlogs==15.0.1
|
blinker==1.8.2
|
||||||
flask==3.0.2
|
click==8.1.7
|
||||||
tabulate==0.9.0
|
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
|
coloredlogs==15.0.1
|
||||||
|
flask==3.0.3
|
||||||
|
humanfriendly==10.0
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
jinja2==3.1.4
|
||||||
|
markupsafe==2.1.5
|
||||||
|
soupsieve==2.5
|
||||||
|
tabulate==0.9.0
|
||||||
|
werkzeug==3.0.3
|
||||||
|
|
||||||
packages = solo_turnier
|
packages = solo_turnier
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import debugpy
|
|
||||||
|
|
||||||
|
|
||||||
class Cli:
|
class Cli:
|
||||||
def __init__(self, l: logging.Logger):
|
def __init__(self, l: logging.Logger):
|
||||||
@@ -50,6 +48,8 @@ class Cli:
|
|||||||
self.__args = parser.parse_args()
|
self.__args = parser.parse_args()
|
||||||
|
|
||||||
if self.__args.debug:
|
if self.__args.debug:
|
||||||
|
import debugpy
|
||||||
|
|
||||||
debugpy.listen(5678)
|
debugpy.listen(5678)
|
||||||
debugpy.wait_for_client()
|
debugpy.wait_for_client()
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ class IncompleteRoundException(Exception):
|
|||||||
super(IncompleteRoundException, self).__init__(*args)
|
super(IncompleteRoundException, self).__init__(*args)
|
||||||
|
|
||||||
|
|
||||||
|
class CannotParseRowException(Exception):
|
||||||
|
def __init__(self, *args):
|
||||||
|
super(CannotParseRowException, self).__init__(*args)
|
||||||
|
|
||||||
|
|
||||||
class HtmlParser:
|
class HtmlParser:
|
||||||
def __init__(self, text: str, fileName: str = None):
|
def __init__(self, text: str, fileName: str = None):
|
||||||
self.l = logging.getLogger("solo_turnier.html_parser")
|
self.l = logging.getLogger("solo_turnier.html_parser")
|
||||||
@@ -37,6 +42,12 @@ class HtmlParser:
|
|||||||
title = self.getEventTitle()
|
title = self.getEventTitle()
|
||||||
|
|
||||||
match = re.compile('.*?OT, Solos (.*?)(?: ".*")?').fullmatch(title)
|
match = re.compile('.*?OT, Solos (.*?)(?: ".*")?').fullmatch(title)
|
||||||
|
if match is None:
|
||||||
|
self.l.debug(
|
||||||
|
'Parsing HTML page title "%s" as OT failed. Falling back to legacy ETW.',
|
||||||
|
title,
|
||||||
|
)
|
||||||
|
match = re.compile('.*?ETW, Solos (.*?)(?: ".*")?').fullmatch(title)
|
||||||
if match is None:
|
if match is None:
|
||||||
self.l.info(
|
self.l.info(
|
||||||
'Cannot parse html title "%s". Is it a solo competition? Possible bug.',
|
'Cannot parse html title "%s". Is it a solo competition? Possible bug.',
|
||||||
@@ -56,34 +67,50 @@ class HtmlParser:
|
|||||||
def parseResult(self) -> HtmlResultImport:
|
def parseResult(self) -> HtmlResultImport:
|
||||||
participants = {}
|
participants = {}
|
||||||
|
|
||||||
def __parseRows(rows, finalist: bool):
|
nameRegex = re.compile("(.*) \\(([0-9]+)\\)")
|
||||||
def __parseRow(row):
|
|
||||||
tds = row.find_all("td")
|
|
||||||
|
|
||||||
if len(tds) != 2:
|
def __parseNameAndId(string: str, tds) -> tuple[str, str]:
|
||||||
return
|
match = nameRegex.fullmatch(string)
|
||||||
|
if match is None:
|
||||||
|
self.l.error("Could not match %s to regex search pattern", str(tds))
|
||||||
|
raise CannotParseRowException(
|
||||||
|
f"Could not match {tds} to regex search pattern for 'name (id)'"
|
||||||
|
)
|
||||||
|
name = match.group(1)
|
||||||
|
number = match.group(2)
|
||||||
|
return name, number
|
||||||
|
|
||||||
if tds[1].contents[0].startswith("Alle Starter weiter genommen."):
|
def __parseRows(rows, parsers):
|
||||||
self.l.info("No excluded starters found.")
|
def parseRow(row):
|
||||||
return
|
for parser in parsers:
|
||||||
|
try:
|
||||||
|
parser(row("td"))
|
||||||
|
return
|
||||||
|
except CannotParseRowException:
|
||||||
|
pass
|
||||||
|
|
||||||
regex = re.compile("(.*) \\(([0-9]+)\\)")
|
# No parser was found if we get here.
|
||||||
|
self.l.error("Cannot parse row in table.")
|
||||||
place = tds[0].contents[0]
|
|
||||||
|
|
||||||
match = regex.fullmatch(tds[1].contents[0])
|
|
||||||
if match is None:
|
|
||||||
self.l.error("Could not match %s to regex search pattern", str(tds))
|
|
||||||
raise Exception(f"Could not match {tds} to regex search pattern")
|
|
||||||
name = match.group(1)
|
|
||||||
number = match.group(2)
|
|
||||||
|
|
||||||
participant = HtmlParticipant(name, number)
|
|
||||||
participant.finalist = finalist
|
|
||||||
participants[participant] = place
|
|
||||||
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
__parseRow(row)
|
parseRow(row)
|
||||||
|
|
||||||
|
def __ensureLength(tds, length):
|
||||||
|
if len(tds) != length:
|
||||||
|
raise CannotParseRowException(
|
||||||
|
"The row has %d entries but %d are expected." % (len(tds), length)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __parseFormationRowGeneric(tds, finalist):
|
||||||
|
__ensureLength(tds, 2)
|
||||||
|
|
||||||
|
place = tds[0].contents[0]
|
||||||
|
name, number = __parseNameAndId(tds[1].contents[0], tds)
|
||||||
|
|
||||||
|
participant = HtmlParticipant(name, number)
|
||||||
|
participant.finalist = finalist
|
||||||
|
participant.club = ""
|
||||||
|
participants[participant] = place
|
||||||
|
|
||||||
def __parseFirstTable(table):
|
def __parseFirstTable(table):
|
||||||
roundName = table.tr.td.contents[0]
|
roundName = table.tr.td.contents[0]
|
||||||
@@ -91,11 +118,93 @@ class HtmlParser:
|
|||||||
self.l.warning("Found table with round name %s.", roundName)
|
self.l.warning("Found table with round name %s.", roundName)
|
||||||
raise IncompleteRoundException("Could not parse HTML file")
|
raise IncompleteRoundException("Could not parse HTML file")
|
||||||
|
|
||||||
__parseRows(table.find_all("tr")[2:], True)
|
def __parseFormationRow(tds):
|
||||||
|
__parseFormationRowGeneric(tds, True)
|
||||||
|
|
||||||
|
def __parsePairRow(tds):
|
||||||
|
__ensureLength(tds, 4)
|
||||||
|
|
||||||
|
place = tds[0].contents[0]
|
||||||
|
tdNameClub = tds[1]
|
||||||
|
tdClub = tdNameClub.i.extract()
|
||||||
|
name, number = __parseNameAndId(tdNameClub.contents[0], tds)
|
||||||
|
|
||||||
|
participant = HtmlParticipant(name, number)
|
||||||
|
participant.finalist = True
|
||||||
|
participant.club = tdClub.contents[0]
|
||||||
|
|
||||||
|
participants[participant] = place
|
||||||
|
|
||||||
|
__parseRows(
|
||||||
|
table.find_all("tr")[2:],
|
||||||
|
[
|
||||||
|
__parsePairRow,
|
||||||
|
__parseFormationRow,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def __parseRemainingTables(tables):
|
def __parseRemainingTables(tables):
|
||||||
|
|
||||||
|
def __parseFormationRow(tds):
|
||||||
|
__parseFormationRowGeneric(tds, False)
|
||||||
|
|
||||||
|
def __parsePairRow(tds):
|
||||||
|
__ensureLength(tds, 3)
|
||||||
|
|
||||||
|
place = tds[0].contents[0]
|
||||||
|
name, number = __parseNameAndId(tds[1].contents[0], tds)
|
||||||
|
|
||||||
|
participant = HtmlParticipant(name, number)
|
||||||
|
participant.finalist = False
|
||||||
|
participant.club = tds[2].contents[0]
|
||||||
|
|
||||||
|
participants[participant] = place
|
||||||
|
|
||||||
|
def __parseSeparatorRow(tds):
|
||||||
|
__ensureLength(tds, 1)
|
||||||
|
if len(list(tds[0].stripped_strings)) == 0:
|
||||||
|
return
|
||||||
|
raise CannotParseRowException("No empty string")
|
||||||
|
|
||||||
|
regexZwischenRunde = re.compile("[1-9]\. Zwischenrunde")
|
||||||
|
|
||||||
|
def __parseRoundHeading(tds):
|
||||||
|
__ensureLength(tds, 1)
|
||||||
|
s = "".join(tds[0].stripped_strings)
|
||||||
|
if s.startswith("Vorrunde"):
|
||||||
|
return
|
||||||
|
if regexZwischenRunde.match(s) is not None:
|
||||||
|
return
|
||||||
|
raise CannotParseRowException("Kein Header einer Runde gefunden.")
|
||||||
|
|
||||||
|
def __parseAllSolosQualifiedFormation(tds):
|
||||||
|
__ensureLength(tds, 2)
|
||||||
|
if tds[1].contents[0].startswith("Alle Starter weiter genommen."):
|
||||||
|
return
|
||||||
|
raise CannotParseRowException(
|
||||||
|
'Not found the text "Alle Starter weiter genommen"'
|
||||||
|
)
|
||||||
|
|
||||||
|
def __parseAllSolosQualifiedPair(tds):
|
||||||
|
__ensureLength(tds, 3)
|
||||||
|
if tds[1].contents[0].startswith("Alle Mannschaften weiter genommen."):
|
||||||
|
return
|
||||||
|
raise CannotParseRowException(
|
||||||
|
'Not found the text "Alle Mannschaften weiter genommen"'
|
||||||
|
)
|
||||||
|
|
||||||
for table in tables:
|
for table in tables:
|
||||||
__parseRows(table.find_all("tr"), False)
|
__parseRows(
|
||||||
|
table.find_all("tr"),
|
||||||
|
[
|
||||||
|
__parseAllSolosQualifiedFormation,
|
||||||
|
__parseAllSolosQualifiedPair,
|
||||||
|
__parsePairRow,
|
||||||
|
__parseFormationRow,
|
||||||
|
__parseSeparatorRow,
|
||||||
|
__parseRoundHeading,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
tables = self.soup.find("div", class_="extract").find_all("table")
|
tables = self.soup.find("div", class_="extract").find_all("table")
|
||||||
|
|
||||||
|
|||||||
@@ -117,16 +117,26 @@ class ConsoleOutputter(AbstractOutputter):
|
|||||||
placeNative = str(result.nativePlace)
|
placeNative = str(result.nativePlace)
|
||||||
place = str(result.place)
|
place = str(result.place)
|
||||||
lineOne = f"{placeNative}"
|
lineOne = f"{placeNative}"
|
||||||
# lineTwo = f"[{place} in {result.competitionClass}]"
|
|
||||||
|
|
||||||
lines = [lineOne]
|
lines = [lineOne]
|
||||||
|
|
||||||
|
groupCompetition = result.competitionGroup
|
||||||
|
if isinstance(groupCompetition, solo_turnier.group.CombinedGroup):
|
||||||
|
lineTwo = f"[{place} in {groupCompetition}]"
|
||||||
|
lines.append(lineTwo)
|
||||||
|
|
||||||
if not result.finalist:
|
if not result.finalist:
|
||||||
lines = ["kein/e Finalist/in"] + lines
|
lines = ["kein/e Finalist/in"] + lines
|
||||||
|
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
mappedResults = map(mapResultColumn, results)
|
mappedResults = map(mapResultColumn, results)
|
||||||
tableRow = [f"{participant.name} ({participant.id})"] + list(mappedResults)
|
|
||||||
|
participantName = f"{participant.name} ({participant.id})"
|
||||||
|
if participant.club is not None:
|
||||||
|
participantName = f"{participantName}, {participant.club}"
|
||||||
|
|
||||||
|
tableRow = [f"{participantName}"] + list(mappedResults)
|
||||||
tableData.append(tableRow)
|
tableData.append(tableRow)
|
||||||
|
|
||||||
self.l.log(5, "table data: %s", pprint.pformat(tableData))
|
self.l.log(5, "table data: %s", pprint.pformat(tableData))
|
||||||
|
|||||||
@@ -1,53 +1,51 @@
|
|||||||
|
|
||||||
.tab-summary {
|
.tab-summary {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-summary tr:nth-of-type(even) {
|
.tab-summary tr:nth-of-type(even) {
|
||||||
background-color: cyan;
|
background-color: cyan;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-summary td {
|
.tab-summary td {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-summary td .competition-place {
|
.tab-summary td .competition-place {
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-summary .no-finalist {
|
.tab-summary .no-finalist {
|
||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-summary .no-finalist-dance {
|
.tab-summary .no-finalist-dance {
|
||||||
color: gray;
|
color: gray;
|
||||||
text-decoration-style: solid;
|
text-decoration-style: solid;
|
||||||
text-decoration-line: line-through;
|
text-decoration-line: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
@page {
|
@page {
|
||||||
size: landscape;
|
size: landscape;
|
||||||
}
|
}
|
||||||
@page portrait {
|
@page portrait {
|
||||||
size: portrait;
|
size: portrait;
|
||||||
}
|
}
|
||||||
/* body {
|
/* body {
|
||||||
size: landscape;
|
size: landscape;
|
||||||
page-orientation: rotate-right;
|
page-orientation: rotate-right;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
.section,
|
.section,
|
||||||
.section table tr,
|
.section table tr,
|
||||||
.section table td
|
.section table td {
|
||||||
{
|
page-break-inside: avoid;
|
||||||
page-break-inside: avoid;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.tab-summary .no-finalist {
|
.tab-summary .no-finalist {
|
||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if participant.finalist or not onlyFinalists %}
|
{% if participant.finalist or not onlyFinalists %}
|
||||||
<tr class="{{ rowCls }}">
|
<tr class="{{ rowCls }}">
|
||||||
<td>{{ participant.name }} ({{ participant.id }})</td>
|
<td>
|
||||||
|
{{ participant.name }} ({{ participant.id }})
|
||||||
|
{% if participant.club is not none %}
|
||||||
|
, {{ participant.club}}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
{% for dance in data.resultsPerGroup[group].dances %}
|
{% for dance in data.resultsPerGroup[group].dances %}
|
||||||
{% block danceResult scoped %}
|
{% block danceResult scoped %}
|
||||||
{% set res = activeGroup[participant][loop.index0] %}
|
{% set res = activeGroup[participant][loop.index0] %}
|
||||||
@@ -45,6 +50,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="{% if not res.finalist %}no-finalist-dance{% endif %}">
|
<span class="{% if not res.finalist %}no-finalist-dance{% endif %}">
|
||||||
{{ res.getNativePlace() }}
|
{{ res.getNativePlace() }}
|
||||||
|
{% if res.isCombinedGroup() %}
|
||||||
|
<br />
|
||||||
|
({{ res.place }} {{ res.competitionGroup }})
|
||||||
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ class HtmlParticipant:
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.id = id
|
self.id = id
|
||||||
self.finalist = None
|
self.finalist = None
|
||||||
|
self.club = None
|
||||||
|
|
||||||
def __eq__(self, o):
|
def __eq__(self, o):
|
||||||
if type(o) != HtmlParticipant:
|
if type(o) != HtmlParticipant:
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ from .place import Place
|
|||||||
|
|
||||||
|
|
||||||
class HtmlSingleCompetitionResult:
|
class HtmlSingleCompetitionResult:
|
||||||
def __init__(self, name: str, place: Place, finalist: bool):
|
def __init__(self, name: str, place: Place, finalist: bool, club: str):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.place = place
|
self.place = place
|
||||||
self.finalist = finalist
|
self.finalist = finalist
|
||||||
|
self.club = club
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
place = self.place
|
place = self.place
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ class Participant(Person):
|
|||||||
name: str,
|
name: str,
|
||||||
id: int,
|
id: int,
|
||||||
finalist: bool = None,
|
finalist: bool = None,
|
||||||
|
club: str = None,
|
||||||
):
|
):
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
self.id = id
|
self.id = id
|
||||||
self.finalist = finalist
|
self.finalist = finalist
|
||||||
|
self.club = club
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if self.finalist == True:
|
if self.finalist == True:
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class SingleParticipantResult:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
competitionClass: solo_turnier.competition_class.Class_t,
|
competitionClass: solo_turnier.competition_class.Class_t,
|
||||||
|
competitionGroup: solo_turnier.group.Group_t,
|
||||||
nativeClass: solo_turnier.competition_class.CompetitionClass,
|
nativeClass: solo_turnier.competition_class.CompetitionClass,
|
||||||
dance: str,
|
dance: str,
|
||||||
finalist: bool,
|
finalist: bool,
|
||||||
@@ -14,6 +15,7 @@ class SingleParticipantResult:
|
|||||||
nativePlace: Place = None,
|
nativePlace: Place = None,
|
||||||
):
|
):
|
||||||
self.competitionClass = competitionClass
|
self.competitionClass = competitionClass
|
||||||
|
self.competitionGroup = competitionGroup
|
||||||
self.nativeClass = nativeClass
|
self.nativeClass = nativeClass
|
||||||
self.dance = dance
|
self.dance = dance
|
||||||
self.finalist = finalist
|
self.finalist = finalist
|
||||||
@@ -27,3 +29,6 @@ class SingleParticipantResult:
|
|||||||
|
|
||||||
def getNativePlace(self) -> str:
|
def getNativePlace(self) -> str:
|
||||||
return str(self.nativePlace)
|
return str(self.nativePlace)
|
||||||
|
|
||||||
|
def isCombinedGroup(self) -> bool:
|
||||||
|
return isinstance(self.competitionGroup, solo_turnier.group.CombinedGroup)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class ResultExtractor:
|
|||||||
placeStr = result.results[person]
|
placeStr = result.results[person]
|
||||||
place = self._extractPlace(placeStr)
|
place = self._extractPlace(placeStr)
|
||||||
competitionResult = types.HtmlSingleCompetitionResult(
|
competitionResult = types.HtmlSingleCompetitionResult(
|
||||||
person.name, place, person.finalist
|
person.name, place, person.finalist, person.club
|
||||||
)
|
)
|
||||||
results.add(
|
results.add(
|
||||||
competitionGroup,
|
competitionGroup,
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ class Worker:
|
|||||||
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 mapping: %s", invertedGroupMapping)
|
||||||
|
|
||||||
idToParticipantMapping = self._invertIdMapping(importedData.htmlResults)
|
idToParticipantMapping = self._invertIdMapping(importedData.htmlResults)
|
||||||
self.l.log(5, "Id to participant mappting: %s", idToParticipantMapping)
|
self.l.log(5, "Id to participant mapping: %s", idToParticipantMapping)
|
||||||
|
|
||||||
totalResult = {}
|
totalResult = {}
|
||||||
|
|
||||||
@@ -96,6 +96,7 @@ class Worker:
|
|||||||
singleResult = solo_turnier.types.SingleParticipantResult(
|
singleResult = solo_turnier.types.SingleParticipantResult(
|
||||||
competitionClass=tup.class_,
|
competitionClass=tup.class_,
|
||||||
nativeClass=tup.class_,
|
nativeClass=tup.class_,
|
||||||
|
competitionGroup=tup.group,
|
||||||
dance=tup.dance,
|
dance=tup.dance,
|
||||||
finalist=singleHtmlResult.finalist,
|
finalist=singleHtmlResult.finalist,
|
||||||
place=singleHtmlResult.place,
|
place=singleHtmlResult.place,
|
||||||
@@ -329,7 +330,7 @@ class Worker:
|
|||||||
|
|
||||||
if id not in mapping:
|
if id not in mapping:
|
||||||
mapping[id] = solo_turnier.types.Participant(
|
mapping[id] = solo_turnier.types.Participant(
|
||||||
name=results[0].name, id=id
|
name=results[0].name, id=id, club=results[0].club
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if mapping[id].name != results[0].name or mapping[id].id != id:
|
if mapping[id].name != results[0].name or mapping[id].id != id:
|
||||||
|
|||||||
Reference in New Issue
Block a user