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.

Files changed (73) hide show
  1. a_sync/ENVIRONMENT_VARIABLES.py +4 -3
  2. a_sync/__init__.py +30 -12
  3. a_sync/_smart.py +132 -28
  4. a_sync/_typing.py +56 -12
  5. a_sync/a_sync/__init__.py +35 -10
  6. a_sync/a_sync/_descriptor.py +74 -26
  7. a_sync/a_sync/_flags.py +14 -6
  8. a_sync/a_sync/_helpers.py +8 -7
  9. a_sync/a_sync/_kwargs.py +3 -2
  10. a_sync/a_sync/_meta.py +120 -28
  11. a_sync/a_sync/abstract.py +102 -28
  12. a_sync/a_sync/base.py +34 -16
  13. a_sync/a_sync/config.py +47 -13
  14. a_sync/a_sync/decorator.py +239 -117
  15. a_sync/a_sync/function.py +416 -146
  16. a_sync/a_sync/method.py +197 -59
  17. a_sync/a_sync/modifiers/__init__.py +47 -5
  18. a_sync/a_sync/modifiers/cache/__init__.py +46 -17
  19. a_sync/a_sync/modifiers/cache/memory.py +86 -20
  20. a_sync/a_sync/modifiers/limiter.py +52 -22
  21. a_sync/a_sync/modifiers/manager.py +98 -16
  22. a_sync/a_sync/modifiers/semaphores.py +48 -15
  23. a_sync/a_sync/property.py +383 -82
  24. a_sync/a_sync/singleton.py +1 -0
  25. a_sync/aliases.py +0 -1
  26. a_sync/asyncio/__init__.py +4 -1
  27. a_sync/asyncio/as_completed.py +177 -49
  28. a_sync/asyncio/create_task.py +31 -17
  29. a_sync/asyncio/gather.py +72 -52
  30. a_sync/asyncio/utils.py +3 -3
  31. a_sync/exceptions.py +78 -23
  32. a_sync/executor.py +118 -71
  33. a_sync/future.py +575 -158
  34. a_sync/iter.py +110 -50
  35. a_sync/primitives/__init__.py +14 -2
  36. a_sync/primitives/_debug.py +13 -13
  37. a_sync/primitives/_loggable.py +5 -4
  38. a_sync/primitives/locks/__init__.py +5 -2
  39. a_sync/primitives/locks/counter.py +38 -36
  40. a_sync/primitives/locks/event.py +21 -7
  41. a_sync/primitives/locks/prio_semaphore.py +182 -62
  42. a_sync/primitives/locks/semaphore.py +78 -77
  43. a_sync/primitives/queue.py +560 -58
  44. a_sync/sphinx/__init__.py +0 -1
  45. a_sync/sphinx/ext.py +160 -50
  46. a_sync/task.py +262 -97
  47. a_sync/utils/__init__.py +12 -6
  48. a_sync/utils/iterators.py +127 -43
  49. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/METADATA +1 -1
  50. ez_a_sync-0.22.15.dist-info/RECORD +74 -0
  51. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/WHEEL +1 -1
  52. tests/conftest.py +1 -2
  53. tests/executor.py +112 -9
  54. tests/fixtures.py +61 -32
  55. tests/test_abstract.py +7 -4
  56. tests/test_as_completed.py +54 -21
  57. tests/test_base.py +66 -17
  58. tests/test_cache.py +31 -15
  59. tests/test_decorator.py +54 -28
  60. tests/test_executor.py +8 -13
  61. tests/test_future.py +45 -8
  62. tests/test_gather.py +8 -2
  63. tests/test_helpers.py +2 -0
  64. tests/test_iter.py +55 -13
  65. tests/test_limiter.py +5 -3
  66. tests/test_meta.py +23 -9
  67. tests/test_modified.py +4 -1
  68. tests/test_semaphore.py +15 -8
  69. tests/test_singleton.py +15 -10
  70. tests/test_task.py +126 -28
  71. ez_a_sync-0.22.14.dist-info/RECORD +0 -74
  72. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/LICENSE.txt +0 -0
  73. {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
- AsyncPropertyDescriptor # type: ignore [import]
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 (ASyncBoundMethod, ASyncBoundMethodAsyncDefault,
20
- ASyncBoundMethodSyncDefault)
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
- class ModifiedMixin:
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 to handle
29
- the application of async and sync modifiers to functions.
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
- Convert a synchronous function to an asynchronous one and apply async modifiers.
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
- An asynchronous function with async modifiers applied.
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
- Apply sync modifiers to the _helpers._await function and cache it.
54
+ Applies sync modifiers to the _helpers._await function and caches it.
52
55
 
53
56
  Returns:
54
- A function that applies sync modifiers to awaitable objects.
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
- Get the default execution mode (sync, async, or None) for the function.
64
+ Gets the default execution mode (sync, async, or None) for the function.
62
65
 
63
66
  Returns:
64
- The default execution mode as determined by the modifiers.
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 # These are always valid
83
+ return # These are always valid
73
84
  if not callable(fn):
74
- raise TypeError(f'Input is not callable. Unable to decorate {fn}')
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(f"{fn} must not have any arguments with the following names: {_flags.VIABLE_FLAGS}")
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(ModifiedMixin, Generic[P, T]):
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
- Initialize an ASyncFunction instance.
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__ += f"\n\nSince `{self.__name__}` is an {self.__docstring_append__}"
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__(self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:...
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__(self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs) -> T:...
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__(self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:...
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
- Call the wrapped function either synchronously or asynchronously.
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("calling %s fn: %s with args: %s kwargs: %s", self, self.fn, args, kwargs)
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(self): # -> Union[SyncFn[[CoroFn[P, T]], MaybeAwaitable[T]], SyncFn[[SyncFn[P, T]], MaybeAwaitable[T]]]:
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(self, *iterables: AnyIterable[P.args], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> "TaskMapping[P, T]":
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
- Create a TaskMapping for the wrapped function with the given iterables.
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
- async def any(self, *iterables: AnyIterable[P.args], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> bool:
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
- Check if any result of the function applied to the iterables is truthy.
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
- A boolean indicating if any result is truthy.
270
+ True if any result is truthy, otherwise False.
210
271
  """
211
- return await self.map(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).any(pop=True, sync=False)
212
-
213
- async def all(self, *iterables: AnyIterable[P.args], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> bool:
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
- Check if all results of the function applied to the iterables are truthy.
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
- A boolean indicating if all results are truthy.
296
+ True if all results are truthy, otherwise False.
225
297
  """
226
- return await self.map(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).all(pop=True, sync=False)
227
-
228
- async def min(self, *iterables: AnyIterable[P.args], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> T:
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
- Find the minimum result of the function applied to the iterables.
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(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).min(pop=True, sync=False)
242
-
243
- async def max(self, *iterables: AnyIterable[P.args], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> T:
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
- Find the maximum result of the function applied to the iterables.
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(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).max(pop=True, sync=False)
257
-
258
- async def sum(self, *iterables: AnyIterable[P.args], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> T:
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
- Calculate the sum of the results of the function applied to the iterables.
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(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).sum(pop=True, sync=False)
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
- def map(self, *iterables: AnyIterable[Any], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> "TaskMapping[P, T]":
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
- Create a TaskMapping for the wrapped function with the given iterables.
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
- async def any(self, *iterables: AnyIterable[Any], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> bool:
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
- Check if any result of the function applied to the iterables is truthy.
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
- A boolean indicating if any result is truthy.
431
+ True if any result is truthy, otherwise False.
301
432
  """
302
- return await self.map(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).any(pop=True, sync=False)
303
-
304
- async def all(self, *iterables: AnyIterable[Any], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> bool:
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
- Check if all results of the function applied to the iterables are truthy.
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
- A boolean indicating if all results are truthy.
457
+ True if all results are truthy, otherwise False.
316
458
  """
317
- return await self.map(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).all(pop=True, sync=False)
318
-
319
- async def min(self, *iterables: AnyIterable[Any], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> T:
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
- Find the minimum result of the function applied to the iterables.
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(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).min(pop=True, sync=False)
333
-
334
- async def max(self, *iterables: AnyIterable[Any], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> T:
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
- Find the maximum result of the function applied to the iterables.
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(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).max(pop=True, sync=False)
348
-
349
- async def sum(self, *iterables: AnyIterable[Any], concurrency: Optional[int] = None, task_name: str = "", **function_kwargs: P.kwargs) -> T:
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
- Calculate the sum of the results of the function applied to the iterables.
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(*iterables, concurrency=concurrency, task_name=task_name, **function_kwargs).sum(pop=True, sync=False)
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
- Determine the default execution mode (sync or async) for the function.
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 the default is async.
553
+ True if the default is sync, False if async.
374
554
  """
375
- return True if self.default == 'sync' else False if self.default == 'async' else not self._async_def
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
- Check if the wrapped function is an asynchronous function.
564
+ Checks if the wrapped function is an asynchronous function.
381
565
 
382
566
  Returns:
383
- True if the wrapped function is an asynchronous function, False otherwise.
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
- Determine whether to run the function synchronously or asynchronously.
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 be run synchronously, False otherwise.
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
- Convert the wrapped function to an asynchronous function and apply both sync and async modifiers.
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
- An asynchronous function with both sync and async modifiers applied.
600
+ The asynchronous version of the wrapped function.
414
601
  """
415
602
  if self._async_def:
416
- raise TypeError(f"Can only be applied to sync functions, not {self.__wrapped__}")
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
- Apply modifiers to the wrapped function.
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 wrapped function with modifiers applied.
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): # -> SyncFn[[CoroFn[P, T]], MaybeAwaitable[T]]:
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 final wrapped function.
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(kwargs) # Must take place before coro is created, we're popping a kwarg.
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): # -> SyncFn[[SyncFn[P, T]], MaybeAwaitable[T]]:
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 final wrapped function.
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
- class ASyncDecorator(ModifiedMixin):
670
+
671
+
672
+ class ASyncDecorator(_ModifiedMixin):
476
673
  def __init__(self, **modifiers: Unpack[ModifierKwargs]) -> None:
477
- assert 'default' in modifiers, modifiers
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
- if self.modifiers.default not in ['sync', 'async', None]:
483
- raise ValueError(f"'default' must be either 'sync', 'async', or None. You passed {self.modifiers.default}.")
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__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T:...
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__(self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:...
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__(self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs) -> T:...
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__(self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:...
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__(self, *args: P.args, **kwargs: P.kwargs) -> T:...
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
- """Call the wrapped function, defaulting to synchronous execution.
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__(self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:...
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__(self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs) -> T:...
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__(self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:...
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
- """Call the wrapped function, defaulting to asynchronous execution.
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
-