base.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import abc
  2. import functools
  3. import weakref
  4. from . import exc as async_exc
  5. class ReversibleProxy:
  6. # weakref.ref(async proxy object) -> weakref.ref(sync proxied object)
  7. _proxy_objects = {}
  8. __slots__ = ("__weakref__",)
  9. def _assign_proxied(self, target):
  10. if target is not None:
  11. target_ref = weakref.ref(target, ReversibleProxy._target_gced)
  12. proxy_ref = weakref.ref(
  13. self,
  14. functools.partial(ReversibleProxy._target_gced, target_ref),
  15. )
  16. ReversibleProxy._proxy_objects[target_ref] = proxy_ref
  17. return target
  18. @classmethod
  19. def _target_gced(cls, ref, proxy_ref=None):
  20. cls._proxy_objects.pop(ref, None)
  21. @classmethod
  22. def _regenerate_proxy_for_target(cls, target):
  23. raise NotImplementedError()
  24. @classmethod
  25. def _retrieve_proxy_for_target(cls, target, regenerate=True):
  26. try:
  27. proxy_ref = cls._proxy_objects[weakref.ref(target)]
  28. except KeyError:
  29. pass
  30. else:
  31. proxy = proxy_ref()
  32. if proxy is not None:
  33. return proxy
  34. if regenerate:
  35. return cls._regenerate_proxy_for_target(target)
  36. else:
  37. return None
  38. class StartableContext(abc.ABC):
  39. __slots__ = ()
  40. @abc.abstractmethod
  41. async def start(self, is_ctxmanager=False):
  42. pass
  43. def __await__(self):
  44. return self.start().__await__()
  45. async def __aenter__(self):
  46. return await self.start(is_ctxmanager=True)
  47. @abc.abstractmethod
  48. async def __aexit__(self, type_, value, traceback):
  49. pass
  50. def _raise_for_not_started(self):
  51. raise async_exc.AsyncContextNotStarted(
  52. "%s context has not been started and object has not been awaited."
  53. % (self.__class__.__name__)
  54. )
  55. class ProxyComparable(ReversibleProxy):
  56. __slots__ = ()
  57. def __hash__(self):
  58. return id(self)
  59. def __eq__(self, other):
  60. return (
  61. isinstance(other, self.__class__)
  62. and self._proxied == other._proxied
  63. )
  64. def __ne__(self, other):
  65. return (
  66. not isinstance(other, self.__class__)
  67. or self._proxied != other._proxied
  68. )