Repository: PySport/kloppy

Issue:
[Sportec] Broken Open DFL Data
This is currently not an issue, however in the future the "figshare" URL to the DFL open dataset might break as discussed https://github.com/PySport/kloppy/pull/365#issuecomment-2505824754.

As long as the url is not broken, this issue exists as a place holder and for future reference within the error message of  https://github.com/PySport/kloppy/pull/365

Hints from issue comments:
@UnravelSports: This has been resolved by https://github.com/PySport/kloppy/pull/371@probberechts: It looks like this issue was erroneously closed. The referenced PR is not related.

Solution patch:
diff --git a/kloppy/_providers/sportec.py b/kloppy/_providers/sportec.py
index 9df12de..eece389 100644
--- a/kloppy/_providers/sportec.py
+++ b/kloppy/_providers/sportec.py
@@ -1,7 +1,5 @@
 from typing import List, Optional
 
-from requests.exceptions import HTTPError
-
 from kloppy.config import get_config
 from kloppy.domain import EventDataset, EventFactory, TrackingDataset
 from kloppy.infra.serializers.event.sportec import (
@@ -90,16 +88,18 @@ def get_IDSSE_url(match_id: str, data_type: str) -> str:
     """Returns the URL for the meta, event or tracking data for a match in the IDDSE dataset."""
     # match_id -> file_id
     DATA_MAP = {
-        "J03WPY": {"meta": 48392497, "event": 48392542, "tracking": 48392572},
-        "J03WN1": {"meta": 48392491, "event": 48392527, "tracking": 48392512},
-        "J03WMX": {"meta": 48392485, "event": 48392524, "tracking": 48392539},
-        "J03WOH": {"meta": 48392515, "event": 48392500, "tracking": 48392578},
-        "J03WQQ": {"meta": 48392488, "event": 48392521, "tracking": 48392545},
-        "J03WOY": {"meta": 48392503, "event": 48392518, "tracking": 48392551},
-        "J03WR9": {"meta": 48392494, "event": 48392530, "tracking": 48392563},
+        "J03WPY": {"meta": 51643487, "event": 51643505, "tracking": 51643526},
+        "J03WN1": {"meta": 51643472, "event": 51643496, "tracking": 51643517},
+        "J03WMX": {"meta": 51643475, "event": 51643493, "tracking": 51643514},
+        "J03WOH": {"meta": 51643478, "event": 51643499, "tracking": 51643520},
+        "J03WQQ": {"meta": 51643484, "event": 51643508, "tracking": 51643529},
+        "J03WOY": {"meta": 51643481, "event": 51643502, "tracking": 51643523},
+        "J03WR9": {"meta": 51643490, "event": 51643511, "tracking": 51643532},
     }
     # URL constant
-    DATA_URL = "https://figshare.com/ndownloader/files/{file_id}?private_link=1f806cb3e755c6b54e05"
+    DATA_URL = (
+        "https://springernature.figshare.com/ndownloader/files/{file_id}"
+    )
 
     if data_type not in ["meta", "event", "tracking"]:
         raise ValueError(
@@ -154,23 +154,17 @@ def load_open_event_data(
         }
 
     References:
-        .. [1] Bassek, M., Weber, H., Rein, R., & Memmert, D. (2024). "An integrated
-               dataset of synchronized spatiotemporal and event data in elite soccer."
-               In Submission.
+        .. [1] Bassek, M., Rein, R., Weber, H. et al. "An integrated dataset of
+               spatiotemporal and event data in elite soccer." Sci Data 12, 195 (2025).
+               https://doi.org/10.1038/s41597-025-04505-y
     """
-    try:
-        return load_event(
-            event_data=get_IDSSE_url(match_id, "event"),
-            meta_data=get_IDSSE_url(match_id, "meta"),
-            event_types=event_types,
-            coordinates=coordinates,
-            event_factory=event_factory,
-        )
-    except HTTPError as e:
-        raise HTTPError(
-            "Unable to retrieve data. The dataset archive location may have changed. "
-            "See https://github.com/PySport/kloppy/issues/369 for details."
-        ) from e
+    return load_event(
+        event_data=get_IDSSE_url(match_id, "event"),
+        meta_data=get_IDSSE_url(match_id, "meta"),
+        event_types=event_types,
+        coordinates=coordinates,
+        event_factory=event_factory,
+    )
 
 
 def load_open_tracking_data(
@@ -221,17 +215,11 @@ def load_open_tracking_data(
                dataset of synchronized spatiotemporal and event data in elite soccer."
                In Submission.
     """
-    try:
-        return load_tracking(
-            raw_data=get_IDSSE_url(match_id, "tracking"),
-            meta_data=get_IDSSE_url(match_id, "meta"),
-            sample_rate=sample_rate,
-            limit=limit,
-            coordinates=coordinates,
-            only_alive=only_alive,
-        )
-    except HTTPError as e:
-        raise HTTPError(
-            "Unable to retrieve data. The dataset archive location may have changed. "
-            "See https://github.com/PySport/kloppy/issues/369 for details."
-        ) from e
+    return load_tracking(
+        raw_data=get_IDSSE_url(match_id, "tracking"),
+        meta_data=get_IDSSE_url(match_id, "meta"),
+        sample_rate=sample_rate,
+        limit=limit,
+        coordinates=coordinates,
+        only_alive=only_alive,
+    )
diff --git a/kloppy/infra/serializers/event/statsperform/deserializer.py b/kloppy/infra/serializers/event/statsperform/deserializer.py
index e7f0dc3..0af9b2d 100644
--- a/kloppy/infra/serializers/event/statsperform/deserializer.py
+++ b/kloppy/infra/serializers/event/statsperform/deserializer.py
@@ -401,7 +401,9 @@ def _parse_substitution(next_event: OptaEvent, team: Team) -> Dict:
 
     raw_position_line = next_event.qualifiers.get(44)
     if raw_position_line:
-        position = position_line_mapping[raw_position_line]
+        position = position_line_mapping.get(
+            raw_position_line, PositionType.Unknown
+        )
 
     return dict(replacement_player=replacement_player, position=position)
 
diff --git a/kloppy/infra/serializers/event/statsperform/parsers/f7_xml.py b/kloppy/infra/serializers/event/statsperform/parsers/f7_xml.py
index 10f166c..f5e7563 100644
--- a/kloppy/infra/serializers/event/statsperform/parsers/f7_xml.py
+++ b/kloppy/infra/serializers/event/statsperform/parsers/f7_xml.py
@@ -12,6 +12,7 @@ from kloppy.domain import (
     Player,
     Score,
     Team,
+    PositionType,
 )
 from kloppy.exceptions import DeserializationError
 
@@ -19,6 +20,7 @@ from .base import OptaXMLParser
 from ..formation_mapping import (
     formation_position_mapping,
     formation_name_mapping,
+    FormationType,
 )
 
 document_path = objectify.ObjectPath("SoccerFeed.SoccerDocument")
@@ -144,26 +146,43 @@ class F7XMLParser(OptaXMLParser):
                 "-".join(list(team_elm.attrib["Formation"]))
             ),
         )
-        team.players = [
-            Player(
-                player_id=player_elm.attrib["PlayerRef"].lstrip("p"),
-                team=team,
-                jersey_no=int(player_elm.attrib["ShirtNumber"]),
-                first_name=team_players[player_elm.attrib["PlayerRef"]][
-                    "first_name"
-                ],
-                last_name=team_players[player_elm.attrib["PlayerRef"]][
-                    "last_name"
-                ],
-                starting=(player_elm.attrib["Status"] == "Start"),
-                starting_position=formation_position_mapping[
-                    formation_name_mapping[team_elm.attrib["Formation"]]
-                ][int(player_elm.attrib["Formation_Place"])],
+        players = []
+
+        formation = (
+            formation_name_mapping.get(
+                team_elm.attrib["Formation"], FormationType.UNKNOWN
+            )
+            if "Formation" in team_elm.attrib
+            else FormationType.UNKNOWN
+        )
+
+        for player_elm in team_elm.find("PlayerLineUp").iterchildren(
+            "MatchPlayer"
+        ):
+            starting_position = (
+                formation_position_mapping[formation][
+                    int(player_elm.attrib["Formation_Place"])
+                ]
+                if formation != FormationType.UNKNOWN
+                else PositionType.Unknown
             )
-            for player_elm in team_elm.find("PlayerLineUp").iterchildren(
-                "MatchPlayer"
+            players.append(
+                Player(
+                    player_id=player_elm.attrib["PlayerRef"].lstrip("p"),
+                    team=team,
+                    jersey_no=int(player_elm.attrib["ShirtNumber"]),
+                    first_name=team_players[player_elm.attrib["PlayerRef"]][
+                        "first_name"
+                    ],
+                    last_name=team_players[player_elm.attrib["PlayerRef"]][
+                        "last_name"
+                    ],
+                    starting=(player_elm.attrib["Status"] == "Start"),
+                    starting_position=starting_position,
+                )
             )
-        ]
+
+        team.players = players
         return team
 
     def _parse_team_players(
diff --git a/kloppy/infra/serializers/event/statsperform/parsers/ma1_json.py b/kloppy/infra/serializers/event/statsperform/parsers/ma1_json.py
index 677ac72..1c21aaa 100644
--- a/kloppy/infra/serializers/event/statsperform/parsers/ma1_json.py
+++ b/kloppy/infra/serializers/event/statsperform/parsers/ma1_json.py
@@ -3,13 +3,14 @@
 from datetime import datetime, timezone
 from typing import Any, Dict, List, Optional, Tuple
 
-from kloppy.domain import Ground, Period, Player, Score, Team
+from kloppy.domain import Ground, Period, Player, Score, Team, PositionType
 from kloppy.exceptions import DeserializationError
 
 from .base import OptaJSONParser
 from ..formation_mapping import (
     formation_name_mapping,
     formation_position_mapping,
+    FormationType,
 )
 
 
@@ -134,7 +135,9 @@ class MA1JSONParser(OptaJSONParser):
         for line_up in line_ups:
             team_id = line_up["contestantId"]
             raw_formation = line_up["formationUsed"]
-            formation = formation_name_mapping[raw_formation]
+            formation = formation_name_mapping.get(
+                raw_formation, FormationType.UNKNOWN
+            )
             team_formations[team_id] = formation
 
         for team in teams:
@@ -156,15 +159,21 @@ class MA1JSONParser(OptaJSONParser):
         for line_up in line_ups:
             team_id = line_up["contestantId"]
             raw_formation = line_up["formationUsed"]
-            formation = formation_name_mapping[raw_formation]
+            formation = formation_name_mapping.get(
+                raw_formation, FormationType.UNKNOWN
+            )
 
             players = line_up["player"]
             for player in players:
                 player_id = player["playerId"]
                 if "formationPlace" in player:
-                    player_position = formation_position_mapping[formation][
-                        int(player["formationPlace"])
-                    ]
+                    player_position = (
+                        formation_position_mapping[formation][
+                            int(player["formationPlace"])
+                        ]
+                        if formation != FormationType.UNKNOWN
+                        else PositionType.Unknown
+                    )
                     starting = True
                 else:
                     player_position = None
diff --git a/kloppy/infra/serializers/event/statsperform/parsers/ma1_xml.py b/kloppy/infra/serializers/event/statsperform/parsers/ma1_xml.py
index 9a2cc72..68f17fb 100644
--- a/kloppy/infra/serializers/event/statsperform/parsers/ma1_xml.py
+++ b/kloppy/infra/serializers/event/statsperform/parsers/ma1_xml.py
@@ -3,12 +3,13 @@
 from datetime import datetime, timezone
 from typing import Any, Optional, List, Dict, Tuple
 
-from kloppy.domain import Period, Score, Team, Ground, Player
+from kloppy.domain import Period, Score, Team, Ground, Player, PositionType
 from kloppy.exceptions import DeserializationError
 from .base import OptaXMLParser
 from ..formation_mapping import (
     formation_name_mapping,
     formation_position_mapping,
+    FormationType,
 )
 
 
@@ -92,7 +93,9 @@ class MA1XMLParser(OptaXMLParser):
         for line_up in line_ups:
             team_id = line_up.get("contestantId")
             raw_formation = line_up.get("formationUsed")
-            formation = formation_name_mapping[raw_formation]
+            formation = formation_name_mapping.get(
+                raw_formation, FormationType.UNKNOWN
+            )
             team_formations[team_id] = formation
 
         for team in teams:
@@ -115,16 +118,23 @@ class MA1XMLParser(OptaXMLParser):
         for line_up in line_ups:
             team_id = line_up.get("contestantId")
             raw_formation = line_up.get("formationUsed")
-            formation = formation_name_mapping[raw_formation]
+            formation = formation_name_mapping.get(
+                raw_formation, FormationType.UNKNOWN
+            )
 
             players = line_up.iterchildren(tag="player")
             for player in players:
                 player_attributes = player.attrib
                 player_id = player_attributes["playerId"]
+
                 if "formationPlace" in player_attributes:
-                    player_position = formation_position_mapping[formation][
-                        int(player_attributes["formationPlace"])
-                    ]
+                    player_position = (
+                        formation_position_mapping[formation][
+                            int(player_attributes["formationPlace"])
+                        ]
+                        if formation != FormationType.UNKNOWN
+                        else PositionType.Unknown
+                    )
                     starting = True
                 else:
                     player_position = None
diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py
index fcb8380..af49116 100644
--- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py
+++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py
@@ -4,7 +4,7 @@ import warnings
 from dataclasses import replace
 from datetime import datetime, timedelta, timezone
 from enum import Enum
-from typing import Dict, List, Optional
+from typing import Dict, List, Optional, Union
 
 from kloppy.domain import (
     BodyPart,
@@ -39,6 +39,7 @@ from kloppy.domain import (
     CarryResult,
     ExpectedGoals,
     PostShotExpectedGoals,
+    Point3D,
 )
 from kloppy.exceptions import DeserializationError, DeserializationWarning
 from kloppy.utils import performance_logging
@@ -110,24 +111,68 @@ def _flip_point(point: Point) -> Point:
     return Point(x=100 - point.x, y=100 - point.y)
 
 
-class ShotZoneResults(str, Enum):
-    GOAL_BOTTOM_LEFT = "glb"
-    GOAL_BOTTOM_RIGHT = "grb"
-    GOAL_BOTTOM_CENTER = "gb"
-    GOAL_CENTER_LEFT = "gl"
-    GOAL_CENTER = "gc"
-    GOAL_CENTER_RIGHT = "gr"
-    GOAL_TOP_LEFT = "glt"
-    GOAL_TOP_RIGHT = "grt"
-    GOAL_TOP_CENTER = "gt"
-    OUT_BOTTOM_RIGHT = "obr"
-    OUT_BOTTOM_LEFT = "olb"
-    OUT_RIGHT = "or"
-    OUT_LEFT = "ol"
-    OUT_LEFT_TOP = "olt"
-    OUT_TOP = "ot"
-    OUT_RIGHT_TOP = "ort"
-    BLOCKED = "bc"
+class ShotZoneResults(Enum):
+    """
+     Wyscout does not provide end-coordinates of shots. Instead shots on goal
+     are tagged with a zone. The zones and corresponding y and z-coordinates are depicted below.
+
+                                        (z-coordinate of zone or post)
+
+         olt      | ot |      otr          3.5
+      --------------------------------
+           ||=================||           2.77
+      -------------------------------
+           || gtl | gt | gtr ||            2
+      --------------------------------
+       ol || gl | gc  | gr || or           1
+      --------------------------------
+       olb || glb  | gb | gbr || orb       0
+
+       40     45    50    55     60    (y-coordinate of zone)
+         44.62               55.38     (y-coordinate of post)
+
+    Attributes:
+       code (str): The string identifier of the shot result.
+       point (Point3D): The predefined Point3D associated with the shot result.
+    """
+
+    GOAL_BOTTOM_LEFT = ("glb", Point3D(100, 45, 0))
+    GOAL_BOTTOM_CENTER = ("gb", Point3D(100, 50, 0))
+    GOAL_BOTTOM_RIGHT = ("gbr", Point3D(100, 55, 0))
+    GOAL_CENTER_LEFT = ("gl", Point3D(100, 45, 1))
+    GOAL_CENTER = ("gc", Point3D(100, 50, 1))
+    GOAL_CENTER_RIGHT = ("gr", Point3D(100, 55, 1))
+    GOAL_TOP_LEFT = ("gtl", Point3D(100, 45, 2))
+    GOAL_TOP_CENTER = ("gt", Point3D(100, 50, 2))
+    GOAL_TOP_RIGHT = ("gtr", Point3D(100, 55, 2))
+    POST_BOTTOM_LEFT = ("plb", Point3D(100, 44.62, 0))
+    POST_BOTTOM_RIGHT = ("pbr", Point3D(100, 55.38, 0))
+    OUT_BOTTOM_LEFT = ("olb", Point3D(100, 40, 0))
+    OUT_BOTTOM_RIGHT = ("obr", Point3D(100, 60, 0))
+    POST_LEFT = ("pl", Point3D(100, 44.62, 1))
+    POST_RIGHT = ("pr", Point3D(100, 55.38, 1))
+    OUT_LEFT = ("ol", Point3D(100, 40, 1))
+    OUT_RIGHT = ("or", Point3D(100, 60, 1))
+    POST_TOP_LEFT = ("ptl", Point3D(100, 44.62, 2))
+    POST_TOP_RIGHT = ("ptr", Point3D(100, 55.38, 2))
+    OUT_TOP_LEFT = ("otl", Point3D(100, 40, 3.5))
+    OUT_TOP_RIGHT = ("otr", Point3D(100, 60, 3.5))
+    POST_TOP = ("pt", Point3D(100, 50, 2.77))
+    OUT_TOP = ("ot", Point3D(100, 50, 3.5))
+    BLOCKED = ("bc", None)
+
+    def __init__(self, code: str, point: Point3D):
+        self.code = code
+        self.point = point
+
+    @classmethod
+    def point_from_code(cls, code: str) -> Optional[Point3D]:
+        """Retrieves the enum member from a string code."""
+        for zone in cls:
+            if zone.code == code:
+                return zone.point
+
+        warnings.warn(f"Invalid shot zone code: {code}")
 
 
 def _parse_team(raw_events, wyId: str, ground: Ground) -> Team:
@@ -185,73 +230,18 @@ def _parse_team(raw_events, wyId: str, ground: Ground) -> Team:
 
 
 def _create_shot_result_coordinates(raw_event: Dict) -> Optional[Point]:
-    """Estimate the shot end location from the Wyscout tags.
-
-    Wyscout does not provide end-coordinates of shots. Instead shots on goal
-    are tagged with a zone. This function maps each of these zones to
-    a coordinate. The zones and corresponding y-coordinate are depicted below.
-
-
-        olt      | ot |      ort
-     --------------------------------
-          ||=================||
-     -------------------------------
-          || glt | gt | grt ||
-     --------------------------------
-      ol || gl | gc  | gr || or
-     --------------------------------
-      olb || glb  | gb | grb || orb
-
-      40     45    50    55     60    (y-coordinate of zone)
-        44.62               55.38     (y-coordiante of post)
-    """
-    if (
-        raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_BOTTOM_CENTER
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_CENTER
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_TOP_CENTER
-    ):
-        return Point(100.0, 50.0)
-
-    if (
-        raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_BOTTOM_RIGHT
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_CENTER_RIGHT
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_TOP_RIGHT
-    ):
-        return Point(100.0, 55.0)
-
-    if (
-        raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_BOTTOM_LEFT
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_CENTER_LEFT
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_TOP_LEFT
-    ):
-        return Point(100.0, 45.0)
-
-    if raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_TOP:
-        return Point(100.0, 50.0)
-
-    if (
-        raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_RIGHT_TOP
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_RIGHT
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_BOTTOM_RIGHT
-    ):
-        return Point(100.0, 60.0)
-
-    if (
-        raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_LEFT_TOP
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_LEFT
-        or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_BOTTOM_LEFT
-    ):
-        return Point(100.0, 40.0)
-
-    # If the shot is blocked, the start location is the best possible estimate
-    # for the shot's end location
-    if raw_event["shot"]["goalZone"] == ShotZoneResults.BLOCKED:
+    """Estimate the shot end location from the Wyscout tags."""
+    if raw_event["shot"]["goalZone"] == ShotZoneResults.BLOCKED.code:
         return Point(
             x=float(raw_event["location"]["x"]),
             y=float(raw_event["location"]["y"]),
         )
 
-    return None
+    else:
+        result_coordinates = ShotZoneResults.point_from_code(
+            raw_event["shot"]["goalZone"]
+        )
+        return result_coordinates
 
 
 def _generic_qualifiers(raw_event: Dict) -> List[Qualifier]:
@@ -336,6 +326,9 @@ def _pass_qualifiers(raw_event) -> List[Qualifier]:
         ):
             qualifiers.append(PassQualifier(pass_type))
 
+    if raw_event["pass"].get("height") == "high":
+        qualifiers.append(PassQualifier(PassType.HIGH_PASS))
+
     return qualifiers
 
 
diff --git a/setup.py b/setup.py
index cc5d7ed..74d3752 100644
--- a/setup.py
+++ b/setup.py
@@ -39,7 +39,6 @@ def setup_package():
         },
         install_requires=[
             "lxml>=4.4.0",
-            "requests>=2.0.0,<3",
             "pytz>=2020.1",
             'typing_extensions;python_version<"3.11"',
             "sortedcontainers>=2",


Test patch:
diff --git a/kloppy/tests/test_statsperform.py b/kloppy/tests/test_statsperform.py
index 07c9337..a50b5a7 100644
--- a/kloppy/tests/test_statsperform.py
+++ b/kloppy/tests/test_statsperform.py
@@ -106,6 +106,7 @@ class TestStatsPerformMetadata:
     def test_teams(self, tracking_dataset: TrackingDataset):
         home_team = tracking_dataset.metadata.teams[0]
         home_player = home_team.players[2]
+
         assert home_player.player_id == "5g5wwp5luxo1rz1kp6chvz0x6"
         assert tracking_dataset.records[0].players_coordinates[
             home_player
diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py
index 70179d2..2d1b7b2 100644
--- a/kloppy/tests/test_wyscout.py
+++ b/kloppy/tests/test_wyscout.py
@@ -28,6 +28,7 @@ from kloppy.domain import (
     SetPieceType,
     ShotResult,
     Time,
+    Point3D,
 )
 
 
@@ -284,12 +285,14 @@ class TestWyscoutV3:
         off_target_shot = dataset.get_event_by_id(1927028562)
         assert off_target_shot.event_type == EventType.SHOT
         assert off_target_shot.result == ShotResult.OFF_TARGET
-        assert off_target_shot.result_coordinates is None
+        assert off_target_shot.result_coordinates == Point3D(
+            x=100, y=40, z=3.5
+        )
         # on target shot
         on_target_shot = dataset.get_event_by_id(1927028637)
         assert on_target_shot.event_type == EventType.SHOT
         assert on_target_shot.result == ShotResult.SAVED
-        assert on_target_shot.result_coordinates == Point(100.0, 45.0)
+        assert on_target_shot.result_coordinates == Point3D(x=100, y=45, z=1)
 
     def test_foul_committed_event(self, dataset: EventDataset):
         foul_committed_event = dataset.get_event_by_id(1927028873)
@@ -381,3 +384,10 @@ class TestWyscoutV3:
         assert PassType.THROUGH_BALL in pass_event.get_qualifier_values(
             PassQualifier
         )
+
+    def test_high_pass_qualifier(self, dataset: EventDataset):
+        pass_event = dataset.get_event_by_id(1927028860)
+        assert pass_event.event_type == EventType.PASS
+        assert PassType.HIGH_PASS in pass_event.get_qualifier_values(
+            PassQualifier
+        )