Skip to content

Commit

Permalink
add more fields to stage_score (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
cahna authored Jan 26, 2023
1 parent 015da31 commit 62ca3ca
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 18 deletions.
7 changes: 7 additions & 0 deletions hitfactorpy/parsers/match_report/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ def parse_power_factor(s: str) -> PowerFactor:
return PowerFactor.UNKNOWN


def parse_power_factor_default_none(s: str | None) -> PowerFactor | None:
if s and (parsed_power_factor := parse_power_factor(s)):
if parsed_power_factor and parsed_power_factor != PowerFactor.UNKNOWN:
return parsed_power_factor
return None


def parse_member_number(s: str):
return re.sub(r"[^0-9A-Z]", "", _sanitize_string(s).upper())

Expand Down
13 changes: 10 additions & 3 deletions hitfactorpy/parsers/match_report/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ class ParsedStage:
class ParsedStageScore:
"""Stage score parsed from match report"""

competitor_id: Optional[int] = None
stage_id: Optional[int] = None
competitor_id: Optional[int] = None
dq: bool = False
dnf: bool = False
a: int = 0
b: int = 0
c: int = 0
Expand All @@ -58,8 +60,13 @@ class ParsedStageScore:
t4: float = 0.0
t5: float = 0.0
time: float = 0.0
dq: bool = False
dnf: bool = False
raw_points: Optional[float] = None
penalty_points: Optional[float] = None
total_points: Optional[float] = None
hit_factor: Optional[float] = None
stage_points: Optional[float] = None
stage_place: Optional[int] = None
stage_power_factor: Optional[PowerFactor] = None


@dataclass(frozen=True)
Expand Down
43 changes: 34 additions & 9 deletions hitfactorpy/parsers/match_report/pandas/stage_score.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pandas._typing import FilePath, ReadCsvBuffer
from pandas.errors import EmptyDataError

from ..fields import parse_boolean, parse_power_factor
from ..fields import parse_boolean, parse_power_factor_default_none
from ..models import ParsedStageScore

_logger = logging.getLogger(__name__)
Expand All @@ -28,6 +28,8 @@ class StageScoreColumnName(str, Enum):
M = "Miss"
NS = "No Shoot"
PROC = "Procedural"
DOUBLE_POPPERS = "Double Poppers"
DOUBLE_POPPER_MISS = "Double Popper Miss"
LATE_SHOT = "Late Shot"
EXTRA_SHOT = "Extra Shot"
EXTRA_HIT = "Extra Hit"
Expand All @@ -42,13 +44,16 @@ class StageScoreColumnName(str, Enum):
TIME = "Time"
RAW_POINTS = "Raw Points"
TOTAL_POINTS = "Total Points"
HIT_FACTOR = "Hit Factor"
STAGE_POINTS = "Stage Points"
STAGE_PLACE = "Stage Place"
STAGE_POWER_FACTOR = "Stage Power Factor"


CSV_CONVERTERS: Mapping[str, Callable[[str], Any]] = {
StageScoreColumnName.DQ: parse_boolean,
StageScoreColumnName.DNF: parse_boolean,
StageScoreColumnName.STAGE_POWER_FACTOR: parse_power_factor,
StageScoreColumnName.STAGE_POWER_FACTOR: parse_power_factor_default_none,
}


Expand All @@ -59,7 +64,6 @@ def read_stage_scores_csv(filepath_or_buffer: FilePath | ReadCsvBuffer[bytes] |
index_col=None,
converters=CSV_CONVERTERS,
)
# df['hit_factor'] = (df['A'] * 5) # TODO
return df


Expand All @@ -75,6 +79,8 @@ def parse_stage_scores(stage_scores_csv: str) -> List[ParsedStageScore]:
ParsedStageScore(
stage_id=stage_id,
competitor_id=competitor_id,
dq=dq,
dnf=dnf,
a=a,
b=b,
c=c,
Expand All @@ -93,12 +99,19 @@ def parse_stage_scores(stage_scores_csv: str) -> List[ParsedStageScore]:
t4=t4,
t5=t5,
time=time,
dq=dq,
dnf=dnf,
raw_points=raw_points,
penalty_points=penalty_points,
total_points=total_points,
hit_factor=hit_factor,
stage_points=stage_points,
stage_place=stage_place,
stage_power_factor=stage_power_factor,
)
for (
stage_id,
competitor_id,
dq,
dnf,
a,
b,
c,
Expand All @@ -117,11 +130,18 @@ def parse_stage_scores(stage_scores_csv: str) -> List[ParsedStageScore]:
t4,
t5,
time,
dq,
dnf,
raw_points,
penalty_points,
total_points,
hit_factor,
stage_points,
stage_place,
stage_power_factor,
) in zip(
df[StageScoreColumnName.STAGE_ID],
df[StageScoreColumnName.COMPETITOR_ID],
df[StageScoreColumnName.DQ],
df[StageScoreColumnName.DNF],
df[StageScoreColumnName.A],
df[StageScoreColumnName.B],
df[StageScoreColumnName.C],
Expand All @@ -140,8 +160,13 @@ def parse_stage_scores(stage_scores_csv: str) -> List[ParsedStageScore]:
df[StageScoreColumnName.T4],
df[StageScoreColumnName.T5],
df[StageScoreColumnName.TIME],
df[StageScoreColumnName.DQ],
df[StageScoreColumnName.DNF],
df[StageScoreColumnName.RAW_POINTS],
df[StageScoreColumnName.PENALTY_POINTS],
df[StageScoreColumnName.TOTAL_POINTS],
df[StageScoreColumnName.HIT_FACTOR],
df[StageScoreColumnName.STAGE_POINTS],
df[StageScoreColumnName.STAGE_PLACE],
df[StageScoreColumnName.STAGE_POWER_FACTOR],
)
]
return stage_scores
23 changes: 17 additions & 6 deletions hitfactorpy/parsers/match_report/strict/stage_score.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from enum import Enum, unique
from typing import List, Optional

from ....enums import PowerFactor
from ...csv_utils import parse_csv_row, parse_float_value, parse_int_value
from ..fields import parse_boolean
from ..fields import parse_boolean, parse_power_factor, parse_power_factor_default_none
from ..models import ParsedStageScore

_logger = logging.getLogger(__name__)
Expand All @@ -24,6 +25,8 @@ class StageScoreColumn(int, Enum):
M = 9
NS = 10
PROC = 11
DOUBLE_POPPERS = 12
DOUBLE_POPPER_MISS = 13
LATE_SHOT = 14
EXTRA_SHOT = 15
EXTRA_HIT = 16
Expand All @@ -38,6 +41,10 @@ class StageScoreColumn(int, Enum):
TIME = 25
RAW_POINTS = 26
TOTAL_POINTS = 27
HIT_FACTOR = 28
STAGE_POINTS = 29
STAGE_PLACE = 30
STAGE_POWER_FACTOR = 31


def check_stage_score_columns(parsed_columns: List[str], fail_on_mismatch=False):
Expand All @@ -61,9 +68,10 @@ def parse_match_report_stage_score_lines(
for line in stage_lines:
row = parse_csv_row(line)
stage = ParsedStageScore(
# Integer attributes
stage_id=parse_int_value(row[StageScoreColumn.STAGE_ID].strip()),
competitor_id=parse_int_value(row[StageScoreColumn.SHOOTER_ID].strip()),
dq=parse_boolean(row[StageScoreColumn.DQ].strip()),
dnf=parse_boolean(row[StageScoreColumn.DNF].strip()),
a=parse_int_value(row[StageScoreColumn.A].strip()) or 0,
b=parse_int_value(row[StageScoreColumn.B].strip()) or 0,
c=parse_int_value(row[StageScoreColumn.C].strip()) or 0,
Expand All @@ -76,16 +84,19 @@ def parse_match_report_stage_score_lines(
extra_shot=parse_int_value(row[StageScoreColumn.EXTRA_SHOT].strip()) or 0,
extra_hit=parse_int_value(row[StageScoreColumn.EXTRA_HIT].strip()) or 0,
other_penalty=parse_int_value(row[StageScoreColumn.OTHER_PENALTY].strip()) or 0,
# Float attributes
t1=parse_float_value(row[StageScoreColumn.T1].strip()) or 0.0,
t2=parse_float_value(row[StageScoreColumn.T2].strip()) or 0.0,
t3=parse_float_value(row[StageScoreColumn.T3].strip()) or 0.0,
t4=parse_float_value(row[StageScoreColumn.T4].strip()) or 0.0,
t5=parse_float_value(row[StageScoreColumn.T5].strip()) or 0.0,
time=parse_float_value(row[StageScoreColumn.TIME].strip()) or 0.0,
# Boolean attributes
dq=parse_boolean(row[StageScoreColumn.DQ].strip()),
dnf=parse_boolean(row[StageScoreColumn.DNF].strip()),
raw_points=parse_float_value(row[StageScoreColumn.RAW_POINTS].strip()),
penalty_points=parse_float_value(row[StageScoreColumn.PENALTY_POINTS].strip()),
total_points=parse_float_value(row[StageScoreColumn.TOTAL_POINTS].strip()),
hit_factor=parse_float_value(row[StageScoreColumn.HIT_FACTOR].strip()),
stage_points=parse_float_value(row[StageScoreColumn.STAGE_POINTS].strip()),
stage_place=parse_int_value(row[StageScoreColumn.STAGE_PLACE].strip()),
stage_power_factor=parse_power_factor_default_none(row[StageScoreColumn.STAGE_POWER_FACTOR].strip()),
)
stages.append(stage)
return stages
7 changes: 7 additions & 0 deletions tests/test_parsers_match_report/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ def assert_example_match_report(report: ParsedMatchReport):
assert report.stage_scores[0].t4 == approx(0)
assert report.stage_scores[0].t5 == approx(0)
assert report.stage_scores[0].time == approx(17.34)
assert report.stage_scores[0].raw_points == approx(150.0)
assert report.stage_scores[0].penalty_points == approx(0)
assert report.stage_scores[0].total_points == approx(150.0)
assert report.stage_scores[0].hit_factor == approx(8.6505)
assert report.stage_scores[0].stage_points == approx(160.0)
assert report.stage_scores[0].stage_place == 1
assert report.stage_scores[0].dq is False
assert report.stage_scores[0].dnf is False
assert report.stage_scores[0].stage_power_factor is None

# Verify a stage score with a DQ
assert report.stage_scores[37].dq is True
Expand Down
14 changes: 14 additions & 0 deletions tests/test_parsers_match_report/test_field_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ def test_parse_power_factor(test_input, expected):
assert fields.parse_power_factor(test_input) == expected


@pytest.mark.parametrize(
"test_input,expected",
[
("mAjOr", PowerFactor.MAJOR),
("minor", PowerFactor.MINOR),
("", None),
(None, None),
("y", None),
],
)
def test_parse_power_factor_default_none(test_input, expected):
assert fields.parse_power_factor_default_none(test_input) == expected


@pytest.mark.parametrize(
"test_input,expected",
[
Expand Down

0 comments on commit 62ca3ca

Please sign in to comment.