|
import os |
|
|
|
import pandas as pd |
|
import pytest |
|
import socceraction.spadl.config as spadlcfg |
|
from socceraction.data.opta import OptaLoader |
|
from socceraction.data.opta import parsers as optaparsers |
|
from socceraction.data.opta.loader import _extract_ids_from_path |
|
from socceraction.spadl import SPADLSchema |
|
from socceraction.spadl import opta as opta |
|
|
|
|
|
class TestSpadlConvertor: |
|
def setup_method(self) -> None: |
|
data_dir = os.path.join(os.path.dirname(__file__), os.pardir, "datasets", "opta") |
|
|
|
loader = OptaLoader( |
|
root=data_dir, |
|
parser="xml", |
|
feeds={ |
|
"f7": "f7-{competition_id}-{season_id}-{game_id}-matchresults.xml", |
|
"f24": "f24-{competition_id}-{season_id}-{game_id}-eventdetails.xml", |
|
}, |
|
) |
|
|
|
self.events = loader.events(1009316) |
|
self.actions = opta.convert_to_actions(self.events, 174) |
|
|
|
def test_convert_to_actions(self) -> None: |
|
assert len(self.actions) > 0 |
|
SPADLSchema.validate(self.actions) |
|
assert (self.actions.game_id == 1009316).all() |
|
assert ((self.actions.team_id == 174) | (self.actions.team_id == 957)).all() |
|
|
|
def test_convert_goalkick(self) -> None: |
|
event = pd.DataFrame( |
|
[ |
|
{ |
|
"game_id": 318175, |
|
"event_id": 1619686768, |
|
"type_id": 1, |
|
"period_id": 1, |
|
"minute": 2, |
|
"second": 14, |
|
"timestamp": "2010-01-27 19:47:14", |
|
"player_id": 8786, |
|
"team_id": 157, |
|
"outcome": False, |
|
"start_x": 5.0, |
|
"start_y": 37.0, |
|
"end_x": 73.0, |
|
"end_y": 18.7, |
|
"assist": False, |
|
"keypass": False, |
|
"qualifiers": { |
|
56: "Right", |
|
141: "18.7", |
|
124: True, |
|
140: "73.0", |
|
1: True, |
|
}, |
|
"type_name": "pass", |
|
} |
|
] |
|
) |
|
action = opta.convert_to_actions(event, 0).iloc[0] |
|
assert action["type_id"] == spadlcfg.actiontypes.index("goalkick") |
|
|
|
def test_convert_own_goal(self) -> None: |
|
event = pd.DataFrame( |
|
[ |
|
{ |
|
"game_id": 318175, |
|
"event_id": 1619686768, |
|
"type_id": 16, |
|
"period_id": 1, |
|
"minute": 2, |
|
"second": 14, |
|
"timestamp": "2010-01-27 19:47:14", |
|
"player_id": 8786, |
|
"team_id": 157, |
|
"outcome": 1, |
|
"start_x": 5.0, |
|
"start_y": 37.0, |
|
"end_x": 73.0, |
|
"end_y": 18.7, |
|
"assist": False, |
|
"keypass": False, |
|
"qualifiers": {28: True}, |
|
"type_name": "goal", |
|
} |
|
] |
|
) |
|
action = opta.convert_to_actions(event, 0).iloc[0] |
|
assert action["type_id"] == spadlcfg.actiontypes.index("bad_touch") |
|
assert action["result_id"] == spadlcfg.results.index("owngoal") |
|
|
|
def test_fix_deflected_passes(self) -> None: |
|
|
|
deflected_pass = self.actions.loc[self.actions.original_event_id == 2016736289].iloc[0] |
|
assert deflected_pass["result_id"] == spadlcfg.results.index("success") |
|
assert deflected_pass["end_x"] == (100 - 70.6) / 100 * spadlcfg.field_length |
|
assert deflected_pass["end_y"] == (100 - 72.6) / 100 * spadlcfg.field_width |
|
|
|
tackle = self.actions.loc[self.actions.original_event_id == 1820711400].iloc[0] |
|
assert tackle["result_id"] == spadlcfg.results.index("fail") |
|
|
|
|
|
def test_extract_lineups_f7xml() -> None: |
|
data_dir = os.path.join(os.path.dirname(__file__), os.pardir, "datasets", "opta") |
|
parser = optaparsers.F7XMLParser(os.path.join(data_dir, "f7-23-2018-1009316-matchresults.xml")) |
|
lineups = parser.extract_lineups() |
|
for _, lineup in lineups.items(): |
|
|
|
assert sum(p["is_starter"] for p in lineup["players"].values()) == 11 |
|
|
|
assert sum(p["minutes_played"] for p in lineup["players"].values()) == 11 * 96 |
|
|
|
|
|
def test_extract_lineups_f9json() -> None: |
|
data_dir = os.path.join(os.path.dirname(__file__), os.pardir, "datasets", "opta") |
|
parser = optaparsers.F9JSONParser(os.path.join(data_dir, "match-2017-8-918893.json")) |
|
lineups = parser.extract_lineups() |
|
for _, lineup in lineups.items(): |
|
print([p["minutes_played"] for p in lineup["players"].values()]) |
|
|
|
assert sum(p["is_starter"] for p in lineup["players"].values()) == 11 |
|
|
|
assert sum(p["minutes_played"] for p in lineup["players"].values()) == 11 * 96 |
|
|
|
|
|
def test_extract_ids_from_path() -> None: |
|
glob_pattern = "{competition_id}-{season_id}/{game_id}.json" |
|
ffp = "blah/blah/blah/1-2021/1234.json" |
|
ids = _extract_ids_from_path(ffp, glob_pattern) |
|
assert ids["competition_id"] == 1 |
|
assert ids["season_id"] == 2021 |
|
assert ids["game_id"] == 1234 |
|
ffp = "blah/blah/blah/1kldfa78394kdf-2021/1234.json" |
|
ids = _extract_ids_from_path(ffp, glob_pattern) |
|
assert ids["competition_id"] == "1kldfa78394kdf" |
|
assert ids["season_id"] == 2021 |
|
assert ids["game_id"] == 1234 |
|
ffp = "blah/blah/blah/EPL-2021/1234.json" |
|
ids = _extract_ids_from_path(ffp, glob_pattern) |
|
assert ids["competition_id"] == "EPL" |
|
assert ids["season_id"] == 2021 |
|
assert ids["game_id"] == 1234 |
|
|
|
|
|
def test_extract_ids_from_path_with_incorrect_pattern() -> None: |
|
glob_pattern = "{competition_id}-{season_id}/{game_id}.json" |
|
ffp = "blah/blah/blah/1/2021/g1234.json" |
|
with pytest.raises(ValueError): |
|
_extract_ids_from_path(ffp, glob_pattern) |
|
|