Source code for asyncutils.futures

 1# ty: ignore[unresolved-attribute]
 2from asyncutils._internal.helpers import copy_and_clear, fullname, simple_wrap
 3from asyncutils._internal.submodules import futures_all as __all__
 4from contextvars import copy_context
 5from asyncio.futures import Future, _PyFuture # ty: ignore[unresolved-import]
 6from asyncio.tasks import Task, _PyTask # ty: ignore[unresolved-import]
 7from sys import audit
 8from time import monotonic_ns
 9t = '_callbacks', '_async_callbacks', '_noargs_callbacks', '_noargs_async_callbacks'
10def f(a, /):
11    def remove_callback(self, f, /):
12        if r := len(C := getattr(self, a))-len(l := tuple(t for t in C if t[0] is not f)): C[:] = l
13        return r
14    return remove_callback
15class A:
16    def __init__(self, *a, **k): super().__init__(*a, **k); self._async_callbacks, self._noargs_callbacks, self._noargs_async_callbacks = (c := type(self)._mcb)(), c(), c()
17    def add_async_callback(self, f, /, *, context=None):
18        if self._state == 'PENDING': type(self)._acb(self._async_callbacks, f, context)
19        else: self._loop.create_task(simple_wrap(f(self)), context=context)
20    def add_noargs_callback(self, f, /, *, context=None):
21        if self._state == 'PENDING': type(self)._acb(self._noargs_callbacks, f, context)
22        else: self._loop.call_soon(f, context=context)
23    def add_noargs_async_callback(self, f, /, *, context=None):
24        if self._state == 'PENDING': type(self)._acb(self._noargs_async_callbacks, f, context)
25        else: self._loop.create_task(simple_wrap(f()), context=context)
26    def _Future__schedule_callbacks(self): # noqa: N802
27        audit(f'{fullname(self)}/schedule_callbacks', id(self)); a, b = (l := self._loop).create_task, l.call_soon; c, d, e, f = map(type(self)._icb, (self._async_callbacks, self._callbacks, self._noargs_async_callbacks, self._noargs_callbacks))
28        for g, _ in c: a(g(self), context=_)
29        for g, _ in d: b(g, self, context=_)
30        for g, _ in e: a(g(), context=_)
31        for g, _ in f: b(g, context=_)
32class B:
33    def __init__(self, *a, **k): self._creation_time = monotonic_ns(); super().__init__(*a, **k)
34    def __lt__(self, o, /): return self._creation_time < o._creation_time
35class C(A): _acb, _icb, _mcb = lambda a, f, c, /: a.append((f, c or copy_context())), copy_and_clear, list; remove_done_callback, remove_async_callback, remove_noargs_callback, remove_noargs_async_callback = map(f, t)
36class D(A):
37    _acb, _icb, _mcb = lambda a, f, c, /: a.__setitem__(f, c or copy_context()), lambda d, /: tuple(d.items()), dict; remove_done_callback, remove_async_callback, remove_noargs_callback, remove_noargs_async_callback = map(lambda a, /: lambda self, f, a=a, /: 0 if getattr(self, a).pop(f, None) is None else 1, t)
38    def __init__(self, *a, **k): super().__init__(*a, **k); self._callbacks = {}
39    def add_done_callback(self, f, /, *, context=None):
40        if self._state == 'PENDING': type(self)._acb(self._callbacks, f, context)
41        else: self._loop.call_soon(f, self, context=context)
[docs] 42class TimeAwareFuture(B, Future): ...
[docs] 43class TimeAwareTask(B, Task): ...
[docs] 44class AsyncCallbacksFuture(C, _PyFuture): ...
[docs] 45class AsyncCallbacksTask(C, _PyTask): ...
[docs] 46class TimeAwareAsyncCallbacksFuture(C, B, _PyFuture): ...
[docs] 47class TimeAwareAsyncCallbacksTask(C, B, _PyTask): ...
[docs] 48class UniqueCallbacksFuture(D, _PyFuture): ...
[docs] 49class UniqueCallbacksTask(D, _PyTask): ...
[docs] 50class TimeAwareUniqueCallbacksFuture(D, B, _PyFuture): ...
[docs] 51class TimeAwareUniqueCallbacksTask(D, B, _PyTask): ...
52del f, t, A, B, C, D