diff options
Diffstat (limited to 'third_party/python/aiohttp/aiohttp/locks.py')
-rw-r--r-- | third_party/python/aiohttp/aiohttp/locks.py | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/third_party/python/aiohttp/aiohttp/locks.py b/third_party/python/aiohttp/aiohttp/locks.py new file mode 100644 index 0000000000..ce5b9c6f73 --- /dev/null +++ b/third_party/python/aiohttp/aiohttp/locks.py @@ -0,0 +1,45 @@ +import asyncio +import collections +from typing import Any, Optional + +try: + from typing import Deque +except ImportError: + from typing_extensions import Deque + + +class EventResultOrError: + """ + This class wrappers the Event asyncio lock allowing either awake the + locked Tasks without any error or raising an exception. + + thanks to @vorpalsmith for the simple design. + """ + + def __init__(self, loop: asyncio.AbstractEventLoop) -> None: + self._loop = loop + self._exc = None # type: Optional[BaseException] + self._event = asyncio.Event() + self._waiters = collections.deque() # type: Deque[asyncio.Future[Any]] + + def set(self, exc: Optional[BaseException] = None) -> None: + self._exc = exc + self._event.set() + + async def wait(self) -> Any: + waiter = self._loop.create_task(self._event.wait()) + self._waiters.append(waiter) + try: + val = await waiter + finally: + self._waiters.remove(waiter) + + if self._exc is not None: + raise self._exc + + return val + + def cancel(self) -> None: + """ Cancel all waiters """ + for waiter in self._waiters: + waiter.cancel() |