9 """Base exception class for this module."""
17 """Call queue is empty error."""
21 """Timed out while waiting for call."""
24CheckerType = typing.Callable[[str],
None]
26__tracebackhide__ = traceback.hide(BaseError)
30 """Function wrapper that puts information about function call into async
33 This class provides methods to wait/check function underlying function
39 func: typing.Callable,
42 checker: CheckerType |
None =
None,
45 self.
_name = name
or func.__name__
50 """Returns underlying function."""
55 return inspect.iscoroutinefunction(self.
_func)
58 def _get_callinfo(self):
59 return callinfo(self.
_func)
62 def _queue(self) -> asyncio.Queue:
63 return asyncio.Queue()
66 return f
'<AsyncCallQueue: for {self._func!r}>'
69 """Call underlying function."""
72 return await self.
_func(*args, **kwargs)
73 return self.
_func(*args, **kwargs)
75 await self.
_queue.put((args, kwargs))
78 """Clear call queue."""
79 self.
_queue = asyncio.Queue()
83 """Returns ``True`` if call queue is not empty."""
89 """Returns call queue length."""
94 """Pops call from queue and return its arguments dict.
96 Raises ``CallQueueError`` if queue is empty
101 except asyncio.queues.QueueEmpty:
103 f
'No calls for {self._name}() left in the queue',
107 """Wait for fucntion to be called. Pops call from queue. Blocks if
110 :param timeout: timeout in seconds
112 Raises ``CallQueueTimeoutError`` if queue is empty for ``timeout``
117 item = await asyncio.wait_for(self.
_queue.get(), timeout=timeout)
119 except asyncio.TimeoutError:
121 f
'Timeout while waiting for {self._name}() to be called',
124 def _check_callqueue(self, caller):
129def getfullargspec(func):
130 if isinstance(func, staticmethod):
132 func = getattr(func,
'__wrapped__', func)
133 return inspect.getfullargspec(func)
137 func_spec = getfullargspec(func)
138 func_varkw = func_spec.varkw
139 func_kwonlyargs = func_spec.kwonlyargs
140 func_kwonlydefaults = func_spec.kwonlydefaults
142 func_args = func_spec.args
143 func_varargs = func_spec.varargs
144 defaults = func_spec.defaults
or ()
145 func_defaults = dict(zip(func_args[-len(defaults) :], defaults))
147 def callinfo_getter(args, kwargs):
148 dct = dict(zip(func_args, args))
149 for argname
in func_args[len(args) :]:
150 if argname
in kwargs:
151 dct[argname] = kwargs[argname]
153 dct[argname] = func_defaults.get(argname)
154 if func_varargs
is not None:
155 dct[func_varargs] = args[len(dct) :]
156 for argname
in func_kwonlyargs:
157 if argname
in kwargs:
158 dct[argname] = kwargs[argname]
160 dct[argname] = func_kwonlydefaults[argname]
161 if func_varkw
is not None:
162 dct[func_varkw] = {k: v
for k, v
in kwargs.items()
if k
not in dct}
165 return callinfo_getter
169 func: typing.Callable,
171 checker: CheckerType |
None =
None,
173 """Turn function into async call queue.
175 :param func: async or sync callable, can be decorated with @staticmethod
176 :param checker: optional function to check whether or not operation on
177 callqueue is possible
179 if isinstance(func, AsyncCallQueue):
181 if isinstance(func, staticmethod):
184 if hasattr(func,
'__name__'):
186 elif hasattr(func,
'__call__'):
187 name = func.__class__.__name__
190 raise RuntimeError(f
'Unsupported func {func!r} given')