I'm trying to wrap the signal class of blinker with one that enforces typing. The basic interface I'm trying to wrap is:
class Signal: def send(self, sender: Any | None, **kwargs): ... def connect(self, receiver): ...
(this isn't the exact interface but models the problem).
I can achieve type-hinting for the sender
arg pretty simply using generics:
T = TypeVar("T")class TypedSignal(Generic[T], Signal): def send(self, sender: Type[T], **kwargs): super(TypedSignal, self).send(sender) def connect(self, receiver: Callable[[Type[T], ...], None]) -> Callable: return super(TypedSignal, self).connect(receiver)# used asmy_signal = TypedSignal[MyClass]()
what gets tricky is when I want to add type-checking for the kwargs
. The approach I've been attempting to get working is using a variadic generic and Unpack
like so:
T = TypeVar("T")KW = TypeVarTuple("KW")class TypedSignal(Generic[T, Unpack[KW]], Signal): def send(self, sender: Type[T], **kwargs: Unpack[Type[KW]]): super(TypedSignal, self).send(sender) def connect(self, receiver: Callable[[Type[T], Unpack[Type[KW]]], None]) -> Callable: return super(TypedSignal, self).connect(receiver)
but mypy complains: error: Unpack item in ** argument must be a TypedDict
which seems odd because this error gets thrown even with no usage of the generic, let alone when a TypedDict
is passed.
Is there a simpler way to do this? Is this possible with current python typing?
mypy version is 1.9.0 - tried with earlier versions and it crashed completely.