diff options
author | Maxim Devaev <[email protected]> | 2022-08-07 18:42:00 +0300 |
---|---|---|
committer | Maxim Devaev <[email protected]> | 2022-08-07 18:42:00 +0300 |
commit | aa630988cc09f31d412a62c5480d4bec1a7c626e (patch) | |
tree | 7e61031827ddcbfc56d049ffa336ac664d3c5c8b /kvmd/aiotools.py | |
parent | d995349b6311bf06b77ac0e8ccc4a424112feeb0 (diff) |
aiotools.shield_fg()
Diffstat (limited to 'kvmd/aiotools.py')
-rw-r--r-- | kvmd/aiotools.py | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/kvmd/aiotools.py b/kvmd/aiotools.py index 6895421c..2a798e2a 100644 --- a/kvmd/aiotools.py +++ b/kvmd/aiotools.py @@ -84,6 +84,47 @@ _RetvalT = TypeVar("_RetvalT") # ===== +class _ArmoredFuture(asyncio.Future): + def cancel(self, *_, **__) -> bool: # type: ignore + # FIXME: Выяснить, почему это работает + return False + + def forced_cancel(self) -> bool: + return super().cancel() + + +def shield_fg(aw: Awaitable): # type: ignore + # XXX: Копия asyncio.shield() с небольшими изменениями + + inner = asyncio.ensure_future(aw) + if inner.done(): + return inner + outer = _ArmoredFuture(loop=inner.get_loop()) + + def inner_done(_) -> None: # type: ignore + if outer.cancelled(): + if not inner.cancelled(): + inner.exception() # Mark inner's result as retrieved + return + + if inner.cancelled(): + outer.forced_cancel() + else: + err = inner.exception() + if err is not None: + outer.set_exception(err) + else: + outer.set_result(inner.result()) + + def outer_done(_) -> None: # type: ignore + if not inner.done(): + inner.remove_done_callback(inner_done) + + inner.add_done_callback(inner_done) + outer.add_done_callback(outer_done) + return outer + + def atomic(func: _FunctionT) -> _FunctionT: @functools.wraps(func) async def wrapper(*args: Any, **kwargs: Any) -> Any: |