awaitable_response.py 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. from __future__ import annotations
  2. from typing import Callable
  3. from . import background_tasks
  4. class AwaitableResponse:
  5. def __init__(self, fire_and_forget: Callable, wait_for_result: Callable) -> None:
  6. """Awaitable Response
  7. This class can be used to run one of two different callables, depending on whether the response is awaited or not.
  8. It must be awaited immediately after creation or not at all.
  9. :param fire_and_forget: The callable to run if the response is not awaited.
  10. :param wait_for_result: The callable to run if the response is awaited.
  11. """
  12. self.fire_and_forget = fire_and_forget
  13. self.wait_for_result = wait_for_result
  14. self._is_fired = False
  15. self._is_awaited = False
  16. background_tasks.create(self._fire(), name='fire')
  17. async def _fire(self) -> None:
  18. if self._is_awaited:
  19. return
  20. self._is_fired = True
  21. self.fire_and_forget()
  22. def __await__(self):
  23. if self._is_fired:
  24. raise RuntimeError('AwaitableResponse must be awaited immediately after creation or not at all')
  25. self._is_awaited = True
  26. return self.wait_for_result().__await__()
  27. class NullResponse(AwaitableResponse):
  28. def __init__(self) -> None: # pylint: disable=super-init-not-called
  29. """Null Response
  30. This class can be used to create an AwaitableResponse that does nothing.
  31. In contrast to AwaitableResponse, it can be created without a running event loop.
  32. """
  33. def __await__(self):
  34. yield from []