diff --git a/kloppy/domain/models/event.py b/kloppy/domain/models/event.py index 488f9ab4..d05c5b83 100644 --- a/kloppy/domain/models/event.py +++ b/kloppy/domain/models/event.py @@ -217,6 +217,7 @@ class EventType(Enum): BALL_OUT (EventType): FOUL_COMMITTED (EventType): GOALKEEPER (EventType): + PRESSURE (EventType): FORMATION_CHANGE (EventType): """ @@ -238,6 +239,7 @@ class EventType(Enum): BALL_OUT = "BALL_OUT" FOUL_COMMITTED = "FOUL_COMMITTED" GOALKEEPER = "GOALKEEPER" + PRESSURE = "PRESSURE" FORMATION_CHANGE = "FORMATION_CHANGE" def __repr__(self): @@ -1024,6 +1026,24 @@ class GoalkeeperEvent(Event): event_name: str = "goalkeeper" +@dataclass(repr=False) +@docstring_inherit_attributes(Event) +class PressureEvent(Event): + """ + PressureEvent + + Attributes: + event_type (EventType): `EventType.Pressure` (See [`EventType`][kloppy.domain.models.event.EventType]) + event_name (str): `"pressure"`, + end_timestamp (float): + """ + + end_timestamp: float + + event_type: EventType = EventType.PRESSURE + event_name: str = "pressure" + + @dataclass(repr=False) class EventDataset(Dataset[Event]): """ diff --git a/kloppy/domain/services/event_factory.py b/kloppy/domain/services/event_factory.py index 33fe4f61..7afe01c3 100644 --- a/kloppy/domain/services/event_factory.py +++ b/kloppy/domain/services/event_factory.py @@ -23,6 +23,7 @@ SubstitutionEvent, GoalkeeperEvent, ) +from kloppy.domain.models.event import PressureEvent T = TypeVar("T") @@ -122,3 +123,6 @@ def build_substitution(self, **kwargs) -> SubstitutionEvent: def build_goalkeeper_event(self, **kwargs) -> GoalkeeperEvent: return create_event(GoalkeeperEvent, **kwargs) + + def build_pressure_event(self, **kwargs) -> PressureEvent: + return create_event(PressureEvent, **kwargs) diff --git a/kloppy/infra/serializers/event/statsbomb/specification.py b/kloppy/infra/serializers/event/statsbomb/specification.py index 9ff8ed8f..cadd101b 100644 --- a/kloppy/infra/serializers/event/statsbomb/specification.py +++ b/kloppy/infra/serializers/event/statsbomb/specification.py @@ -1136,6 +1136,24 @@ def _create_events( return [recovery_event] +class PRESSURE(EVENT): + """StatsBomb 17/Pressure event.""" + + def _create_events( + self, event_factory: EventFactory, **generic_event_kwargs + ) -> List[Event]: + end_timestamp = generic_event_kwargs["timestamp"] + self.raw_event.get( + "duration", 0.0 + ) + pressure_event = event_factory.build_pressure_event( + result=None, + qualifiers=None, + end_timestamp=end_timestamp, + **generic_event_kwargs, + ) + return [pressure_event] + + class TACTICAL_SHIFT(EVENT): """StatsBomb 36/Tactical shift event.""" @@ -1282,6 +1300,7 @@ def event_decoder(raw_event: Dict) -> Union[EVENT, Dict]: EVENT_TYPE.PLAYER_ON: PLAYER_ON, EVENT_TYPE.PLAYER_OFF: PLAYER_OFF, EVENT_TYPE.BALL_RECOVERY: BALL_RECOVERY, + EVENT_TYPE.PRESSURE: PRESSURE, EVENT_TYPE.TACTICAL_SHIFT: TACTICAL_SHIFT, } event_type = EVENT_TYPE(raw_event["type"]) diff --git a/kloppy/tests/test_statsbomb.py b/kloppy/tests/test_statsbomb.py index 49ec8aa7..f4b57999 100644 --- a/kloppy/tests/test_statsbomb.py +++ b/kloppy/tests/test_statsbomb.py @@ -990,6 +990,15 @@ def test_card(self, dataset: EventDataset): assert foul_without_card.get_qualifier_value(CardQualifier) is None +class TestStatsBombPressureEvent: + """Tests related to deserializing 17/Pressure events""" + + def test_deserialize_all(self, dataset: EventDataset): + """It should deserialize all pressure events""" + events = dataset.find_all("pressure") + assert len(events) == 203 + + class TestStatsBombPlayerOffEvent: """Tests related to deserializing 19/Player Off events"""