# Path: sygnal/exceptions.py
# class InvalidNotificationException(Exception):
#     pass
# 
# class NotificationDispatchException(Exception):
#     pass
# 
# class PushkinSetupException(Exception):
#     pass


import abc
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, TypeVar, overload
from matrix_common.regex import glob_to_regex
from opentracing import Span
from prometheus_client import Counter
from sygnal.exceptions import (
    InvalidNotificationException,
    NotificationDispatchException,
    PushkinSetupException,
)
    from sygnal.sygnal import Sygnal
@overload
def get_key(
    raw: Dict[str, Any], key: str, type_: Type[T], default: None = None
) -> Optional[T]:
    ...


def get_key(
    raw: Dict[str, Any], key: str, type_: Type[T], default: Optional[T] = None
) -> Optional[T]:
    if key not in raw:
        return default
    if not isinstance(raw[key], type_):
        raise InvalidNotificationException(f"{key} is of invalid type")
    return raw[key]


class Tweaks:
    def __init__(self, raw: Dict[str, Any]):
        self.sound: Optional[str] = get_key(raw, "sound", str)


class Device:
    def __init__(self, raw: Dict[str, Any]):
        if "app_id" not in raw or not isinstance(raw["app_id"], str):
            raise InvalidNotificationException(
                "Device with missing or non-string app_id"
            )
        self.app_id: str = raw["app_id"]
        if "pushkey" not in raw or not isinstance(raw["pushkey"], str):

# Path: sygnal/exceptions.py
# class InvalidNotificationException(Exception):
#     pass
# 
# class NotificationDispatchException(Exception):
#     pass
# 
# class PushkinSetupException(Exception):
#     pass


# Path: sygnal/notifications.py
import abc
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, TypeVar, overload
from matrix_common.regex import glob_to_regex
from opentracing import Span
from prometheus_client import Counter
from sygnal.exceptions import (
    InvalidNotificationException,
    NotificationDispatchException,
    PushkinSetupException,
)
    from sygnal.sygnal import Sygnal

@overload
def get_key(
    raw: Dict[str, Any], key: str, type_: Type[T], default: None = None
) -> Optional[T]:
    ...


def get_key(
    raw: Dict[str, Any], key: str, type_: Type[T], default: Optional[T] = None
) -> Optional[T]:
    if key not in raw:
        return default
    if not isinstance(raw[key], type_):
        raise InvalidNotificationException(f"{key} is of invalid type")
    return raw[key]


class Tweaks:
    def __init__(self, raw: Dict[str, Any]):
        self.sound: Optional[str] = get_key(raw, "sound", str)


class Device:
    def __init__(self, raw: Dict[str, Any]):
        if "app_id" not in raw or not isinstance(raw["app_id"], str):
            raise InvalidNotificationException(
                "Device with missing or non-string app_id"
            )
        self.app_id: str = raw["app_id"]
        if "pushkey" not in raw or not isinstance(raw["pushkey"], str):

            raise InvalidNotificationException(