ez-a-sync 0.22.14__py3-none-any.whl → 0.22.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ez-a-sync might be problematic. Click here for more details.
- a_sync/ENVIRONMENT_VARIABLES.py +4 -3
- a_sync/__init__.py +30 -12
- a_sync/_smart.py +132 -28
- a_sync/_typing.py +56 -12
- a_sync/a_sync/__init__.py +35 -10
- a_sync/a_sync/_descriptor.py +74 -26
- a_sync/a_sync/_flags.py +14 -6
- a_sync/a_sync/_helpers.py +8 -7
- a_sync/a_sync/_kwargs.py +3 -2
- a_sync/a_sync/_meta.py +120 -28
- a_sync/a_sync/abstract.py +102 -28
- a_sync/a_sync/base.py +34 -16
- a_sync/a_sync/config.py +47 -13
- a_sync/a_sync/decorator.py +239 -117
- a_sync/a_sync/function.py +416 -146
- a_sync/a_sync/method.py +197 -59
- a_sync/a_sync/modifiers/__init__.py +47 -5
- a_sync/a_sync/modifiers/cache/__init__.py +46 -17
- a_sync/a_sync/modifiers/cache/memory.py +86 -20
- a_sync/a_sync/modifiers/limiter.py +52 -22
- a_sync/a_sync/modifiers/manager.py +98 -16
- a_sync/a_sync/modifiers/semaphores.py +48 -15
- a_sync/a_sync/property.py +383 -82
- a_sync/a_sync/singleton.py +1 -0
- a_sync/aliases.py +0 -1
- a_sync/asyncio/__init__.py +4 -1
- a_sync/asyncio/as_completed.py +177 -49
- a_sync/asyncio/create_task.py +31 -17
- a_sync/asyncio/gather.py +72 -52
- a_sync/asyncio/utils.py +3 -3
- a_sync/exceptions.py +78 -23
- a_sync/executor.py +118 -71
- a_sync/future.py +575 -158
- a_sync/iter.py +110 -50
- a_sync/primitives/__init__.py +14 -2
- a_sync/primitives/_debug.py +13 -13
- a_sync/primitives/_loggable.py +5 -4
- a_sync/primitives/locks/__init__.py +5 -2
- a_sync/primitives/locks/counter.py +38 -36
- a_sync/primitives/locks/event.py +21 -7
- a_sync/primitives/locks/prio_semaphore.py +182 -62
- a_sync/primitives/locks/semaphore.py +78 -77
- a_sync/primitives/queue.py +560 -58
- a_sync/sphinx/__init__.py +0 -1
- a_sync/sphinx/ext.py +160 -50
- a_sync/task.py +262 -97
- a_sync/utils/__init__.py +12 -6
- a_sync/utils/iterators.py +127 -43
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/METADATA +1 -1
- ez_a_sync-0.22.15.dist-info/RECORD +74 -0
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/WHEEL +1 -1
- tests/conftest.py +1 -2
- tests/executor.py +112 -9
- tests/fixtures.py +61 -32
- tests/test_abstract.py +7 -4
- tests/test_as_completed.py +54 -21
- tests/test_base.py +66 -17
- tests/test_cache.py +31 -15
- tests/test_decorator.py +54 -28
- tests/test_executor.py +8 -13
- tests/test_future.py +45 -8
- tests/test_gather.py +8 -2
- tests/test_helpers.py +2 -0
- tests/test_iter.py +55 -13
- tests/test_limiter.py +5 -3
- tests/test_meta.py +23 -9
- tests/test_modified.py +4 -1
- tests/test_semaphore.py +15 -8
- tests/test_singleton.py +15 -10
- tests/test_task.py +126 -28
- ez_a_sync-0.22.14.dist-info/RECORD +0 -74
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/top_level.txt +0 -0
a_sync/a_sync/function.py
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
1
|
import functools
|
|
3
2
|
import inspect
|
|
4
3
|
import logging
|
|
5
4
|
import sys
|
|
6
5
|
|
|
7
6
|
from async_lru import _LRUCacheWrapper
|
|
8
|
-
from async_property.base import
|
|
9
|
-
|
|
10
|
-
from async_property.cached import \
|
|
11
|
-
AsyncCachedPropertyDescriptor # type: ignore [import]
|
|
7
|
+
from async_property.base import AsyncPropertyDescriptor # type: ignore [import]
|
|
8
|
+
from async_property.cached import AsyncCachedPropertyDescriptor # type: ignore [import]
|
|
12
9
|
|
|
13
10
|
from a_sync._typing import *
|
|
14
11
|
from a_sync.a_sync import _flags, _helpers, _kwargs
|
|
@@ -16,17 +13,23 @@ from a_sync.a_sync.modifiers.manager import ModifierManager
|
|
|
16
13
|
|
|
17
14
|
if TYPE_CHECKING:
|
|
18
15
|
from a_sync import TaskMapping
|
|
19
|
-
from a_sync.a_sync.method import (
|
|
20
|
-
|
|
16
|
+
from a_sync.a_sync.method import (
|
|
17
|
+
ASyncBoundMethod,
|
|
18
|
+
ASyncBoundMethodAsyncDefault,
|
|
19
|
+
ASyncBoundMethodSyncDefault,
|
|
20
|
+
)
|
|
21
21
|
|
|
22
22
|
logger = logging.getLogger(__name__)
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
class _ModifiedMixin:
|
|
25
26
|
"""
|
|
26
|
-
A mixin class that provides functionality for applying modifiers to functions.
|
|
27
|
+
A mixin class for internal use that provides functionality for applying modifiers to functions.
|
|
27
28
|
|
|
28
|
-
This class is used as a base for :class:`~ASyncFunction` and its variants
|
|
29
|
-
|
|
29
|
+
This class is used as a base for :class:`~ASyncFunction` and its variants, such as
|
|
30
|
+
`ASyncFunctionAsyncDefault` and `ASyncFunctionSyncDefault`, to handle the application
|
|
31
|
+
of async and sync modifiers to functions. Modifiers can alter the behavior of functions,
|
|
32
|
+
such as converting sync functions to async, applying caching, or rate limiting.
|
|
30
33
|
"""
|
|
31
34
|
|
|
32
35
|
modifiers: ModifierManager
|
|
@@ -34,13 +37,13 @@ class ModifiedMixin:
|
|
|
34
37
|
|
|
35
38
|
def _asyncify(self, func: SyncFn[P, T]) -> CoroFn[P, T]:
|
|
36
39
|
"""
|
|
37
|
-
|
|
40
|
+
Converts a synchronous function to an asynchronous one and applies async modifiers.
|
|
38
41
|
|
|
39
42
|
Args:
|
|
40
43
|
func: The synchronous function to be converted.
|
|
41
44
|
|
|
42
45
|
Returns:
|
|
43
|
-
|
|
46
|
+
The asynchronous version of the function with applied modifiers.
|
|
44
47
|
"""
|
|
45
48
|
coro_fn = _helpers._asyncify(func, self.modifiers.executor)
|
|
46
49
|
return self.modifiers.apply_async_modifiers(coro_fn)
|
|
@@ -48,39 +51,50 @@ class ModifiedMixin:
|
|
|
48
51
|
@functools.cached_property
|
|
49
52
|
def _await(self) -> Callable[[Awaitable[T]], T]:
|
|
50
53
|
"""
|
|
51
|
-
|
|
54
|
+
Applies sync modifiers to the _helpers._await function and caches it.
|
|
52
55
|
|
|
53
56
|
Returns:
|
|
54
|
-
|
|
57
|
+
The modified _await function.
|
|
55
58
|
"""
|
|
56
59
|
return self.modifiers.apply_sync_modifiers(_helpers._await)
|
|
57
60
|
|
|
58
61
|
@functools.cached_property
|
|
59
62
|
def default(self) -> DefaultMode:
|
|
60
63
|
"""
|
|
61
|
-
|
|
64
|
+
Gets the default execution mode (sync, async, or None) for the function.
|
|
62
65
|
|
|
63
66
|
Returns:
|
|
64
|
-
The default execution mode
|
|
67
|
+
The default execution mode.
|
|
65
68
|
"""
|
|
66
69
|
return self.modifiers.default
|
|
67
70
|
|
|
68
71
|
|
|
69
72
|
def _validate_wrapped_fn(fn: Callable) -> None:
|
|
70
|
-
"""Ensures 'fn' is an appropriate function for wrapping with a_sync.
|
|
73
|
+
"""Ensures 'fn' is an appropriate function for wrapping with a_sync.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
fn: The function to validate.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
TypeError: If the input is not callable.
|
|
80
|
+
RuntimeError: If the function has arguments with names that conflict with viable flags.
|
|
81
|
+
"""
|
|
71
82
|
if isinstance(fn, (AsyncPropertyDescriptor, AsyncCachedPropertyDescriptor)):
|
|
72
|
-
return
|
|
83
|
+
return # These are always valid
|
|
73
84
|
if not callable(fn):
|
|
74
|
-
raise TypeError(f
|
|
85
|
+
raise TypeError(f"Input is not callable. Unable to decorate {fn}")
|
|
75
86
|
if isinstance(fn, _LRUCacheWrapper):
|
|
76
87
|
fn = fn.__wrapped__
|
|
77
88
|
_check_not_genfunc(fn)
|
|
78
89
|
fn_args = inspect.getfullargspec(fn)[0]
|
|
79
90
|
for flag in _flags.VIABLE_FLAGS:
|
|
80
91
|
if flag in fn_args:
|
|
81
|
-
raise RuntimeError(
|
|
92
|
+
raise RuntimeError(
|
|
93
|
+
f"{fn} must not have any arguments with the following names: {_flags.VIABLE_FLAGS}"
|
|
94
|
+
)
|
|
95
|
+
|
|
82
96
|
|
|
83
|
-
class ASyncFunction(
|
|
97
|
+
class ASyncFunction(_ModifiedMixin, Generic[P, T]):
|
|
84
98
|
"""
|
|
85
99
|
A callable wrapper object that can be executed both synchronously and asynchronously.
|
|
86
100
|
|
|
@@ -92,7 +106,6 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
92
106
|
such as caching, rate limiting, and execution in specific contexts (e.g., thread pools).
|
|
93
107
|
|
|
94
108
|
Example:
|
|
95
|
-
```python
|
|
96
109
|
async def my_coroutine(x: int) -> str:
|
|
97
110
|
return str(x)
|
|
98
111
|
|
|
@@ -103,18 +116,23 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
103
116
|
|
|
104
117
|
# Asynchronous call
|
|
105
118
|
result = await func(5) # returns "5"
|
|
106
|
-
```
|
|
107
119
|
"""
|
|
108
120
|
|
|
109
121
|
# NOTE: We can't use __slots__ here because it breaks functools.update_wrapper
|
|
110
122
|
|
|
111
123
|
@overload
|
|
112
|
-
def __init__(self, fn: CoroFn[P, T], **modifiers: Unpack[ModifierKwargs]) -> None
|
|
124
|
+
def __init__(self, fn: CoroFn[P, T], **modifiers: Unpack[ModifierKwargs]) -> None:
|
|
125
|
+
...
|
|
126
|
+
# TODO write specific docs for this overload
|
|
127
|
+
|
|
113
128
|
@overload
|
|
114
|
-
def __init__(self, fn: SyncFn[P, T], **modifiers: Unpack[ModifierKwargs]) -> None
|
|
129
|
+
def __init__(self, fn: SyncFn[P, T], **modifiers: Unpack[ModifierKwargs]) -> None:
|
|
130
|
+
...
|
|
131
|
+
# TODO write specific docs for this overload
|
|
132
|
+
|
|
115
133
|
def __init__(self, fn: AnyFn[P, T], **modifiers: Unpack[ModifierKwargs]) -> None:
|
|
116
134
|
"""
|
|
117
|
-
|
|
135
|
+
Initializes an ASyncFunction instance.
|
|
118
136
|
|
|
119
137
|
Args:
|
|
120
138
|
fn: The function to wrap.
|
|
@@ -132,21 +150,44 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
132
150
|
if self.__doc__ is None:
|
|
133
151
|
self.__doc__ = f"Since `{self.__name__}` is an {self.__docstring_append__}"
|
|
134
152
|
else:
|
|
135
|
-
self.__doc__ +=
|
|
153
|
+
self.__doc__ += (
|
|
154
|
+
f"\n\nSince `{self.__name__}` is an {self.__docstring_append__}"
|
|
155
|
+
)
|
|
136
156
|
|
|
137
157
|
@overload
|
|
138
|
-
def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T
|
|
158
|
+
def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T:
|
|
159
|
+
...
|
|
160
|
+
# TODO write specific docs for this overload
|
|
161
|
+
|
|
139
162
|
@overload
|
|
140
|
-
def __call__(
|
|
163
|
+
def __call__(
|
|
164
|
+
self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
|
|
165
|
+
) -> Coroutine[Any, Any, T]:
|
|
166
|
+
...
|
|
167
|
+
# TODO write specific docs for this overload
|
|
168
|
+
|
|
141
169
|
@overload
|
|
142
|
-
def __call__(
|
|
170
|
+
def __call__(
|
|
171
|
+
self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
|
|
172
|
+
) -> T:
|
|
173
|
+
...
|
|
174
|
+
# TODO write specific docs for this overload
|
|
175
|
+
|
|
143
176
|
@overload
|
|
144
|
-
def __call__(
|
|
177
|
+
def __call__(
|
|
178
|
+
self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
|
|
179
|
+
) -> Coroutine[Any, Any, T]:
|
|
180
|
+
...
|
|
181
|
+
# TODO write specific docs for this overload
|
|
182
|
+
|
|
145
183
|
@overload
|
|
146
|
-
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]
|
|
184
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]:
|
|
185
|
+
...
|
|
186
|
+
# TODO write specific docs for this overload
|
|
187
|
+
|
|
147
188
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]:
|
|
148
189
|
"""
|
|
149
|
-
|
|
190
|
+
Calls the wrapped function either synchronously or asynchronously.
|
|
150
191
|
|
|
151
192
|
This method determines whether to execute the wrapped function synchronously
|
|
152
193
|
or asynchronously based on the default mode and any provided flags.
|
|
@@ -155,20 +196,21 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
155
196
|
*args: Positional arguments to pass to the wrapped function.
|
|
156
197
|
**kwargs: Keyword arguments to pass to the wrapped function.
|
|
157
198
|
|
|
158
|
-
Returns:
|
|
159
|
-
The result of the wrapped function call, which may be a coroutine if run asynchronously.
|
|
160
|
-
|
|
161
199
|
Raises:
|
|
162
200
|
Exception: Any exception that may be raised by the wrapped function.
|
|
163
201
|
"""
|
|
164
|
-
logger.debug(
|
|
202
|
+
logger.debug(
|
|
203
|
+
"calling %s fn: %s with args: %s kwargs: %s", self, self.fn, args, kwargs
|
|
204
|
+
)
|
|
165
205
|
return self.fn(*args, **kwargs)
|
|
166
206
|
|
|
167
207
|
def __repr__(self) -> str:
|
|
168
208
|
return f"<{self.__class__.__name__} {self.__module__}.{self.__name__} at {hex(id(self))}>"
|
|
169
209
|
|
|
170
210
|
@functools.cached_property
|
|
171
|
-
def fn(
|
|
211
|
+
def fn(
|
|
212
|
+
self,
|
|
213
|
+
): # -> Union[SyncFn[[CoroFn[P, T]], MaybeAwaitable[T]], SyncFn[[SyncFn[P, T]], MaybeAwaitable[T]]]:
|
|
172
214
|
"""
|
|
173
215
|
Returns the final wrapped version of :attr:`ASyncFunction._fn` decorated with all of the a_sync goodness.
|
|
174
216
|
|
|
@@ -179,9 +221,15 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
179
221
|
|
|
180
222
|
if sys.version_info >= (3, 11) or TYPE_CHECKING:
|
|
181
223
|
# we can specify P.args in python>=3.11 but in lower versions it causes a crash. Everything should still type check correctly on all versions.
|
|
182
|
-
def map(
|
|
224
|
+
def map(
|
|
225
|
+
self,
|
|
226
|
+
*iterables: AnyIterable[P.args],
|
|
227
|
+
concurrency: Optional[int] = None,
|
|
228
|
+
task_name: str = "",
|
|
229
|
+
**function_kwargs: P.kwargs,
|
|
230
|
+
) -> "TaskMapping[P, T]":
|
|
183
231
|
"""
|
|
184
|
-
|
|
232
|
+
Creates a TaskMapping for the wrapped function with the given iterables.
|
|
185
233
|
|
|
186
234
|
Args:
|
|
187
235
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -190,14 +238,27 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
190
238
|
**function_kwargs: Additional keyword arguments to pass to the function.
|
|
191
239
|
|
|
192
240
|
Returns:
|
|
193
|
-
A TaskMapping object.
|
|
241
|
+
A TaskMapping object for managing concurrent execution.
|
|
194
242
|
"""
|
|
195
243
|
from a_sync import TaskMapping
|
|
196
|
-
return TaskMapping(self, *iterables, concurrency=concurrency, name=task_name, **function_kwargs)
|
|
197
244
|
|
|
198
|
-
|
|
245
|
+
return TaskMapping(
|
|
246
|
+
self,
|
|
247
|
+
*iterables,
|
|
248
|
+
concurrency=concurrency,
|
|
249
|
+
name=task_name,
|
|
250
|
+
**function_kwargs,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
async def any(
|
|
254
|
+
self,
|
|
255
|
+
*iterables: AnyIterable[P.args],
|
|
256
|
+
concurrency: Optional[int] = None,
|
|
257
|
+
task_name: str = "",
|
|
258
|
+
**function_kwargs: P.kwargs,
|
|
259
|
+
) -> bool:
|
|
199
260
|
"""
|
|
200
|
-
|
|
261
|
+
Checks if any result of the function applied to the iterables is truthy.
|
|
201
262
|
|
|
202
263
|
Args:
|
|
203
264
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -206,13 +267,24 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
206
267
|
**function_kwargs: Additional keyword arguments to pass to the function.
|
|
207
268
|
|
|
208
269
|
Returns:
|
|
209
|
-
|
|
270
|
+
True if any result is truthy, otherwise False.
|
|
210
271
|
"""
|
|
211
|
-
return await self.map(
|
|
212
|
-
|
|
213
|
-
|
|
272
|
+
return await self.map(
|
|
273
|
+
*iterables,
|
|
274
|
+
concurrency=concurrency,
|
|
275
|
+
task_name=task_name,
|
|
276
|
+
**function_kwargs,
|
|
277
|
+
).any(pop=True, sync=False)
|
|
278
|
+
|
|
279
|
+
async def all(
|
|
280
|
+
self,
|
|
281
|
+
*iterables: AnyIterable[P.args],
|
|
282
|
+
concurrency: Optional[int] = None,
|
|
283
|
+
task_name: str = "",
|
|
284
|
+
**function_kwargs: P.kwargs,
|
|
285
|
+
) -> bool:
|
|
214
286
|
"""
|
|
215
|
-
|
|
287
|
+
Checks if all results of the function applied to the iterables are truthy.
|
|
216
288
|
|
|
217
289
|
Args:
|
|
218
290
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -221,13 +293,24 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
221
293
|
**function_kwargs: Additional keyword arguments to pass to the function.
|
|
222
294
|
|
|
223
295
|
Returns:
|
|
224
|
-
|
|
296
|
+
True if all results are truthy, otherwise False.
|
|
225
297
|
"""
|
|
226
|
-
return await self.map(
|
|
227
|
-
|
|
228
|
-
|
|
298
|
+
return await self.map(
|
|
299
|
+
*iterables,
|
|
300
|
+
concurrency=concurrency,
|
|
301
|
+
task_name=task_name,
|
|
302
|
+
**function_kwargs,
|
|
303
|
+
).all(pop=True, sync=False)
|
|
304
|
+
|
|
305
|
+
async def min(
|
|
306
|
+
self,
|
|
307
|
+
*iterables: AnyIterable[P.args],
|
|
308
|
+
concurrency: Optional[int] = None,
|
|
309
|
+
task_name: str = "",
|
|
310
|
+
**function_kwargs: P.kwargs,
|
|
311
|
+
) -> T:
|
|
229
312
|
"""
|
|
230
|
-
|
|
313
|
+
Finds the minimum result of the function applied to the iterables.
|
|
231
314
|
|
|
232
315
|
Args:
|
|
233
316
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -238,11 +321,22 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
238
321
|
Returns:
|
|
239
322
|
The minimum result.
|
|
240
323
|
"""
|
|
241
|
-
return await self.map(
|
|
242
|
-
|
|
243
|
-
|
|
324
|
+
return await self.map(
|
|
325
|
+
*iterables,
|
|
326
|
+
concurrency=concurrency,
|
|
327
|
+
task_name=task_name,
|
|
328
|
+
**function_kwargs,
|
|
329
|
+
).min(pop=True, sync=False)
|
|
330
|
+
|
|
331
|
+
async def max(
|
|
332
|
+
self,
|
|
333
|
+
*iterables: AnyIterable[P.args],
|
|
334
|
+
concurrency: Optional[int] = None,
|
|
335
|
+
task_name: str = "",
|
|
336
|
+
**function_kwargs: P.kwargs,
|
|
337
|
+
) -> T:
|
|
244
338
|
"""
|
|
245
|
-
|
|
339
|
+
Finds the maximum result of the function applied to the iterables.
|
|
246
340
|
|
|
247
341
|
Args:
|
|
248
342
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -253,11 +347,22 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
253
347
|
Returns:
|
|
254
348
|
The maximum result.
|
|
255
349
|
"""
|
|
256
|
-
return await self.map(
|
|
257
|
-
|
|
258
|
-
|
|
350
|
+
return await self.map(
|
|
351
|
+
*iterables,
|
|
352
|
+
concurrency=concurrency,
|
|
353
|
+
task_name=task_name,
|
|
354
|
+
**function_kwargs,
|
|
355
|
+
).max(pop=True, sync=False)
|
|
356
|
+
|
|
357
|
+
async def sum(
|
|
358
|
+
self,
|
|
359
|
+
*iterables: AnyIterable[P.args],
|
|
360
|
+
concurrency: Optional[int] = None,
|
|
361
|
+
task_name: str = "",
|
|
362
|
+
**function_kwargs: P.kwargs,
|
|
363
|
+
) -> T:
|
|
259
364
|
"""
|
|
260
|
-
|
|
365
|
+
Calculates the sum of the results of the function applied to the iterables.
|
|
261
366
|
|
|
262
367
|
Args:
|
|
263
368
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -268,11 +373,24 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
268
373
|
Returns:
|
|
269
374
|
The sum of the results.
|
|
270
375
|
"""
|
|
271
|
-
return await self.map(
|
|
376
|
+
return await self.map(
|
|
377
|
+
*iterables,
|
|
378
|
+
concurrency=concurrency,
|
|
379
|
+
task_name=task_name,
|
|
380
|
+
**function_kwargs,
|
|
381
|
+
).sum(pop=True, sync=False)
|
|
382
|
+
|
|
272
383
|
else:
|
|
273
|
-
|
|
384
|
+
|
|
385
|
+
def map(
|
|
386
|
+
self,
|
|
387
|
+
*iterables: AnyIterable[Any],
|
|
388
|
+
concurrency: Optional[int] = None,
|
|
389
|
+
task_name: str = "",
|
|
390
|
+
**function_kwargs: P.kwargs,
|
|
391
|
+
) -> "TaskMapping[P, T]":
|
|
274
392
|
"""
|
|
275
|
-
|
|
393
|
+
Creates a TaskMapping for the wrapped function with the given iterables.
|
|
276
394
|
|
|
277
395
|
Args:
|
|
278
396
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -281,14 +399,27 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
281
399
|
**function_kwargs: Additional keyword arguments to pass to the function.
|
|
282
400
|
|
|
283
401
|
Returns:
|
|
284
|
-
A TaskMapping object.
|
|
402
|
+
A TaskMapping object for managing concurrent execution.
|
|
285
403
|
"""
|
|
286
404
|
from a_sync import TaskMapping
|
|
287
|
-
return TaskMapping(self, *iterables, concurrency=concurrency, name=task_name, **function_kwargs)
|
|
288
405
|
|
|
289
|
-
|
|
406
|
+
return TaskMapping(
|
|
407
|
+
self,
|
|
408
|
+
*iterables,
|
|
409
|
+
concurrency=concurrency,
|
|
410
|
+
name=task_name,
|
|
411
|
+
**function_kwargs,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
async def any(
|
|
415
|
+
self,
|
|
416
|
+
*iterables: AnyIterable[Any],
|
|
417
|
+
concurrency: Optional[int] = None,
|
|
418
|
+
task_name: str = "",
|
|
419
|
+
**function_kwargs: P.kwargs,
|
|
420
|
+
) -> bool:
|
|
290
421
|
"""
|
|
291
|
-
|
|
422
|
+
Checks if any result of the function applied to the iterables is truthy.
|
|
292
423
|
|
|
293
424
|
Args:
|
|
294
425
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -297,13 +428,24 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
297
428
|
**function_kwargs: Additional keyword arguments to pass to the function.
|
|
298
429
|
|
|
299
430
|
Returns:
|
|
300
|
-
|
|
431
|
+
True if any result is truthy, otherwise False.
|
|
301
432
|
"""
|
|
302
|
-
return await self.map(
|
|
303
|
-
|
|
304
|
-
|
|
433
|
+
return await self.map(
|
|
434
|
+
*iterables,
|
|
435
|
+
concurrency=concurrency,
|
|
436
|
+
task_name=task_name,
|
|
437
|
+
**function_kwargs,
|
|
438
|
+
).any(pop=True, sync=False)
|
|
439
|
+
|
|
440
|
+
async def all(
|
|
441
|
+
self,
|
|
442
|
+
*iterables: AnyIterable[Any],
|
|
443
|
+
concurrency: Optional[int] = None,
|
|
444
|
+
task_name: str = "",
|
|
445
|
+
**function_kwargs: P.kwargs,
|
|
446
|
+
) -> bool:
|
|
305
447
|
"""
|
|
306
|
-
|
|
448
|
+
Checks if all results of the function applied to the iterables are truthy.
|
|
307
449
|
|
|
308
450
|
Args:
|
|
309
451
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -312,13 +454,24 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
312
454
|
**function_kwargs: Additional keyword arguments to pass to the function.
|
|
313
455
|
|
|
314
456
|
Returns:
|
|
315
|
-
|
|
457
|
+
True if all results are truthy, otherwise False.
|
|
316
458
|
"""
|
|
317
|
-
return await self.map(
|
|
318
|
-
|
|
319
|
-
|
|
459
|
+
return await self.map(
|
|
460
|
+
*iterables,
|
|
461
|
+
concurrency=concurrency,
|
|
462
|
+
task_name=task_name,
|
|
463
|
+
**function_kwargs,
|
|
464
|
+
).all(pop=True, sync=False)
|
|
465
|
+
|
|
466
|
+
async def min(
|
|
467
|
+
self,
|
|
468
|
+
*iterables: AnyIterable[Any],
|
|
469
|
+
concurrency: Optional[int] = None,
|
|
470
|
+
task_name: str = "",
|
|
471
|
+
**function_kwargs: P.kwargs,
|
|
472
|
+
) -> T:
|
|
320
473
|
"""
|
|
321
|
-
|
|
474
|
+
Finds the minimum result of the function applied to the iterables.
|
|
322
475
|
|
|
323
476
|
Args:
|
|
324
477
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -329,11 +482,22 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
329
482
|
Returns:
|
|
330
483
|
The minimum result.
|
|
331
484
|
"""
|
|
332
|
-
return await self.map(
|
|
333
|
-
|
|
334
|
-
|
|
485
|
+
return await self.map(
|
|
486
|
+
*iterables,
|
|
487
|
+
concurrency=concurrency,
|
|
488
|
+
task_name=task_name,
|
|
489
|
+
**function_kwargs,
|
|
490
|
+
).min(pop=True, sync=False)
|
|
491
|
+
|
|
492
|
+
async def max(
|
|
493
|
+
self,
|
|
494
|
+
*iterables: AnyIterable[Any],
|
|
495
|
+
concurrency: Optional[int] = None,
|
|
496
|
+
task_name: str = "",
|
|
497
|
+
**function_kwargs: P.kwargs,
|
|
498
|
+
) -> T:
|
|
335
499
|
"""
|
|
336
|
-
|
|
500
|
+
Finds the maximum result of the function applied to the iterables.
|
|
337
501
|
|
|
338
502
|
Args:
|
|
339
503
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -344,11 +508,22 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
344
508
|
Returns:
|
|
345
509
|
The maximum result.
|
|
346
510
|
"""
|
|
347
|
-
return await self.map(
|
|
348
|
-
|
|
349
|
-
|
|
511
|
+
return await self.map(
|
|
512
|
+
*iterables,
|
|
513
|
+
concurrency=concurrency,
|
|
514
|
+
task_name=task_name,
|
|
515
|
+
**function_kwargs,
|
|
516
|
+
).max(pop=True, sync=False)
|
|
517
|
+
|
|
518
|
+
async def sum(
|
|
519
|
+
self,
|
|
520
|
+
*iterables: AnyIterable[Any],
|
|
521
|
+
concurrency: Optional[int] = None,
|
|
522
|
+
task_name: str = "",
|
|
523
|
+
**function_kwargs: P.kwargs,
|
|
524
|
+
) -> T:
|
|
350
525
|
"""
|
|
351
|
-
|
|
526
|
+
Calculates the sum of the results of the function applied to the iterables.
|
|
352
527
|
|
|
353
528
|
Args:
|
|
354
529
|
*iterables: Iterable objects to be used as arguments for the function.
|
|
@@ -359,34 +534,43 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
359
534
|
Returns:
|
|
360
535
|
The sum of the results.
|
|
361
536
|
"""
|
|
362
|
-
return await self.map(
|
|
537
|
+
return await self.map(
|
|
538
|
+
*iterables,
|
|
539
|
+
concurrency=concurrency,
|
|
540
|
+
task_name=task_name,
|
|
541
|
+
**function_kwargs,
|
|
542
|
+
).sum(pop=True, sync=False)
|
|
363
543
|
|
|
364
544
|
@functools.cached_property
|
|
365
545
|
def _sync_default(self) -> bool:
|
|
366
546
|
"""
|
|
367
|
-
|
|
547
|
+
Determines the default execution mode (sync or async) for the function.
|
|
368
548
|
|
|
369
549
|
If the user did not specify a default, this method defers to the function's
|
|
370
550
|
definition (sync vs async def).
|
|
371
551
|
|
|
372
552
|
Returns:
|
|
373
|
-
True if the default is sync, False if
|
|
553
|
+
True if the default is sync, False if async.
|
|
374
554
|
"""
|
|
375
|
-
return
|
|
555
|
+
return (
|
|
556
|
+
True
|
|
557
|
+
if self.default == "sync"
|
|
558
|
+
else False if self.default == "async" else not self._async_def
|
|
559
|
+
)
|
|
376
560
|
|
|
377
561
|
@functools.cached_property
|
|
378
562
|
def _async_def(self) -> bool:
|
|
379
563
|
"""
|
|
380
|
-
|
|
564
|
+
Checks if the wrapped function is an asynchronous function.
|
|
381
565
|
|
|
382
566
|
Returns:
|
|
383
|
-
True if the
|
|
567
|
+
True if the function is asynchronous, otherwise False.
|
|
384
568
|
"""
|
|
385
569
|
return asyncio.iscoroutinefunction(self.__wrapped__)
|
|
386
570
|
|
|
387
571
|
def _run_sync(self, kwargs: dict) -> bool:
|
|
388
572
|
"""
|
|
389
|
-
|
|
573
|
+
Determines whether to run the function synchronously or asynchronously.
|
|
390
574
|
|
|
391
575
|
This method checks for a flag in the kwargs and defers to it if present.
|
|
392
576
|
If no flag is specified, it defers to the default execution mode.
|
|
@@ -395,7 +579,7 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
395
579
|
kwargs: The keyword arguments passed to the function.
|
|
396
580
|
|
|
397
581
|
Returns:
|
|
398
|
-
True if the function should
|
|
582
|
+
True if the function should run synchronously, otherwise False.
|
|
399
583
|
"""
|
|
400
584
|
if flag := _kwargs.get_flag_name(kwargs):
|
|
401
585
|
# If a flag was specified in the kwargs, we will defer to it.
|
|
@@ -407,88 +591,129 @@ class ASyncFunction(ModifiedMixin, Generic[P, T]):
|
|
|
407
591
|
@functools.cached_property
|
|
408
592
|
def _asyncified(self) -> CoroFn[P, T]:
|
|
409
593
|
"""
|
|
410
|
-
|
|
594
|
+
Converts the wrapped function to an asynchronous function and applies both sync and async modifiers.
|
|
595
|
+
|
|
596
|
+
Raises:
|
|
597
|
+
TypeError: If the wrapped function is already asynchronous.
|
|
411
598
|
|
|
412
599
|
Returns:
|
|
413
|
-
|
|
600
|
+
The asynchronous version of the wrapped function.
|
|
414
601
|
"""
|
|
415
602
|
if self._async_def:
|
|
416
|
-
raise TypeError(
|
|
603
|
+
raise TypeError(
|
|
604
|
+
f"Can only be applied to sync functions, not {self.__wrapped__}"
|
|
605
|
+
)
|
|
417
606
|
return self._asyncify(self._modified_fn) # type: ignore [arg-type]
|
|
418
607
|
|
|
419
608
|
@functools.cached_property
|
|
420
609
|
def _modified_fn(self) -> AnyFn[P, T]:
|
|
421
610
|
"""
|
|
422
|
-
|
|
611
|
+
Applies modifiers to the wrapped function.
|
|
423
612
|
|
|
424
613
|
If the wrapped function is an asynchronous function, this method applies async modifiers.
|
|
425
614
|
If the wrapped function is a synchronous function, this method applies sync modifiers.
|
|
426
615
|
|
|
427
616
|
Returns:
|
|
428
|
-
The
|
|
617
|
+
The modified function.
|
|
429
618
|
"""
|
|
430
619
|
if self._async_def:
|
|
431
620
|
return self.modifiers.apply_async_modifiers(self.__wrapped__) # type: ignore [arg-type]
|
|
432
621
|
return self.modifiers.apply_sync_modifiers(self.__wrapped__) # type: ignore [return-value]
|
|
433
622
|
|
|
434
623
|
@functools.cached_property
|
|
435
|
-
def _async_wrap(self):
|
|
624
|
+
def _async_wrap(self): # -> SyncFn[[CoroFn[P, T]], MaybeAwaitable[T]]:
|
|
436
625
|
"""
|
|
437
626
|
The final wrapper if the wrapped function is an asynchronous function.
|
|
438
627
|
|
|
439
628
|
This method applies the appropriate modifiers and determines whether to await the result.
|
|
440
629
|
|
|
441
630
|
Returns:
|
|
442
|
-
The
|
|
631
|
+
The wrapped function with async handling.
|
|
443
632
|
"""
|
|
633
|
+
|
|
444
634
|
@functools.wraps(self._modified_fn)
|
|
445
635
|
def async_wrap(*args: P.args, **kwargs: P.kwargs) -> MaybeAwaitable[T]: # type: ignore [name-defined]
|
|
446
|
-
should_await = self._run_sync(
|
|
636
|
+
should_await = self._run_sync(
|
|
637
|
+
kwargs
|
|
638
|
+
) # Must take place before coro is created, we're popping a kwarg.
|
|
447
639
|
coro = self._modified_fn(*args, **kwargs)
|
|
448
640
|
return self._await(coro) if should_await else coro
|
|
641
|
+
|
|
449
642
|
return async_wrap
|
|
450
643
|
|
|
451
644
|
@functools.cached_property
|
|
452
|
-
def _sync_wrap(self):
|
|
645
|
+
def _sync_wrap(self): # -> SyncFn[[SyncFn[P, T]], MaybeAwaitable[T]]:
|
|
453
646
|
"""
|
|
454
647
|
The final wrapper if the wrapped function is a synchronous function.
|
|
455
648
|
|
|
456
649
|
This method applies the appropriate modifiers and determines whether to run the function synchronously or asynchronously.
|
|
457
650
|
|
|
458
651
|
Returns:
|
|
459
|
-
The
|
|
652
|
+
The wrapped function with sync handling.
|
|
460
653
|
"""
|
|
654
|
+
|
|
461
655
|
@functools.wraps(self._modified_fn)
|
|
462
656
|
def sync_wrap(*args: P.args, **kwargs: P.kwargs) -> MaybeAwaitable[T]: # type: ignore [name-defined]
|
|
463
657
|
if self._run_sync(kwargs):
|
|
464
658
|
return self._modified_fn(*args, **kwargs)
|
|
465
|
-
return self._asyncified(*args, **kwargs)
|
|
659
|
+
return self._asyncified(*args, **kwargs)
|
|
660
|
+
|
|
466
661
|
return sync_wrap
|
|
467
662
|
|
|
468
663
|
__docstring_append__ = ":class:`~a_sync.a_sync.function.ASyncFunction`, you can optionally pass either a `sync` or `asynchronous` kwarg with a boolean value."
|
|
469
664
|
|
|
665
|
+
|
|
470
666
|
if sys.version_info < (3, 10):
|
|
471
667
|
_inherit = ASyncFunction[AnyFn[P, T], ASyncFunction[P, T]]
|
|
472
668
|
else:
|
|
473
669
|
_inherit = ASyncFunction[[AnyFn[P, T]], ASyncFunction[P, T]]
|
|
474
|
-
|
|
475
|
-
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
class ASyncDecorator(_ModifiedMixin):
|
|
476
673
|
def __init__(self, **modifiers: Unpack[ModifierKwargs]) -> None:
|
|
477
|
-
|
|
674
|
+
"""
|
|
675
|
+
Initializes an ASyncDecorator instance.
|
|
676
|
+
|
|
677
|
+
Args:
|
|
678
|
+
**modifiers: Keyword arguments for function modifiers.
|
|
679
|
+
|
|
680
|
+
Raises:
|
|
681
|
+
ValueError: If 'default' is not 'sync', 'async', or None.
|
|
682
|
+
"""
|
|
683
|
+
assert "default" in modifiers, modifiers
|
|
478
684
|
self.modifiers = ModifierManager(modifiers)
|
|
479
685
|
self.validate_inputs()
|
|
480
|
-
|
|
686
|
+
|
|
481
687
|
def validate_inputs(self) -> None:
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
688
|
+
"""
|
|
689
|
+
Validates the input modifiers.
|
|
690
|
+
|
|
691
|
+
Raises:
|
|
692
|
+
ValueError: If 'default' is not 'sync', 'async', or None.
|
|
693
|
+
"""
|
|
694
|
+
if self.modifiers.default not in ["sync", "async", None]:
|
|
695
|
+
raise ValueError(
|
|
696
|
+
f"'default' must be either 'sync', 'async', or None. You passed {self.modifiers.default}."
|
|
697
|
+
)
|
|
698
|
+
|
|
485
699
|
@overload
|
|
486
700
|
def __call__(self, func: AnyFn[Concatenate[B, P], T]) -> "ASyncBoundMethod[B, P, T]": # type: ignore [override]
|
|
487
|
-
...
|
|
701
|
+
... # TODO write specific docs for this overload
|
|
702
|
+
|
|
488
703
|
@overload
|
|
489
704
|
def __call__(self, func: AnyFn[P, T]) -> ASyncFunction[P, T]: # type: ignore [override]
|
|
490
|
-
...
|
|
705
|
+
... # TODO write specific docs for this overload
|
|
706
|
+
|
|
491
707
|
def __call__(self, func: AnyFn[P, T]) -> ASyncFunction[P, T]: # type: ignore [override]
|
|
708
|
+
"""
|
|
709
|
+
Decorates a function with async or sync behavior based on the default modifier.
|
|
710
|
+
|
|
711
|
+
Args:
|
|
712
|
+
func: The function to decorate.
|
|
713
|
+
|
|
714
|
+
Returns:
|
|
715
|
+
An ASyncFunction instance with the appropriate default behavior.
|
|
716
|
+
"""
|
|
492
717
|
if self.default == "async":
|
|
493
718
|
return ASyncFunctionAsyncDefault(func, **self.modifiers)
|
|
494
719
|
elif self.default == "sync":
|
|
@@ -498,13 +723,23 @@ class ASyncDecorator(ModifiedMixin):
|
|
|
498
723
|
else:
|
|
499
724
|
return ASyncFunctionSyncDefault(func, **self.modifiers)
|
|
500
725
|
|
|
726
|
+
|
|
501
727
|
def _check_not_genfunc(func: Callable) -> None:
|
|
728
|
+
"""Raises an error if the function is a generator or async generator.
|
|
729
|
+
|
|
730
|
+
Args:
|
|
731
|
+
func: The function to check.
|
|
732
|
+
|
|
733
|
+
Raises:
|
|
734
|
+
ValueError: If the function is a generator or async generator.
|
|
735
|
+
"""
|
|
502
736
|
if inspect.isasyncgenfunction(func) or inspect.isgeneratorfunction(func):
|
|
503
737
|
raise ValueError("unable to decorate generator functions with this decorator")
|
|
504
738
|
|
|
505
739
|
|
|
506
740
|
# Mypy helper classes
|
|
507
741
|
|
|
742
|
+
|
|
508
743
|
class ASyncFunctionSyncDefault(ASyncFunction[P, T]):
|
|
509
744
|
"""A specialized :class:`~ASyncFunction` that defaults to synchronous execution.
|
|
510
745
|
|
|
@@ -516,7 +751,6 @@ class ASyncFunctionSyncDefault(ASyncFunction[P, T]):
|
|
|
516
751
|
or `asynchronous=True` as a keyword argument.
|
|
517
752
|
|
|
518
753
|
Example:
|
|
519
|
-
```python
|
|
520
754
|
@a_sync(default='sync')
|
|
521
755
|
async def my_function(x: int) -> str:
|
|
522
756
|
return str(x)
|
|
@@ -526,20 +760,30 @@ class ASyncFunctionSyncDefault(ASyncFunction[P, T]):
|
|
|
526
760
|
|
|
527
761
|
# Asynchronous call
|
|
528
762
|
result = await my_function(5, sync=False) # returns "5"
|
|
529
|
-
```
|
|
530
763
|
"""
|
|
764
|
+
|
|
531
765
|
@overload
|
|
532
|
-
def __call__(
|
|
766
|
+
def __call__(
|
|
767
|
+
self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs
|
|
768
|
+
) -> T: ... # TODO write specific docs for this overload
|
|
533
769
|
@overload
|
|
534
|
-
def __call__(
|
|
770
|
+
def __call__(
|
|
771
|
+
self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
|
|
772
|
+
) -> Coroutine[Any, Any, T]: ... # TODO write specific docs for this overload
|
|
535
773
|
@overload
|
|
536
|
-
def __call__(
|
|
774
|
+
def __call__(
|
|
775
|
+
self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
|
|
776
|
+
) -> T: ... # TODO write specific docs for this overload
|
|
537
777
|
@overload
|
|
538
|
-
def __call__(
|
|
778
|
+
def __call__(
|
|
779
|
+
self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
|
|
780
|
+
) -> Coroutine[Any, Any, T]: ... # TODO write specific docs for this overload
|
|
539
781
|
@overload
|
|
540
|
-
def __call__(
|
|
782
|
+
def __call__(
|
|
783
|
+
self, *args: P.args, **kwargs: P.kwargs
|
|
784
|
+
) -> T: ... # TODO write specific docs for this overload
|
|
541
785
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]:
|
|
542
|
-
"""
|
|
786
|
+
"""Calls the wrapped function, defaulting to synchronous execution.
|
|
543
787
|
|
|
544
788
|
This method overrides the base :meth:`ASyncFunction.__call__` to provide a synchronous
|
|
545
789
|
default behavior.
|
|
@@ -548,29 +792,29 @@ class ASyncFunctionSyncDefault(ASyncFunction[P, T]):
|
|
|
548
792
|
*args: Positional arguments to pass to the wrapped function.
|
|
549
793
|
**kwargs: Keyword arguments to pass to the wrapped function.
|
|
550
794
|
|
|
551
|
-
Returns:
|
|
552
|
-
The result of the wrapped function call.
|
|
553
|
-
|
|
554
795
|
Raises:
|
|
555
796
|
Exception: Any exception that may be raised by the wrapped function.
|
|
797
|
+
|
|
798
|
+
Returns:
|
|
799
|
+
The result of the function call.
|
|
556
800
|
"""
|
|
557
801
|
return self.fn(*args, **kwargs)
|
|
558
802
|
|
|
559
803
|
__docstring_append__ = ":class:`~a_sync.a_sync.function.ASyncFunctionSyncDefault`, you can optionally pass `sync=False` or `asynchronous=True` to force it to return a coroutine. Without either kwarg, it will run synchronously."
|
|
560
|
-
|
|
804
|
+
|
|
805
|
+
|
|
561
806
|
class ASyncFunctionAsyncDefault(ASyncFunction[P, T]):
|
|
562
807
|
"""
|
|
563
808
|
A specialized :class:`~ASyncFunction` that defaults to asynchronous execution.
|
|
564
809
|
|
|
565
810
|
This class is used when the :func:`~a_sync` decorator is applied with `default='async'`.
|
|
566
|
-
It provides type hints to indicate that the default call behavior is asynchronous
|
|
811
|
+
It provides type hints to indicate that the default call behavior is asynchronous
|
|
567
812
|
and supports IDE type checking for most use cases.
|
|
568
813
|
|
|
569
814
|
The wrapped function can still be called synchronously by passing `sync=True`
|
|
570
815
|
or `asynchronous=False` as a keyword argument.
|
|
571
816
|
|
|
572
817
|
Example:
|
|
573
|
-
```python
|
|
574
818
|
@a_sync(default='async')
|
|
575
819
|
async def my_function(x: int) -> str:
|
|
576
820
|
return str(x)
|
|
@@ -580,20 +824,36 @@ class ASyncFunctionAsyncDefault(ASyncFunction[P, T]):
|
|
|
580
824
|
|
|
581
825
|
# Synchronous call
|
|
582
826
|
result = my_function(5, sync=True) # returns "5"
|
|
583
|
-
```
|
|
584
827
|
"""
|
|
828
|
+
|
|
585
829
|
@overload
|
|
586
|
-
def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T
|
|
830
|
+
def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
|
|
831
|
+
|
|
832
|
+
# TODO write specific docs for this overload
|
|
587
833
|
@overload
|
|
588
|
-
def __call__(
|
|
834
|
+
def __call__(
|
|
835
|
+
self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
|
|
836
|
+
) -> Coroutine[Any, Any, T]: ...
|
|
837
|
+
|
|
838
|
+
# TODO write specific docs for this overload
|
|
589
839
|
@overload
|
|
590
|
-
def __call__(
|
|
840
|
+
def __call__(
|
|
841
|
+
self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
|
|
842
|
+
) -> T: ...
|
|
843
|
+
|
|
844
|
+
# TODO write specific docs for this overload
|
|
591
845
|
@overload
|
|
592
|
-
def __call__(
|
|
846
|
+
def __call__(
|
|
847
|
+
self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
|
|
848
|
+
) -> Coroutine[Any, Any, T]: ...
|
|
849
|
+
|
|
850
|
+
# TODO write specific docs for this overload
|
|
593
851
|
@overload
|
|
594
|
-
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T]
|
|
852
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T]: ...
|
|
853
|
+
|
|
854
|
+
# TODO write specific docs for this overload
|
|
595
855
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]:
|
|
596
|
-
"""
|
|
856
|
+
"""Calls the wrapped function, defaulting to asynchronous execution.
|
|
597
857
|
|
|
598
858
|
This method overrides the base :meth:`ASyncFunction.__call__` to provide an asynchronous
|
|
599
859
|
default behavior.
|
|
@@ -602,39 +862,49 @@ class ASyncFunctionAsyncDefault(ASyncFunction[P, T]):
|
|
|
602
862
|
*args: Positional arguments to pass to the wrapped function.
|
|
603
863
|
**kwargs: Keyword arguments to pass to the wrapped function.
|
|
604
864
|
|
|
605
|
-
Returns:
|
|
606
|
-
A coroutine object representing the asynchronous execution of the wrapped function.
|
|
607
|
-
|
|
608
865
|
Raises:
|
|
609
866
|
Exception: Any exception that may be raised by the wrapped function.
|
|
867
|
+
|
|
868
|
+
Returns:
|
|
869
|
+
The result of the function call.
|
|
610
870
|
"""
|
|
611
871
|
return self.fn(*args, **kwargs)
|
|
612
872
|
|
|
613
873
|
__docstring_append__ = ":class:`~a_sync.a_sync.function.ASyncFunctionAsyncDefault`, you can optionally pass `sync=True` or `asynchronous=False` to force it to run synchronously and return a value. Without either kwarg, it will return a coroutine for you to await."
|
|
614
874
|
|
|
875
|
+
|
|
615
876
|
class ASyncDecoratorSyncDefault(ASyncDecorator):
|
|
616
877
|
@overload
|
|
617
878
|
def __call__(self, func: AnyFn[Concatenate[B, P], T]) -> "ASyncBoundMethodSyncDefault[P, T]": # type: ignore [override]
|
|
618
879
|
...
|
|
880
|
+
# TODO write specific docs for this overload
|
|
881
|
+
|
|
619
882
|
@overload
|
|
620
883
|
def __call__(self, func: AnyBoundMethod[P, T]) -> ASyncFunctionSyncDefault[P, T]: # type: ignore [override]
|
|
621
|
-
...
|
|
884
|
+
... # TODO write specific docs for this overload
|
|
885
|
+
|
|
622
886
|
@overload
|
|
623
887
|
def __call__(self, func: AnyFn[P, T]) -> ASyncFunctionSyncDefault[P, T]: # type: ignore [override]
|
|
624
|
-
...
|
|
888
|
+
... # TODO write specific docs for this overload
|
|
889
|
+
|
|
625
890
|
def __call__(self, func: AnyFn[P, T]) -> ASyncFunctionSyncDefault[P, T]:
|
|
891
|
+
... # TODO write specific docs for this overload
|
|
626
892
|
return ASyncFunctionSyncDefault(func, **self.modifiers)
|
|
627
893
|
|
|
894
|
+
|
|
628
895
|
class ASyncDecoratorAsyncDefault(ASyncDecorator):
|
|
629
896
|
@overload
|
|
630
897
|
def __call__(self, func: AnyFn[Concatenate[B, P], T]) -> "ASyncBoundMethodAsyncDefault[P, T]": # type: ignore [override]
|
|
631
|
-
...
|
|
898
|
+
... # TODO write specific docs for this overload
|
|
899
|
+
|
|
632
900
|
@overload
|
|
633
901
|
def __call__(self, func: AnyBoundMethod[P, T]) -> ASyncFunctionAsyncDefault[P, T]: # type: ignore [override]
|
|
634
|
-
...
|
|
902
|
+
... # TODO write specific docs for this overload
|
|
903
|
+
|
|
635
904
|
@overload
|
|
636
905
|
def __call__(self, func: AnyFn[P, T]) -> ASyncFunctionAsyncDefault[P, T]: # type: ignore [override]
|
|
637
|
-
...
|
|
906
|
+
... # TODO write specific docs for this overload
|
|
907
|
+
|
|
638
908
|
def __call__(self, func: AnyFn[P, T]) -> ASyncFunctionAsyncDefault[P, T]:
|
|
909
|
+
# TODO write specific docs for this overload
|
|
639
910
|
return ASyncFunctionAsyncDefault(func, **self.modifiers)
|
|
640
|
-
|