__init__.py 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import sys
  2. from typing import Any, Awaitable, Callable, TypeVar
  3. from frozenlist import FrozenList
  4. if sys.version_info >= (3, 11):
  5. from typing import Unpack
  6. else:
  7. from typing_extensions import Unpack
  8. if sys.version_info >= (3, 13):
  9. from typing import TypeVarTuple
  10. else:
  11. from typing_extensions import TypeVarTuple
  12. _T = TypeVar("_T")
  13. _Ts = TypeVarTuple("_Ts", default=Unpack[tuple[()]])
  14. __version__ = "1.4.0"
  15. __all__ = ("Signal",)
  16. class Signal(FrozenList[Callable[[Unpack[_Ts]], Awaitable[object]]]):
  17. """Coroutine-based signal implementation.
  18. To connect a callback to a signal, use any list method.
  19. Signals are fired using the send() coroutine, which takes named
  20. arguments.
  21. """
  22. __slots__ = ("_owner",)
  23. def __init__(self, owner: object):
  24. super().__init__()
  25. self._owner = owner
  26. def __repr__(self) -> str:
  27. return "<Signal owner={}, frozen={}, {!r}>".format(
  28. self._owner, self.frozen, list(self)
  29. )
  30. async def send(self, *args: Unpack[_Ts], **kwargs: Any) -> None:
  31. """
  32. Sends data to all registered receivers.
  33. """
  34. if not self.frozen:
  35. raise RuntimeError("Cannot send non-frozen signal.")
  36. for receiver in self:
  37. await receiver(*args, **kwargs)
  38. def __call__(
  39. self, func: Callable[[Unpack[_Ts]], Awaitable[_T]]
  40. ) -> Callable[[Unpack[_Ts]], Awaitable[_T]]:
  41. """Decorator to add a function to this Signal."""
  42. self.append(func)
  43. return func