1# ty: ignore[unresolved-import]
2__lazy_modules__ = frozenset(('_contextvars',))
3from asyncutils._internal.helpers import copy_and_clear, fullname
4from asyncutils._internal.submodules import futures_all as __all__
5from _contextvars import copy_context
6from asyncio.futures import Future, _PyFuture
7from asyncio.tasks import Task, _PyTask, eager_task_factory
8from sys import audit
9class FB:
10 def __init__(self): self._creation_time = self.get_loop().time() # ty: ignore[unresolved-attribute]
11 def __lt__(self, other, /): return self._creation_time < other._creation_time
[docs]
12class TimeAwareFuture(FB, Future): ...
[docs]
13class TimeAwareTask(FB, Task): ...
14def ff(a):
15 def remove_callback(self, fn, /):
16 if r := len(C := getattr(self, a))-len(l := [(f, c) for f, c in C if f is not fn]): C[:] = l
17 return r
18 return remove_callback
[docs]
19class AsyncCallbacksFuture(_PyFuture):
20 def __init__(self, *, loop=None): _PyFuture.__init__(self, loop=loop); self._setup()
21 def _setup(self): self._async_callbacks, self._noargs_callbacks, self._noargs_async_callbacks = [], [], []
[docs]
22 def add_async_callback(self, fn, /, *, context=None):
23 if self._state == 'PENDING': self._async_callbacks.append((fn, context or copy_context()))
24 else: self._loop.create_task(fn(self))
[docs]
25 def add_noargs_callback(self, fn, /, *, context=None):
26 if self._state == 'PENDING': self._noargs_callbacks.append((fn, context or copy_context()))
27 else: self._loop.call_soon(fn)
[docs]
28 def add_noargs_async_callback(self, fn, /, *, context=None):
29 if self._state == 'PENDING': self._noargs_async_callbacks.append((fn, context or copy_context()))
30 else: self._loop.create_task(fn())
31 remove_async_callback, remove_noargs_callback, remove_noargs_async_callback = map(ff, ('_async_callbacks', '_noargs_callbacks', '_noargs_async_callbacks'))
32 def __schedule_callbacks(self):
33 audit(f'{fullname(self)}/schedule_callbacks', id(self)); a, b = (l := self._loop).create_task, l.call_soon; c, d, e, f = map(copy_and_clear, (self._async_callbacks, self._callbacks, self._noargs_async_callbacks, self._noargs_callbacks))
34 for g, _ in c: a(g(self), context=_)
35 for g, _ in d: b(g, self, context=_)
36 for g, _ in e: a(g(), context=_)
37 for g, _ in f: b(g, context=_)
[docs]
38class AsyncCallbacksTask(_PyTask, AsyncCallbacksFuture): # ty: ignore[inconsistent-mro]
39 def __init__(self, coro, **k): _PyTask.__init__(self, coro, **k); self._setup()
[docs]
40class EagerAsyncCallbacksFuture(AsyncCallbacksFuture):
41 def _setup(self): self._loop.set_task_factory(eager_task_factory); super()._setup()
[docs]
42class EagerAsyncCallbacksTask(AsyncCallbacksTask, EagerAsyncCallbacksFuture): ...
[docs]
43class TimeAwareAsyncCallbacksFuture(FB, AsyncCallbacksFuture): ...
[docs]
44class TimeAwareAsyncCallbacksTask(FB, AsyncCallbacksTask): ...
[docs]
45class EagerTimeAwareAsyncCallbacksFuture(TimeAwareAsyncCallbacksFuture, EagerAsyncCallbacksFuture): ...
[docs]
46class EagerTimeAwareAsyncCallbacksTask(TimeAwareAsyncCallbacksTask, EagerAsyncCallbacksTask): ...
47del FB, ff