From bb2cccee4817bfc091224bd50c72da358c95b0bc Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Fri, 15 Dec 2023 14:46:11 +0100 Subject: [PATCH 1/7] Fix FoulComitted + Card for Wyscout v2 - No FoulComitted event was recorded when a card was given. To be consistent with the other data providers both a FoulCommittedEvent and CardEvent are recorded now. - Adds CardQualifiers to the FoulCommittedEvent. --- .../event/wyscout/deserializer_v2.py | 97 +++++++++++++------ kloppy/tests/test_wyscout.py | 2 +- 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py index d20392f8..4eee5709 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py @@ -5,6 +5,7 @@ from kloppy.domain import ( BodyPart, BodyPartQualifier, + CardQualifier, CardType, CounterAttackQualifier, Dimension, @@ -12,6 +13,7 @@ DuelQualifier, DuelType, EventDataset, + EventType, GoalkeeperQualifier, GoalkeeperActionType, Ground, @@ -208,6 +210,14 @@ def _parse_goalkeeper_save(raw_event) -> List[Qualifier]: def _parse_foul(raw_event: Dict) -> Dict: qualifiers = _generic_qualifiers(raw_event) + + if _has_tag(raw_event, wyscout_tags.RED_CARD): + qualifiers.append(CardQualifier(value=CardType.RED)) + elif _has_tag(raw_event, wyscout_tags.YELLOW_CARD): + qualifiers.append(CardQualifier(value=CardType.FIRST_YELLOW)) + elif _has_tag(raw_event, wyscout_tags.SECOND_YELLOW_CARD): + qualifiers.append(CardQualifier(value=CardType.SECOND_YELLOW)) + return { "result": None, "qualifiers": qualifiers, @@ -428,39 +438,47 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: "timestamp": raw_event["eventSec"], } - event = None + new_events = [] if raw_event["eventId"] == wyscout_events.SHOT.EVENT: shot_event_args = _parse_shot(raw_event, next_event) - event = self.event_factory.build_shot( + shot_event = self.event_factory.build_shot( **shot_event_args, **generic_event_args ) + new_events.append(shot_event) elif raw_event["eventId"] == wyscout_events.PASS.EVENT: pass_event_args = _parse_pass(raw_event, next_event) - event = self.event_factory.build_pass( + pass_event = self.event_factory.build_pass( **pass_event_args, **generic_event_args ) + new_events.append(pass_event) elif raw_event["eventId"] == wyscout_events.FOUL.EVENT: foul_event_args = _parse_foul(raw_event) - event = self.event_factory.build_foul_committed( + foul_event = self.event_factory.build_foul_committed( **foul_event_args, **generic_event_args ) + new_events.append(foul_event) if any( (_has_tag(raw_event, tag) for tag in wyscout_tags.CARD) ): card_event_args = _parse_card(raw_event) - event = self.event_factory.build_card( + card_event = self.event_factory.build_card( **card_event_args, **generic_event_args ) + new_events.append(card_event) elif raw_event["eventId"] == wyscout_events.INTERRUPTION.EVENT: ball_out_event_args = _parse_ball_out(raw_event) - event = self.event_factory.build_ball_out( + ball_out_event = self.event_factory.build_ball_out( **ball_out_event_args, **generic_event_args ) + new_events.append(ball_out_event) elif raw_event["eventId"] == wyscout_events.SAVE.EVENT: goalkeeper_save_args = _parse_goalkeeper_save(raw_event) - event = self.event_factory.build_goalkeeper_event( - **goalkeeper_save_args, **generic_event_args + goalkeeper_save_event = ( + self.event_factory.build_goalkeeper_event( + **goalkeeper_save_args, **generic_event_args + ) ) + new_events.append(goalkeeper_save_event) elif raw_event["eventId"] == wyscout_events.FREE_KICK.EVENT: set_piece_event_args = _parse_set_piece( raw_event, next_event @@ -469,16 +487,18 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: raw_event["subEventId"] in wyscout_events.FREE_KICK.PASS_TYPES ): - event = self.event_factory.build_pass( + fk_pass_event = self.event_factory.build_pass( **set_piece_event_args, **generic_event_args ) + new_events.append(fk_pass_event) elif ( raw_event["subEventId"] in wyscout_events.FREE_KICK.SHOT_TYPES ): - event = self.event_factory.build_shot( + fk_shot_event = self.event_factory.build_shot( **set_piece_event_args, **generic_event_args ) + new_events.append(fk_shot_event) elif ( raw_event["eventId"] == wyscout_events.OTHERS_ON_BALL.EVENT @@ -488,10 +508,11 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: == wyscout_events.OTHERS_ON_BALL.CLEARANCE ): clearance_event_args = _parse_clearance(raw_event) - event = self.event_factory.build_clearance( + clearance_event = self.event_factory.build_clearance( **clearance_event_args, **generic_event_args, ) + new_events.append(clearance_event) elif ( raw_event["subEventId"] == wyscout_events.OTHERS_ON_BALL.TOUCH @@ -500,34 +521,40 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: "result": None, "qualifiers": _generic_qualifiers(raw_event), } - event = self.event_factory.build_miscontrol( + miscontrol_event = self.event_factory.build_miscontrol( **miscontrol_event_args, **generic_event_args, ) + new_events.append(miscontrol_event) else: recovery_event_args = _parse_recovery(raw_event) - event = self.event_factory.build_recovery( + recovery_event = self.event_factory.build_recovery( **recovery_event_args, **generic_event_args ) + new_events.append(recovery_event) elif raw_event["eventId"] == wyscout_events.DUEL.EVENT: duel_event_args = _parse_duel(raw_event) - event = self.event_factory.build_duel( + duel_event = self.event_factory.build_duel( **duel_event_args, **generic_event_args ) + new_events.append(duel_event) elif raw_event["eventId"] not in [ wyscout_events.SAVE.EVENT, wyscout_events.OFFSIDE.EVENT, ]: # The events SAVE and OFFSIDE are already merged with PASS and SHOT events qualifiers = _generic_qualifiers(raw_event) - event = self.event_factory.build_generic( + generic_event = self.event_factory.build_generic( result=None, qualifiers=qualifiers, **generic_event_args, ) + new_events.append(generic_event) - # Since Interception is not an event in wyscout v2 but a tag for pass, touch and duel. Therefore, - # we convert those duels and touch events to an interception. And insert interception before passes. + # Wyscout v2 does not have a seperate event type for + # interceptions. Interceptions are recored by adding a tag to + # the next pass, touch or duel. Therefore, we convert events + # with this tag to an interception. if _has_tag(raw_event, wyscout_tags.INTERCEPTION): interception_event_args = _parse_interception( raw_event, next_event @@ -537,19 +564,29 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: **generic_event_args, ) - if event.event_type.name == "DUEL": - # when DuelEvent is interception, we need to overwrite this and the previous DuelEvent - events = events[:-1] - event = interception_event - elif event.event_name in ["recovery", "miscontrol"]: - event = interception_event - elif event.event_name in ["pass", "clearance"]: - events.append( - transformer.transform_event(interception_event) - ) - - if event and self.should_include_event(event): - events.append(transformer.transform_event(event)) + for i, new_event in enumerate(list(new_events)): + if new_event.event_type == EventType.DUEL: + # when DuelEvent is interception, we need to + # overwrite this and the previous DuelEvent + events = events[:-1] + new_events[i] = interception_event + elif new_event.event_type in [ + EventType.RECOVERY, + EventType.MISCONTROL, + ]: + # replace touch events + new_events[i] = interception_event + elif new_event.event_type in [ + EventType.PASS, + EventType.CLEARANCE, + ]: + # insert an interception event before interception passes + new_events.insert(i, interception_event) + + for new_event in new_events: + if self.should_include_event(new_event): + events.append(transformer.transform_event(new_event)) + new_events = [] metadata = Metadata( teams=[home_team, away_team], diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index ed66416f..14f87720 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -86,7 +86,7 @@ def test_correct_v2_deserialization(self, event_v2_data: Path): == DuelType.SLIDING_TACKLE ) assert ( - dataset.events[301].get_qualifier_value(GoalkeeperQualifier) + dataset.events[302].get_qualifier_value(GoalkeeperQualifier) == GoalkeeperActionType.SAVE ) From e340d05b975a06c525da171bcd709ae34f7c9cfc Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Fri, 22 Dec 2023 09:30:09 +0100 Subject: [PATCH 2/7] Avoid duplicate event ids in Wyscout v2 Adds a prefix to the ID of synthetic events to avoid having multiple events with the same ID. --- .../event/wyscout/deserializer_v2.py | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py index 4eee5709..7193069c 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py @@ -1,6 +1,6 @@ import json import logging -from typing import Dict, List, Tuple, NamedTuple, IO +from typing import Dict, List, NamedTuple, IO from kloppy.domain import ( BodyPart, @@ -8,7 +8,6 @@ CardQualifier, CardType, CounterAttackQualifier, - Dimension, DuelResult, DuelQualifier, DuelType, @@ -31,7 +30,6 @@ SetPieceQualifier, SetPieceType, ShotResult, - TakeOnResult, Team, ) from kloppy.utils import performance_logging @@ -422,7 +420,7 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: ) generic_event_args = { - "event_id": raw_event["id"], + "event_id": str(raw_event["id"]), "raw_event": raw_event, "coordinates": Point( x=float(raw_event["positions"][0]["x"]), @@ -461,8 +459,15 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: (_has_tag(raw_event, tag) for tag in wyscout_tags.CARD) ): card_event_args = _parse_card(raw_event) + card_event_id = ( + f"card-{generic_event_args['event_id']}" + ) card_event = self.event_factory.build_card( - **card_event_args, **generic_event_args + **card_event_args, + **{ + **generic_event_args, + "event_id": card_event_id, + }, ) new_events.append(card_event) elif raw_event["eventId"] == wyscout_events.INTERRUPTION.EVENT: @@ -559,34 +564,48 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: interception_event_args = _parse_interception( raw_event, next_event ) - interception_event = self.event_factory.build_interception( - **interception_event_args, - **generic_event_args, - ) for i, new_event in enumerate(list(new_events)): if new_event.event_type == EventType.DUEL: # when DuelEvent is interception, we need to # overwrite this and the previous DuelEvent events = events[:-1] - new_events[i] = interception_event + new_events[ + i + ] = self.event_factory.build_interception( + **interception_event_args, + **generic_event_args, + ) elif new_event.event_type in [ EventType.RECOVERY, EventType.MISCONTROL, ]: # replace touch events - new_events[i] = interception_event + new_events[ + i + ] = self.event_factory.build_interception( + **interception_event_args, + **generic_event_args, + ) elif new_event.event_type in [ EventType.PASS, EventType.CLEARANCE, ]: # insert an interception event before interception passes + generic_event_args[ + "event_id" + ] = f"interception-{generic_event_args['event_id']}" + interception_event = ( + self.event_factory.build_interception( + **interception_event_args, + **generic_event_args, + ) + ) new_events.insert(i, interception_event) for new_event in new_events: if self.should_include_event(new_event): events.append(transformer.transform_event(new_event)) - new_events = [] metadata = Metadata( teams=[home_team, away_team], From 67403eeaedcc1b420f8c9bf807102c7217d34a51 Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Fri, 22 Dec 2023 09:31:41 +0100 Subject: [PATCH 3/7] Refactor Wyscout tests --- kloppy/tests/conftest.py | 2 +- kloppy/tests/files/wyscout_events_v3.json | 8 +- kloppy/tests/test_wyscout.py | 185 ++++++++++++++++------ 3 files changed, 144 insertions(+), 51 deletions(-) diff --git a/kloppy/tests/conftest.py b/kloppy/tests/conftest.py index 0ff67a20..d79ee688 100644 --- a/kloppy/tests/conftest.py +++ b/kloppy/tests/conftest.py @@ -5,6 +5,6 @@ import pytest -@pytest.fixture +@pytest.fixture(scope="session") def base_dir() -> Path: return Path(__file__).parent diff --git a/kloppy/tests/files/wyscout_events_v3.json b/kloppy/tests/files/wyscout_events_v3.json index 29459b72..bf0f7273 100644 --- a/kloppy/tests/files/wyscout_events_v3.json +++ b/kloppy/tests/files/wyscout_events_v3.json @@ -590,7 +590,7 @@ "videoTimestamp": "8.148438" }, { - "id": 663291840, + "id": 663291841, "type": { "primary": "duel", "secondary": [ @@ -662,7 +662,7 @@ "videoTimestamp": "8.148438" }, { - "id": 663291840, + "id": 663291842, "type": { "primary": "duel", "secondary": [ @@ -724,7 +724,7 @@ "videoTimestamp": "8.148438" }, { - "id": 663291842, + "id": 663291843, "minute": 0, "matchId": 2852835, "matchPeriod": "1H", @@ -4148,4 +4148,4 @@ } }, "meta": [] -} \ No newline at end of file +} diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index 14f87720..2689875a 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -3,93 +3,186 @@ import pytest from kloppy.domain import ( Point, + EventDataset, SetPieceType, SetPieceQualifier, + DatasetType, DuelQualifier, DuelType, EventType, GoalkeeperQualifier, GoalkeeperActionType, + CardQualifier, + CardType, ) from kloppy import wyscout -class TestWyscout: - """""" +@pytest.fixture(scope="session") +def event_v2_data(base_dir: Path) -> Path: + return base_dir / "files" / "wyscout_events_v2.json" - @pytest.fixture - def event_v3_data(self, base_dir): - return base_dir / "files/wyscout_events_v3.json" - @pytest.fixture - def event_v2_data(self, base_dir): - return base_dir / "files/wyscout_events_v2.json" +@pytest.fixture(scope="session") +def event_v3_data(base_dir: Path) -> Path: + return base_dir / "files" / "wyscout_events_v3.json" - def test_correct_v3_deserialization(self, event_v3_data: Path): + +def test_correct_auto_recognize_deserialization( + event_v2_data: Path, event_v3_data: Path +): + dataset = wyscout.load(event_data=event_v2_data, coordinates="wyscout") + assert dataset.records[2].coordinates == Point(29.0, 6.0) + dataset = wyscout.load(event_data=event_v3_data, coordinates="wyscout") + assert dataset.records[2].coordinates == Point(36.0, 78.0) + + +class TestWyscoutV2: + """Tests related to deserialization of Wyscout V2 data.""" + + @pytest.fixture(scope="class") + def dataset(self, event_v2_data) -> EventDataset: + """Load Wyscout V2 event dataset""" dataset = wyscout.load( - event_data=event_v3_data, + event_data=event_v2_data, coordinates="wyscout", - data_version="V3", + data_version="V2", ) - assert dataset.records[2].coordinates == Point(36.0, 78.0) + assert dataset.dataset_type == DatasetType.EVENT + return dataset + + def test_miscontrol_event(self, dataset: EventDataset): + miscontrol_event = dataset.get_event_by_id("190078351") + assert miscontrol_event.event_type == EventType.MISCONTROL + assert dataset.events[11].event_type == EventType.MISCONTROL + + def test_interception_event(self, dataset: EventDataset): + # A touch or duel with "interception" tag should be converted to an interception event + interception_event = dataset.get_event_by_id("190079090") + assert interception_event.event_type == EventType.INTERCEPTION + # Other events with "interception" tag should be split in two events + clearance_event = dataset.get_event_by_id("190079171") + assert clearance_event.event_type == EventType.CLEARANCE + interception_event = dataset.get_event_by_id("interception-190079171") + assert interception_event.event_type == EventType.INTERCEPTION + + def test_duel_event(self, dataset: EventDataset): + ground_duel_event = dataset.get_event_by_id("190078379") + assert ground_duel_event.event_type == EventType.DUEL assert ( - dataset.events[10].get_qualifier_value(GoalkeeperQualifier) - == GoalkeeperActionType.SAVE + ground_duel_event.get_qualifier_value(DuelQualifier) + == DuelType.GROUND ) + aerial_duel_event = dataset.get_event_by_id("190078381") + assert aerial_duel_event.event_type == EventType.DUEL assert ( - dataset.events[4].get_qualifier_value(SetPieceQualifier) - == SetPieceType.CORNER_KICK + aerial_duel_event.get_qualifier_values(DuelQualifier)[1].value + == DuelType.AERIAL ) - assert dataset.events[5].event_type == EventType.FOUL_COMMITTED + sliding_tackle_duel_event = dataset.get_event_by_id("190079260") + assert sliding_tackle_duel_event.event_type == EventType.DUEL assert ( - dataset.events[6].get_qualifier_value(DuelQualifier) - == DuelType.GROUND + sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[ + 2 + ].value + == DuelType.SLIDING_TACKLE ) + + def test_goalkeeper_event(self, dataset: EventDataset): + goalkeeper_event = dataset.get_event_by_id("190079010") + assert goalkeeper_event.event_type == EventType.GOALKEEPER assert ( - dataset.events[7].get_qualifier_values(DuelQualifier)[1].value - == DuelType.AERIAL + goalkeeper_event.get_qualifier_value(GoalkeeperQualifier) + == GoalkeeperActionType.SAVE ) + + def test_foul_committed_event(self, dataset: EventDataset): + foul_committed_event = dataset.get_event_by_id("190079289") + assert foul_committed_event.event_type == EventType.FOUL_COMMITTED assert ( - dataset.events[8].get_qualifier_values(DuelQualifier)[2].value - == DuelType.SLIDING_TACKLE + foul_committed_event.get_qualifier_value(CardQualifier) + == CardType.FIRST_YELLOW ) - assert dataset.events[9].event_type == EventType.CLEARANCE - assert dataset.events[12].event_type == EventType.INTERCEPTION - assert dataset.events[14].event_type == EventType.TAKE_ON + card_event = dataset.get_event_by_id("card-190079289") + assert card_event.event_type == EventType.CARD - def test_correct_normalized_v3_deserialization(self, event_v3_data: Path): - dataset = wyscout.load(event_data=event_v3_data, data_version="V3") - assert dataset.records[2].coordinates == Point(0.36, 0.78) + def test_correct_normalized_deserialization(self, event_v2_data: Path): + dataset = wyscout.load(event_data=event_v2_data, data_version="V2") + assert dataset.records[2].coordinates == Point(0.29, 0.06) - def test_correct_v2_deserialization(self, event_v2_data: Path): + +class TestWyscoutV3: + """Tests related to deserialization of Wyscout V3 data.""" + + @pytest.fixture(scope="class") + def dataset(self, event_v3_data: Path) -> EventDataset: + """Load Wyscout V3 event dataset""" dataset = wyscout.load( - event_data=event_v2_data, + event_data=event_v3_data, coordinates="wyscout", - data_version="V2", + data_version="V3", + ) + assert dataset.dataset_type == DatasetType.EVENT + return dataset + + def test_coordinates(self, dataset: EventDataset): + assert dataset.records[2].coordinates == Point(36.0, 78.0) + + def test_normalized_deserialization(self, event_v3_data: Path): + dataset = wyscout.load(event_data=event_v3_data, data_version="V3") + assert dataset.records[2].coordinates == Point(0.36, 0.78) + + def test_goalkeeper_event(self, dataset: EventDataset): + goalkeeper_event = dataset.get_event_by_id(1331979498) + assert goalkeeper_event.event_type == EventType.GOALKEEPER + assert ( + goalkeeper_event.get_qualifier_value(GoalkeeperQualifier) + == GoalkeeperActionType.SAVE ) - assert dataset.records[2].coordinates == Point(29.0, 6.0) - assert dataset.events[11].event_type == EventType.MISCONTROL - assert dataset.events[34].event_type == EventType.INTERCEPTION - assert dataset.events[143].event_type == EventType.CLEARANCE + def test_shot_event(self, dataset: EventDataset): + shot_event = dataset.get_event_by_id(663291840) + assert shot_event.event_type == EventType.SHOT assert ( - dataset.events[39].get_qualifier_value(DuelQualifier) + shot_event.get_qualifier_value(SetPieceQualifier) + == SetPieceType.CORNER_KICK + ) + + def test_foul_committed_event(self, dataset: EventDataset): + foul_committed_event = dataset.get_event_by_id(1343788476) + assert foul_committed_event.event_type == EventType.FOUL_COMMITTED + + def test_duel_event(self, dataset: EventDataset): + ground_duel_event = dataset.get_event_by_id(663291421) + assert ground_duel_event.event_type == EventType.DUEL + assert ( + ground_duel_event.get_qualifier_value(DuelQualifier) == DuelType.GROUND ) + aerial_duel_event = dataset.get_event_by_id(663291841) + assert aerial_duel_event.event_type == EventType.DUEL assert ( - dataset.events[43].get_qualifier_values(DuelQualifier)[1].value + aerial_duel_event.get_qualifier_values(DuelQualifier)[1].value == DuelType.AERIAL ) + sliding_tackle_duel_event = dataset.get_event_by_id(663291842) + assert sliding_tackle_duel_event.event_type == EventType.DUEL assert ( - dataset.events[268].get_qualifier_values(DuelQualifier)[2].value + sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[ + 2 + ].value == DuelType.SLIDING_TACKLE ) - assert ( - dataset.events[302].get_qualifier_value(GoalkeeperQualifier) - == GoalkeeperActionType.SAVE - ) - def test_correct_auto_recognize_deserialization(self, event_v2_data: Path): - dataset = wyscout.load(event_data=event_v2_data, coordinates="wyscout") - assert dataset.records[2].coordinates == Point(29.0, 6.0) + def test_clearance_event(self, dataset: EventDataset): + clearance_event = dataset.get_event_by_id(663291843) + assert clearance_event.event_type == EventType.CLEARANCE + + def test_interception_event(self, dataset: EventDataset): + interception_event = dataset.get_event_by_id(1397082780) + assert interception_event.event_type == EventType.INTERCEPTION + + def test_take_on_event(self, dataset: EventDataset): + take_on_event = dataset.get_event_by_id(139800000) + assert take_on_event.event_type == EventType.TAKE_ON From ea5715bd47634df6a8d3956d0ec32fc6bd13291e Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Fri, 22 Dec 2023 10:24:56 +0100 Subject: [PATCH 4/7] Typo fixes Wyscout deserializer --- kloppy/infra/serializers/event/wyscout/deserializer_v2.py | 4 ++-- kloppy/tests/test_wyscout.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py index 7193069c..10702dac 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py @@ -556,8 +556,8 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: ) new_events.append(generic_event) - # Wyscout v2 does not have a seperate event type for - # interceptions. Interceptions are recored by adding a tag to + # Wyscout v2 does not have a separate event type for + # interceptions. Interceptions are recorded by adding a tag to # the next pass, touch or duel. Therefore, we convert events # with this tag to an interception. if _has_tag(raw_event, wyscout_tags.INTERCEPTION): diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index 2689875a..ad00cc49 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -55,7 +55,6 @@ def dataset(self, event_v2_data) -> EventDataset: def test_miscontrol_event(self, dataset: EventDataset): miscontrol_event = dataset.get_event_by_id("190078351") assert miscontrol_event.event_type == EventType.MISCONTROL - assert dataset.events[11].event_type == EventType.MISCONTROL def test_interception_event(self, dataset: EventDataset): # A touch or duel with "interception" tag should be converted to an interception event From a98cac11d40c2bfaa97bb266278d711b60d70ec6 Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Tue, 26 Dec 2023 19:58:25 +0100 Subject: [PATCH 5/7] linting --- kloppy/tests/test_wyscout.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index 19d45a3c..1c4496ad 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -168,9 +168,7 @@ def test_duel_event(self, dataset: EventDataset): sliding_tackle_duel_event = dataset.get_event_by_id(663291842) assert sliding_tackle_duel_event.event_type == EventType.DUEL assert ( - sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[ - 2 - ] + sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[2] == DuelType.SLIDING_TACKLE ) From 38f6abaf898372e96017b247fd32dd5e9f6d4e09 Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Tue, 26 Dec 2023 20:00:46 +0100 Subject: [PATCH 6/7] Fix previous merge commit --- kloppy/tests/test_wyscout.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index 1c4496ad..fa980bda 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -76,15 +76,13 @@ def test_duel_event(self, dataset: EventDataset): aerial_duel_event = dataset.get_event_by_id("190078381") assert aerial_duel_event.event_type == EventType.DUEL assert ( - aerial_duel_event.get_qualifier_values(DuelQualifier)[1].value + aerial_duel_event.get_qualifier_values(DuelQualifier)[1] == DuelType.AERIAL ) sliding_tackle_duel_event = dataset.get_event_by_id("190079260") assert sliding_tackle_duel_event.event_type == EventType.DUEL assert ( - sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[ - 2 - ].value + sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[2] == DuelType.SLIDING_TACKLE ) From 184de78dbdba69570053c5830470984d26177976 Mon Sep 17 00:00:00 2001 From: koenvo Date: Fri, 29 Dec 2023 10:53:20 +0100 Subject: [PATCH 7/7] Fix merge --- kloppy/tests/test_wyscout.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index 39a74441..c1d0f42b 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -54,6 +54,13 @@ def dataset(self, event_v2_data) -> EventDataset: assert dataset.dataset_type == DatasetType.EVENT return dataset + def test_shot_event(self, dataset: EventDataset): + shot_event = dataset.get_event_by_id("190079151") + assert ( + shot_event.get_qualifier_value(BodyPartQualifier) + == BodyPart.RIGHT_FOOT + ) + def test_miscontrol_event(self, dataset: EventDataset): miscontrol_event = dataset.get_event_by_id("190078351") assert miscontrol_event.event_type == EventType.MISCONTROL @@ -169,11 +176,6 @@ def test_duel_event(self, dataset: EventDataset): assert sliding_tackle_duel_event.event_type == EventType.DUEL assert ( sliding_tackle_duel_event.get_qualifier_values(DuelQualifier)[2] - dataset.events[118].get_qualifier_value(BodyPartQualifier) - == BodyPart.RIGHT_FOOT - ) - assert ( - dataset.events[268].get_qualifier_values(DuelQualifier)[2] == DuelType.SLIDING_TACKLE )