ez-a-sync 0.32.29__cp310-cp310-win_amd64.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 (177) hide show
  1. a_sync/ENVIRONMENT_VARIABLES.py +42 -0
  2. a_sync/__init__.pxd +2 -0
  3. a_sync/__init__.py +145 -0
  4. a_sync/_smart.c +22803 -0
  5. a_sync/_smart.cp310-win_amd64.pyd +0 -0
  6. a_sync/_smart.pxd +2 -0
  7. a_sync/_smart.pyi +202 -0
  8. a_sync/_smart.pyx +674 -0
  9. a_sync/_typing.py +258 -0
  10. a_sync/a_sync/__init__.py +60 -0
  11. a_sync/a_sync/_descriptor.c +20528 -0
  12. a_sync/a_sync/_descriptor.cp310-win_amd64.pyd +0 -0
  13. a_sync/a_sync/_descriptor.pyi +33 -0
  14. a_sync/a_sync/_descriptor.pyx +422 -0
  15. a_sync/a_sync/_flags.c +6074 -0
  16. a_sync/a_sync/_flags.cp310-win_amd64.pyd +0 -0
  17. a_sync/a_sync/_flags.pxd +3 -0
  18. a_sync/a_sync/_flags.pyx +92 -0
  19. a_sync/a_sync/_helpers.c +14521 -0
  20. a_sync/a_sync/_helpers.cp310-win_amd64.pyd +0 -0
  21. a_sync/a_sync/_helpers.pxd +3 -0
  22. a_sync/a_sync/_helpers.pyi +10 -0
  23. a_sync/a_sync/_helpers.pyx +167 -0
  24. a_sync/a_sync/_kwargs.c +12194 -0
  25. a_sync/a_sync/_kwargs.cp310-win_amd64.pyd +0 -0
  26. a_sync/a_sync/_kwargs.pxd +2 -0
  27. a_sync/a_sync/_kwargs.pyx +64 -0
  28. a_sync/a_sync/_meta.py +210 -0
  29. a_sync/a_sync/abstract.c +12411 -0
  30. a_sync/a_sync/abstract.cp310-win_amd64.pyd +0 -0
  31. a_sync/a_sync/abstract.pyi +141 -0
  32. a_sync/a_sync/abstract.pyx +221 -0
  33. a_sync/a_sync/base.c +14932 -0
  34. a_sync/a_sync/base.cp310-win_amd64.pyd +0 -0
  35. a_sync/a_sync/base.pyi +60 -0
  36. a_sync/a_sync/base.pyx +271 -0
  37. a_sync/a_sync/config.py +168 -0
  38. a_sync/a_sync/decorator.py +651 -0
  39. a_sync/a_sync/flags.c +5272 -0
  40. a_sync/a_sync/flags.cp310-win_amd64.pyd +0 -0
  41. a_sync/a_sync/flags.pxd +72 -0
  42. a_sync/a_sync/flags.pyi +74 -0
  43. a_sync/a_sync/flags.pyx +72 -0
  44. a_sync/a_sync/function.c +37846 -0
  45. a_sync/a_sync/function.cp310-win_amd64.pyd +0 -0
  46. a_sync/a_sync/function.pxd +28 -0
  47. a_sync/a_sync/function.pyi +571 -0
  48. a_sync/a_sync/function.pyx +1381 -0
  49. a_sync/a_sync/method.c +29774 -0
  50. a_sync/a_sync/method.cp310-win_amd64.pyd +0 -0
  51. a_sync/a_sync/method.pxd +9 -0
  52. a_sync/a_sync/method.pyi +525 -0
  53. a_sync/a_sync/method.pyx +1023 -0
  54. a_sync/a_sync/modifiers/__init__.pxd +1 -0
  55. a_sync/a_sync/modifiers/__init__.py +101 -0
  56. a_sync/a_sync/modifiers/cache/__init__.py +160 -0
  57. a_sync/a_sync/modifiers/cache/memory.py +165 -0
  58. a_sync/a_sync/modifiers/limiter.py +132 -0
  59. a_sync/a_sync/modifiers/manager.c +16149 -0
  60. a_sync/a_sync/modifiers/manager.cp310-win_amd64.pyd +0 -0
  61. a_sync/a_sync/modifiers/manager.pxd +5 -0
  62. a_sync/a_sync/modifiers/manager.pyi +219 -0
  63. a_sync/a_sync/modifiers/manager.pyx +299 -0
  64. a_sync/a_sync/modifiers/semaphores.py +173 -0
  65. a_sync/a_sync/property.c +27260 -0
  66. a_sync/a_sync/property.cp310-win_amd64.pyd +0 -0
  67. a_sync/a_sync/property.pyi +376 -0
  68. a_sync/a_sync/property.pyx +819 -0
  69. a_sync/a_sync/singleton.py +63 -0
  70. a_sync/aliases.py +3 -0
  71. a_sync/async_property/__init__.pxd +1 -0
  72. a_sync/async_property/__init__.py +1 -0
  73. a_sync/async_property/cached.c +20386 -0
  74. a_sync/async_property/cached.cp310-win_amd64.pyd +0 -0
  75. a_sync/async_property/cached.pxd +10 -0
  76. a_sync/async_property/cached.pyi +45 -0
  77. a_sync/async_property/cached.pyx +178 -0
  78. a_sync/async_property/proxy.c +34654 -0
  79. a_sync/async_property/proxy.cp310-win_amd64.pyd +0 -0
  80. a_sync/async_property/proxy.pxd +2 -0
  81. a_sync/async_property/proxy.pyi +124 -0
  82. a_sync/async_property/proxy.pyx +474 -0
  83. a_sync/asyncio/__init__.pxd +6 -0
  84. a_sync/asyncio/__init__.py +164 -0
  85. a_sync/asyncio/as_completed.c +18841 -0
  86. a_sync/asyncio/as_completed.cp310-win_amd64.pyd +0 -0
  87. a_sync/asyncio/as_completed.pxd +8 -0
  88. a_sync/asyncio/as_completed.pyi +109 -0
  89. a_sync/asyncio/as_completed.pyx +269 -0
  90. a_sync/asyncio/create_task.c +15902 -0
  91. a_sync/asyncio/create_task.cp310-win_amd64.pyd +0 -0
  92. a_sync/asyncio/create_task.pxd +2 -0
  93. a_sync/asyncio/create_task.pyi +51 -0
  94. a_sync/asyncio/create_task.pyx +271 -0
  95. a_sync/asyncio/gather.c +16679 -0
  96. a_sync/asyncio/gather.cp310-win_amd64.pyd +0 -0
  97. a_sync/asyncio/gather.pyi +107 -0
  98. a_sync/asyncio/gather.pyx +218 -0
  99. a_sync/asyncio/igather.c +12676 -0
  100. a_sync/asyncio/igather.cp310-win_amd64.pyd +0 -0
  101. a_sync/asyncio/igather.pxd +1 -0
  102. a_sync/asyncio/igather.pyi +7 -0
  103. a_sync/asyncio/igather.pyx +182 -0
  104. a_sync/asyncio/sleep.c +9593 -0
  105. a_sync/asyncio/sleep.cp310-win_amd64.pyd +0 -0
  106. a_sync/asyncio/sleep.pyi +14 -0
  107. a_sync/asyncio/sleep.pyx +49 -0
  108. a_sync/debugging.c +15362 -0
  109. a_sync/debugging.cp310-win_amd64.pyd +0 -0
  110. a_sync/debugging.pyi +76 -0
  111. a_sync/debugging.pyx +107 -0
  112. a_sync/exceptions.c +13312 -0
  113. a_sync/exceptions.cp310-win_amd64.pyd +0 -0
  114. a_sync/exceptions.pyi +376 -0
  115. a_sync/exceptions.pyx +446 -0
  116. a_sync/executor.py +619 -0
  117. a_sync/functools.c +12738 -0
  118. a_sync/functools.cp310-win_amd64.pyd +0 -0
  119. a_sync/functools.pxd +7 -0
  120. a_sync/functools.pyi +33 -0
  121. a_sync/functools.pyx +139 -0
  122. a_sync/future.py +1497 -0
  123. a_sync/iter.c +37271 -0
  124. a_sync/iter.cp310-win_amd64.pyd +0 -0
  125. a_sync/iter.pxd +11 -0
  126. a_sync/iter.pyi +370 -0
  127. a_sync/iter.pyx +981 -0
  128. a_sync/primitives/__init__.pxd +1 -0
  129. a_sync/primitives/__init__.py +53 -0
  130. a_sync/primitives/_debug.c +15757 -0
  131. a_sync/primitives/_debug.cp310-win_amd64.pyd +0 -0
  132. a_sync/primitives/_debug.pxd +12 -0
  133. a_sync/primitives/_debug.pyi +52 -0
  134. a_sync/primitives/_debug.pyx +223 -0
  135. a_sync/primitives/_loggable.c +11529 -0
  136. a_sync/primitives/_loggable.cp310-win_amd64.pyd +0 -0
  137. a_sync/primitives/_loggable.pxd +4 -0
  138. a_sync/primitives/_loggable.pyi +66 -0
  139. a_sync/primitives/_loggable.pyx +102 -0
  140. a_sync/primitives/locks/__init__.pxd +8 -0
  141. a_sync/primitives/locks/__init__.py +17 -0
  142. a_sync/primitives/locks/counter.c +17679 -0
  143. a_sync/primitives/locks/counter.cp310-win_amd64.pyd +0 -0
  144. a_sync/primitives/locks/counter.pxd +12 -0
  145. a_sync/primitives/locks/counter.pyi +151 -0
  146. a_sync/primitives/locks/counter.pyx +260 -0
  147. a_sync/primitives/locks/event.c +17063 -0
  148. a_sync/primitives/locks/event.cp310-win_amd64.pyd +0 -0
  149. a_sync/primitives/locks/event.pxd +22 -0
  150. a_sync/primitives/locks/event.pyi +43 -0
  151. a_sync/primitives/locks/event.pyx +185 -0
  152. a_sync/primitives/locks/prio_semaphore.c +25590 -0
  153. a_sync/primitives/locks/prio_semaphore.cp310-win_amd64.pyd +0 -0
  154. a_sync/primitives/locks/prio_semaphore.pxd +25 -0
  155. a_sync/primitives/locks/prio_semaphore.pyi +217 -0
  156. a_sync/primitives/locks/prio_semaphore.pyx +597 -0
  157. a_sync/primitives/locks/semaphore.c +26509 -0
  158. a_sync/primitives/locks/semaphore.cp310-win_amd64.pyd +0 -0
  159. a_sync/primitives/locks/semaphore.pxd +21 -0
  160. a_sync/primitives/locks/semaphore.pyi +197 -0
  161. a_sync/primitives/locks/semaphore.pyx +454 -0
  162. a_sync/primitives/queue.py +1022 -0
  163. a_sync/py.typed +0 -0
  164. a_sync/sphinx/__init__.py +3 -0
  165. a_sync/sphinx/ext.py +289 -0
  166. a_sync/task.py +932 -0
  167. a_sync/utils/__init__.py +105 -0
  168. a_sync/utils/iterators.py +297 -0
  169. a_sync/utils/repr.c +15799 -0
  170. a_sync/utils/repr.cp310-win_amd64.pyd +0 -0
  171. a_sync/utils/repr.pyi +2 -0
  172. a_sync/utils/repr.pyx +73 -0
  173. ez_a_sync-0.32.29.dist-info/METADATA +367 -0
  174. ez_a_sync-0.32.29.dist-info/RECORD +177 -0
  175. ez_a_sync-0.32.29.dist-info/WHEEL +5 -0
  176. ez_a_sync-0.32.29.dist-info/licenses/LICENSE.txt +17 -0
  177. ez_a_sync-0.32.29.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1023 @@
1
+ """
2
+ This module provides classes for implementing dual-functional sync/async methods in Python.
3
+
4
+ It includes descriptors and bound methods that can be used to create flexible
5
+ asynchronous interfaces, allowing methods to be called both synchronously and
6
+ asynchronously based on various conditions and configurations.
7
+ """
8
+
9
+ # mypy: disable-error-code=valid-type
10
+ # mypy: disable-error-code=misc
11
+ import asyncio
12
+ import inspect
13
+ import typing
14
+ from cpython.object cimport PyObject
15
+ from cpython.ref cimport Py_DECREF, Py_INCREF
16
+ from libc.stdint cimport uintptr_t
17
+ from logging import getLogger
18
+
19
+ import typing_extensions
20
+
21
+ from a_sync._typing import AnyFn, AnyIterable, I, MaybeCoro, ModifierKwargs, P, T
22
+ from a_sync.a_sync import _descriptor, function
23
+ from a_sync.a_sync._kwargs cimport get_flag_name, is_sync
24
+ from a_sync.a_sync._helpers cimport _await
25
+ from a_sync.a_sync.function cimport _ASyncFunction, _ModifiedMixin
26
+ from a_sync.functools cimport update_wrapper
27
+
28
+ cdef extern from "weakrefobject.h":
29
+ PyObject* PyWeakref_NewRef(PyObject*, PyObject*)
30
+
31
+ cdef extern from "pythoncapi_compat.h":
32
+ int PyWeakref_GetRef(PyObject*, PyObject**)
33
+
34
+ if typing.TYPE_CHECKING:
35
+ from a_sync import TaskMapping
36
+ from a_sync.a_sync.abstract import ASyncABC
37
+
38
+ else:
39
+ # Due to circ import issues we will populate these later
40
+ ASyncABC, TaskMapping = None, None
41
+
42
+
43
+ # cdef asyncio
44
+ cdef object get_event_loop = asyncio.get_event_loop
45
+ cdef object iscoroutinefunction = asyncio.iscoroutinefunction
46
+ cdef object cancel_handle = asyncio.TimerHandle.cancel
47
+
48
+ # cdef inspect
49
+ cdef object isawaitable = inspect.isawaitable
50
+
51
+ # cdef typing
52
+ cdef object Any = typing.Any
53
+ cdef object Coroutine = typing.Coroutine
54
+ cdef object Generic = typing.Generic
55
+ cdef object Literal = typing.Literal
56
+ cdef object Optional = typing.Optional
57
+ cdef object Type = typing.Type
58
+ cdef object Union = typing.Union
59
+ cdef object overload = typing.overload
60
+
61
+ # cdef typing_extensions
62
+ cdef object Concatenate = typing_extensions.Concatenate
63
+ cdef object Self = typing_extensions.Self
64
+ cdef object Unpack = typing_extensions.Unpack
65
+
66
+
67
+ # cdef a_sync
68
+ cdef object ASyncDescriptor = _descriptor.ASyncDescriptor
69
+ cdef object ASyncFunctionAsyncDefault = function.ASyncFunctionAsyncDefault
70
+ cdef object ASyncFunctionSyncDefault = function.ASyncFunctionSyncDefault
71
+
72
+
73
+ cdef public double METHOD_CACHE_TTL = 3600
74
+
75
+
76
+ logger = getLogger(__name__)
77
+
78
+ cdef object _logger_is_enabled = logger.isEnabledFor
79
+ cdef object _logger_log = logger._log
80
+ cdef object DEBUG = 10
81
+
82
+ cdef inline void _logger_debug(str msg, tuple args):
83
+ if _logger_is_enabled(DEBUG):
84
+ _logger_log(DEBUG, msg, args)
85
+
86
+
87
+ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
88
+ """
89
+ A descriptor for managing methods that can be called both synchronously and asynchronously.
90
+
91
+ This class provides the core functionality for binding methods to instances and determining
92
+ the execution mode ("sync" or "async") based on various conditions, such as the instance type,
93
+ the method's default setting, or specific flags passed during the method call.
94
+
95
+ The descriptor is responsible for creating an appropriate bound method when accessed,
96
+ which is the actual object that can be called in both synchronous and asynchronous contexts.
97
+ It can create different types of bound methods (`ASyncBoundMethodSyncDefault`,
98
+ `ASyncBoundMethodAsyncDefault`, or `ASyncBoundMethod`) based on the default mode or instance type.
99
+
100
+ If the default mode is explicitly set to "sync" or "async", it creates `ASyncBoundMethodSyncDefault`
101
+ or `ASyncBoundMethodAsyncDefault` respectively. If neither is set, it defaults to creating an
102
+ `ASyncBoundMethod`. For instances of :class:`ASyncABC`, it checks the `__a_sync_instance_should_await__`
103
+ attribute to decide the type of bound method to create.
104
+
105
+ It also manages cache handles for bound methods and prevents setting or deleting the descriptor.
106
+
107
+ Examples:
108
+ >>> class MyClass:
109
+ ... @ASyncMethodDescriptor
110
+ ... async def my_method(self):
111
+ ... return "Hello, World!"
112
+ ...
113
+ >>> obj = MyClass()
114
+ >>> await obj.my_method()
115
+ 'Hello, World!'
116
+ >>> obj.my_method(sync=True)
117
+ 'Hello, World!'
118
+
119
+ See Also:
120
+ - :class:`ASyncBoundMethod`
121
+ - :class:`ASyncFunction`
122
+ """
123
+
124
+ __wrapped__: AnyFn[P, T]
125
+ """The unbound function which will be bound to an instance when :meth:`__get__` is called."""
126
+
127
+ _initialized = False
128
+
129
+ async def __call__(self, instance: I, *args: P.args, **kwargs: P.kwargs) -> T:
130
+ """
131
+ Asynchronously call the method.
132
+
133
+ Args:
134
+ instance: The instance the method is bound to.
135
+ *args: Positional arguments.
136
+ **kwargs: Keyword arguments.
137
+
138
+ Examples:
139
+ >>> descriptor = ASyncMethodDescriptor(my_async_function)
140
+ >>> await descriptor(instance, arg1, arg2, kwarg1=value1)
141
+ """
142
+ # NOTE: This is only used by TaskMapping atm # TODO: use it elsewhere
143
+ _logger_debug(
144
+ "awaiting %s for instance: %s args: %s kwargs: %s",
145
+ (self, instance, args, kwargs),
146
+ )
147
+ return await self.__get__(instance, None)(*args, **kwargs)
148
+
149
+ @overload
150
+ def __get__(self, instance: None, owner: Type[I]) -> Self: ...
151
+ @overload
152
+ def __get__(self, instance: I, owner: Type[I]) -> "ASyncBoundMethod[I, P, T]": ...
153
+ def __get__(
154
+ _ModifiedMixin self, instance: Optional[I], owner: Type[I]
155
+ ) -> Union[Self, "ASyncBoundMethod[I, P, T]"]:
156
+ """
157
+ Get the bound method or the descriptor itself.
158
+
159
+ Args:
160
+ instance: The instance to bind the method to, or None.
161
+ owner: The owner class.
162
+
163
+ Examples:
164
+ >>> descriptor = ASyncMethodDescriptor(my_function)
165
+ >>> bound_method = descriptor.__get__(instance, MyClass)
166
+ """
167
+ if instance is None:
168
+ return self
169
+
170
+ cdef str field_name = self.field_name
171
+ cdef dict instance_dict = instance.__dict__
172
+
173
+ try:
174
+ bound = instance_dict[field_name]
175
+ except KeyError:
176
+ if ASyncABC is None:
177
+ _import_ASyncABC()
178
+
179
+ default = _ModifiedMixin.get_default(self)
180
+ if default == "sync":
181
+ bound = ASyncBoundMethodSyncDefault(
182
+ instance, self.__wrapped__, self.__is_async_def__, **self.modifiers._modifiers
183
+ )
184
+ elif default == "async":
185
+ bound = ASyncBoundMethodAsyncDefault(
186
+ instance, self.__wrapped__, self.__is_async_def__, **self.modifiers._modifiers
187
+ )
188
+ elif isinstance(instance, ASyncABC):
189
+ try:
190
+ if instance.__a_sync_instance_should_await__:
191
+ bound = ASyncBoundMethodSyncDefault(
192
+ instance,
193
+ self.__wrapped__,
194
+ self.__is_async_def__,
195
+ **self.modifiers._modifiers,
196
+ )
197
+ else:
198
+ bound = ASyncBoundMethodAsyncDefault(
199
+ instance,
200
+ self.__wrapped__,
201
+ self.__is_async_def__,
202
+ **self.modifiers._modifiers,
203
+ )
204
+ except AttributeError:
205
+ bound = ASyncBoundMethod(
206
+ instance,
207
+ self.__wrapped__,
208
+ self.__is_async_def__,
209
+ **self.modifiers._modifiers,
210
+ )
211
+ else:
212
+ bound = ASyncBoundMethod(
213
+ instance, self.__wrapped__, self.__is_async_def__, **self.modifiers._modifiers
214
+ )
215
+ instance_dict[field_name] = bound
216
+ _logger_debug("new bound method: %s", (bound,))
217
+ _update_cache_timer(field_name, instance, bound)
218
+ return bound
219
+
220
+ def __set__(self, instance, value):
221
+ """
222
+ Prevent setting the descriptor.
223
+
224
+ Args:
225
+ instance: The instance.
226
+ value: The value to set.
227
+
228
+ Raises:
229
+ RuntimeError: Always raised to prevent setting.
230
+
231
+ Examples:
232
+ >>> descriptor = ASyncMethodDescriptor(my_function)
233
+ >>> descriptor.__set__(instance, value)
234
+ RuntimeError: cannot set field_name, descriptor is what you get. sorry.
235
+ """
236
+ raise RuntimeError(
237
+ f"cannot set {self.field_name}, {self} is what you get. sorry."
238
+ )
239
+
240
+ def __delete__(self, instance):
241
+ """
242
+ Prevent deleting the descriptor.
243
+
244
+ Args:
245
+ instance: The instance.
246
+
247
+ Raises:
248
+ RuntimeError: Always raised to prevent deletion.
249
+
250
+ Examples:
251
+ >>> descriptor = ASyncMethodDescriptor(my_function)
252
+ >>> descriptor.__delete__(instance)
253
+ RuntimeError: cannot delete field_name, you're stuck with descriptor forever. sorry.
254
+ """
255
+ raise RuntimeError(
256
+ f"cannot delete {self.field_name}, you're stuck with {self} forever. sorry."
257
+ )
258
+
259
+ @property
260
+ def __is_async_def__(self) -> bint:
261
+ """
262
+ Check if the wrapped function is a coroutine function.
263
+
264
+ Examples:
265
+ >>> descriptor = ASyncMethodDescriptor(my_function)
266
+ >>> descriptor.__is_async_def__
267
+ True
268
+ """
269
+ if not self._initialized:
270
+ self._is_async_def = iscoroutinefunction(self.__wrapped__)
271
+ self._initialized = True
272
+ return self._is_async_def
273
+
274
+
275
+ cdef void _update_cache_timer(str field_name, object instance, _ASyncBoundMethod bound):
276
+ """
277
+ Update the TTL for the cache handle for the instance.
278
+
279
+ Args:
280
+ instance: The instance to create a cache handle for.
281
+ bound: The bound method we are caching.
282
+ """
283
+ # Handler for popping unused bound methods from bound method cache
284
+ cdef object handle, loop
285
+ if handle := bound._cache_handle:
286
+ # update the timer handle
287
+ handle._when = <double>handle._loop.time() + METHOD_CACHE_TTL
288
+ else:
289
+ # create and assign the timer handle
290
+ loop = get_event_loop()
291
+ # NOTE: use `instance.__dict__.pop` instead of `delattr` so we don't create a strong ref to `instance`
292
+ bound._cache_handle = loop.call_at(<double>loop.time() + METHOD_CACHE_TTL, instance.__dict__.pop, field_name)
293
+
294
+
295
+ class ASyncMethodDescriptorSyncDefault(ASyncMethodDescriptor[I, P, T]):
296
+ """
297
+ A descriptor for :class:`ASyncBoundMethodSyncDefault` objects.
298
+
299
+ This class extends :class:`ASyncMethodDescriptor` to provide a synchronous
300
+ default behavior for method calls. It specifically creates `ASyncBoundMethodSyncDefault`
301
+ instances, which are specialized versions of `ASyncBoundMethod` with synchronous default behavior.
302
+
303
+ Examples:
304
+ >>> class MyClass:
305
+ ... @ASyncMethodDescriptorSyncDefault
306
+ ... def my_method(self):
307
+ ... return "Hello, World!"
308
+ ...
309
+ >>> obj = MyClass()
310
+ >>> obj.my_method()
311
+ 'Hello, World!'
312
+ >>> coro = obj.my_method(sync=False)
313
+ >>> coro
314
+ <coroutine object MyClass.my_method at 0x7fb4f5fb49c0>
315
+ >>> await coro
316
+ 'Hello, World!'
317
+
318
+ See Also:
319
+ - :class:`ASyncBoundMethodSyncDefault`
320
+ - :class:`ASyncFunctionSyncDefault`
321
+ """
322
+
323
+ default = "sync"
324
+ """The default mode for this bound method. Always set to "sync"."""
325
+
326
+ any: ASyncFunctionSyncDefault[Concatenate[AnyIterable[I], P], bool]
327
+ """Synchronous default version of the :meth:`~ASyncMethodDescriptor.any` method."""
328
+
329
+ all: ASyncFunctionSyncDefault[Concatenate[AnyIterable[I], P], bool]
330
+ """Synchronous default version of the :meth:`~ASyncMethodDescriptor.all` method."""
331
+
332
+ min: ASyncFunctionSyncDefault[Concatenate[AnyIterable[I], P], T]
333
+ """Synchronous default version of the :meth:`~ASyncMethodDescriptor.min` method."""
334
+
335
+ max: ASyncFunctionSyncDefault[Concatenate[AnyIterable[I], P], T]
336
+ """Synchronous default version of the :meth:`~ASyncMethodDescriptor.max` method."""
337
+
338
+ sum: ASyncFunctionSyncDefault[Concatenate[AnyIterable[I], P], T]
339
+ """Synchronous default version of the :meth:`~ASyncMethodDescriptor.sum` method."""
340
+
341
+ @overload
342
+ def __get__(
343
+ self, instance: None, owner: Type[I] = None
344
+ ) -> "ASyncMethodDescriptorSyncDefault[I, P, T]": ...
345
+ @overload
346
+ def __get__(
347
+ self, instance: I, owner: Type[I] = None
348
+ ) -> "ASyncBoundMethodSyncDefault[I, P, T]": ...
349
+ def __get__(
350
+ _ModifiedMixin self, instance: Optional[I], owner: Type[I] = None
351
+ ) -> (
352
+ "Union[ASyncMethodDescriptorSyncDefault, ASyncBoundMethodSyncDefault[I, P, T]]"
353
+ ):
354
+ """
355
+ Get the bound method or the descriptor itself.
356
+
357
+ Args:
358
+ instance: The instance to bind the method to, or None.
359
+ owner: The owner class.
360
+
361
+ Examples:
362
+ >>> descriptor = ASyncMethodDescriptorSyncDefault(my_function)
363
+ >>> bound_method = descriptor.__get__(instance, MyClass)
364
+ """
365
+ if instance is None:
366
+ return self
367
+
368
+ cdef str field_name = self.field_name
369
+ cdef dict instance_dict = instance.__dict__
370
+
371
+ try:
372
+ bound = instance_dict[field_name]
373
+ except KeyError:
374
+ bound = ASyncBoundMethodSyncDefault(
375
+ instance, self.__wrapped__, self.__is_async_def__, **self.modifiers._modifiers
376
+ )
377
+ instance_dict[field_name] = bound
378
+ _logger_debug("new bound method: %s", (bound,))
379
+ _update_cache_timer(field_name, instance, bound)
380
+ return bound
381
+
382
+
383
+ class ASyncMethodDescriptorAsyncDefault(ASyncMethodDescriptor[I, P, T]):
384
+ """
385
+ A descriptor for asynchronous methods with an asynchronous default.
386
+
387
+ This class extends :class:`ASyncMethodDescriptor` to provide an asynchronous default
388
+ behavior for method calls. It specifically creates `ASyncBoundMethodAsyncDefault`
389
+ instances, which are specialized versions of `ASyncBoundMethod` with asynchronous default behavior.
390
+
391
+ Examples:
392
+ >>> class MyClass:
393
+ ... @ASyncMethodDescriptorAsyncDefault
394
+ ... async def my_method(self):
395
+ ... return "Hello, World!"
396
+ ...
397
+ >>> obj = MyClass()
398
+ >>> coro = obj.my_method()
399
+ >>> coro
400
+ <coroutine object MyClass.my_method at 0x7fb4f5fb49c0>
401
+ >>> await coro
402
+ >>> obj.my_method(sync=True)
403
+ 'Hello, World!'
404
+
405
+ See Also:
406
+ - :class:`ASyncBoundMethodAsyncDefault`
407
+ - :class:`ASyncFunctionAsyncDefault`
408
+ """
409
+
410
+ default = "async"
411
+ """The default mode for this bound method. Always set to "async"."""
412
+
413
+ any: ASyncFunctionAsyncDefault[Concatenate[AnyIterable[I], P], bool]
414
+ """Asynchronous default version of the :meth:`~ASyncMethodDescriptor.any` method."""
415
+
416
+ all: ASyncFunctionAsyncDefault[Concatenate[AnyIterable[I], P], bool]
417
+ """Asynchronous default version of the :meth:`~ASyncMethodDescriptor.all` method."""
418
+
419
+ min: ASyncFunctionAsyncDefault[Concatenate[AnyIterable[I], P], T]
420
+ """Asynchronous default version of the :meth:`~ASyncMethodDescriptor.min` method."""
421
+
422
+ max: ASyncFunctionAsyncDefault[Concatenate[AnyIterable[I], P], T]
423
+ """Asynchronous default version of the :meth:`~ASyncMethodDescriptor.max` method."""
424
+
425
+ sum: ASyncFunctionAsyncDefault[Concatenate[AnyIterable[I], P], T]
426
+ """Asynchronous default version of the :meth:`~ASyncMethodDescriptor.sum` method."""
427
+
428
+ @overload
429
+ def __get__(
430
+ self, instance: None, owner: Type[I]
431
+ ) -> "ASyncMethodDescriptorAsyncDefault[I, P, T]": ...
432
+ @overload
433
+ def __get__(
434
+ self, instance: I, owner: Type[I]
435
+ ) -> "ASyncBoundMethodAsyncDefault[I, P, T]": ...
436
+ def __get__(
437
+ _ModifiedMixin self, instance: Optional[I], owner: Type[I]
438
+ ) -> "Union[ASyncMethodDescriptorAsyncDefault, ASyncBoundMethodAsyncDefault[I, P, T]]":
439
+ """
440
+ Get the bound method or the descriptor itself.
441
+
442
+ Args:
443
+ instance: The instance to bind the method to, or None.
444
+ owner: The owner class.
445
+
446
+ Examples:
447
+ >>> descriptor = ASyncMethodDescriptorAsyncDefault(my_function)
448
+ >>> bound_method = descriptor.__get__(instance, MyClass)
449
+ """
450
+ if instance is None:
451
+ return self
452
+
453
+ cdef object bound
454
+ cdef str field_name = self.field_name
455
+ cdef dict instance_dict = instance.__dict__
456
+
457
+ try:
458
+ bound = instance_dict[field_name]
459
+ except KeyError:
460
+ bound = ASyncBoundMethodAsyncDefault(
461
+ instance, self.__wrapped__, self.__is_async_def__, **self.modifiers._modifiers
462
+ )
463
+ instance_dict[field_name] = bound
464
+ _logger_debug("new bound method: %s", (bound,))
465
+ _update_cache_timer(field_name, instance, bound)
466
+ return bound
467
+
468
+
469
+ cdef dict[object, bint] _is_a_sync_instance_cache = {}
470
+
471
+
472
+ cdef bint _is_a_sync_instance(object instance):
473
+ """Checks if an instance is an ASync instance.
474
+
475
+ Args:
476
+ instance: The instance to check.
477
+
478
+ Returns:
479
+ A boolean indicating if the instance is an ASync instance.
480
+ """
481
+ cdef object instance_type = type(instance)
482
+ cdef object instance_type_uid = id(instance_type)
483
+ if instance_type_uid in _is_a_sync_instance_cache:
484
+ return _is_a_sync_instance_cache[instance_type_uid]
485
+
486
+ if ASyncABC is None:
487
+ _import_ASyncABC()
488
+
489
+ cdef bint is_a_sync = issubclass(instance_type, ASyncABC)
490
+ _is_a_sync_instance_cache[instance_type_uid] = is_a_sync
491
+ return is_a_sync
492
+
493
+
494
+ cdef bint _should_await(_ASyncBoundMethod self, dict kwargs):
495
+ """
496
+ Determine if the method should be awaited.
497
+
498
+ Args:
499
+ kwargs: Keyword arguments passed to the method.
500
+
501
+ Examples:
502
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
503
+ >>> should_await = _should_await(bound_method, kwargs)
504
+ """
505
+ cdef str flag = get_flag_name(kwargs)
506
+ if flag:
507
+ return is_sync(flag, kwargs, pop_flag=True) # type: ignore [arg-type]
508
+ elif default := self.get_default():
509
+ return default == "sync"
510
+ elif _is_a_sync_instance(instance := self.__c_self__()):
511
+ instance: "ASyncABC"
512
+ return instance.__a_sync_should_await__(kwargs)
513
+ return self._is_async_def
514
+
515
+
516
+ cdef class _ASyncBoundMethod(_ASyncFunction):
517
+ """
518
+ A bound method that can be called both synchronously and asynchronously.
519
+
520
+ This class represents a method bound to an instance, which can be called
521
+ either synchronously or asynchronously based on various conditions. It handles
522
+ caching of bound methods and includes logic for determining whether to await
523
+ the method call based on flags or default settings.
524
+
525
+ Examples:
526
+ >>> class MyClass:
527
+ ... def __init__(self, value):
528
+ ... self.value = value
529
+ ...
530
+ ... @ASyncMethodDescriptor
531
+ ... async def my_method(self):
532
+ ... return self.value
533
+ ...
534
+ >>> obj = MyClass(42)
535
+ >>> await obj.my_method()
536
+ 42
537
+ >>> obj.my_method(sync=True)
538
+ 42
539
+
540
+ See Also:
541
+ - :class:`ASyncMethodDescriptor`
542
+ - :class:`ASyncFunction`
543
+ """
544
+
545
+ def __init__(
546
+ self,
547
+ instance: I,
548
+ unbound: AnyFn[Concatenate[I, P], T],
549
+ bint async_def,
550
+ dict modifiers,
551
+ ) -> None:
552
+ """
553
+ Initialize the bound method.
554
+
555
+ Args:
556
+ instance: The instance to bind the method to.
557
+ unbound: The unbound function.
558
+ async_def: Whether the original function is an async def.
559
+ **modifiers: Additional modifiers for the function.
560
+
561
+ Examples:
562
+ >>> class MyClass:
563
+ ... def __init__(self, value):
564
+ ... self.value = value
565
+ ...
566
+ ... @ASyncMethodDescriptor
567
+ ... async def my_method(self):
568
+ ... return self.value
569
+ ...
570
+ >>> obj = MyClass(42)
571
+ >>> bound_method = ASyncBoundMethod(obj, MyClass.my_method, True)
572
+ """
573
+ # NOTE: This will be created by the Descriptor
574
+ self._cache_handle = None
575
+
576
+ # First we bind the method to a weak reference
577
+ # - bind and create a strong reference to the cache handle method
578
+ weakref_callback = self.__cancel_cache_handle
579
+ # - we do this so the bound callback method does not get garbage collected until this ASyncBoundMethod dies
580
+ self.__cancel_cache_handle = weakref_callback
581
+ self.__weakself__ = <object>PyWeakref_NewRef(<PyObject*>instance, <PyObject*>weakref_callback)
582
+
583
+ # Then we unwrap the coro_fn and rewrap it so overriding flag kwargs are handled automagically.
584
+ if isinstance(unbound, _ASyncFunction):
585
+ (<dict>modifiers).update((<_ASyncFunction>unbound).modifiers._modifiers)
586
+ unbound = (<_ASyncFunction>unbound).__wrapped__
587
+ # NOTE: the wrapped function was validated when the descriptor was initialized
588
+ _ASyncFunction.__init__(self, unbound, _skip_validate=True, **<dict>modifiers)
589
+ self._is_async_def = async_def
590
+ """True if `self.__wrapped__` is a coroutine function, False otherwise."""
591
+ update_wrapper(self, unbound)
592
+
593
+ def __repr__(self) -> str:
594
+ """
595
+ Return a string representation of the bound method.
596
+
597
+ Examples:
598
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
599
+ >>> repr(bound_method)
600
+ '<ASyncBoundMethod for function module.ClassName.method_name bound to instance>'
601
+ """
602
+ cdef object instance, instance_type
603
+
604
+ try:
605
+ instance = self.__c_self__()
606
+ instance_type = type(instance)
607
+ return "<{} for function {}.{}.{} bound to {}>".format(
608
+ self.__class__.__name__,
609
+ instance_type.__module__,
610
+ instance_type.__name__,
611
+ self.__name__,
612
+ instance,
613
+ )
614
+ except ReferenceError:
615
+ return "<{} for function COLLECTED.COLLECTED.{} bound to {}>".format(
616
+ self.__class__.__name__,
617
+ self.__name__,
618
+ self.__weakself__
619
+ )
620
+
621
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]:
622
+ """
623
+ Call the bound method.
624
+
625
+ This method handles both synchronous and asynchronous calls based on
626
+ the provided flags and the method's configuration.
627
+
628
+ Args:
629
+ *args: Positional arguments.
630
+ **kwargs: Keyword arguments.
631
+
632
+ Examples:
633
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
634
+ >>> await bound_method(arg1, arg2, kwarg1=value1)
635
+ >>> bound_method(arg1, arg2, kwarg1=value1, sync=True)
636
+ """
637
+ cdef object retval, coro
638
+ cdef bint debug_logs
639
+ if debug_logs := _logger_is_enabled(DEBUG):
640
+ _logger_log(DEBUG, "calling %s with args: %s kwargs: %s", (self, args, kwargs))
641
+ # This could either be a coroutine or a return value from an awaited coroutine,
642
+ # depending on if an overriding flag kwarg was passed into the function call.
643
+ retval = coro = _ASyncFunction.__call__(self, self.__c_self__(), *args, **kwargs)
644
+ if not isawaitable(retval):
645
+ # The coroutine was already awaited due to the use of an overriding flag kwarg.
646
+ # We can return the value.
647
+ pass
648
+ elif _should_await(self, kwargs):
649
+ # The awaitable was not awaited, so now we need to check the flag as defined on 'self' and await if appropriate.
650
+ if debug_logs:
651
+ _logger_log(
652
+ DEBUG, "awaiting %s for %s args: %s kwargs: %s", (coro, self, args, kwargs)
653
+ )
654
+ retval = _await(coro)
655
+ if debug_logs:
656
+ _logger_log(
657
+ DEBUG, "returning %s for %s args: %s kwargs: %s", (retval, self, args, kwargs)
658
+ )
659
+ return retval # type: ignore [call-overload, return-value]
660
+
661
+ @property
662
+ def __self__(self) -> object:
663
+ """
664
+ Get the instance the method is bound to.
665
+
666
+ Raises:
667
+ ReferenceError: If the instance has been garbage collected.
668
+
669
+ Examples:
670
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
671
+ >>> bound_method.__self__
672
+ <MyClass instance>
673
+ """
674
+ return self.__c_self__()
675
+
676
+ cdef object __c_self__(self):
677
+ cdef PyObject *self_ptr
678
+ if PyWeakref_GetRef(<PyObject*>self.__weakself__, &self_ptr) == 1:
679
+ # 1 is success
680
+ return <object>self_ptr
681
+ raise ReferenceError(self)
682
+
683
+ def map(
684
+ self,
685
+ *iterables: AnyIterable[I],
686
+ concurrency: Optional[int] = None,
687
+ task_name: str = "",
688
+ **kwargs: P.kwargs,
689
+ ) -> "TaskMapping[I, T]":
690
+ """
691
+ Create a TaskMapping for this method.
692
+
693
+ Args:
694
+ *iterables: Iterables to map over.
695
+ concurrency: Optional concurrency limit.
696
+ task_name: Optional name for the task.
697
+ **kwargs: Additional keyword arguments.
698
+
699
+ Returns:
700
+ A TaskMapping instance for this method.
701
+
702
+ Examples:
703
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
704
+ >>> task_mapping = bound_method.map(iterable1, iterable2, concurrency=5)
705
+ TODO briefly include how someone would then use task_mapping
706
+ """
707
+ return self.c_map(iterables, concurrency, task_name, kwargs)
708
+
709
+ cdef object c_map(self, tuple iterables, object concurrency, str task_name, dict kwargs):
710
+ if TaskMapping is None:
711
+ _import_TaskMapping()
712
+
713
+ return TaskMapping(
714
+ self, *iterables, concurrency=concurrency, name=task_name, **kwargs
715
+ )
716
+
717
+ async def any(
718
+ self,
719
+ *iterables: AnyIterable[I],
720
+ concurrency: Optional[int] = None,
721
+ task_name: str = "",
722
+ **kwargs: P.kwargs,
723
+ ) -> bool:
724
+ """
725
+ Check if any of the results are truthy.
726
+
727
+ Args:
728
+ *iterables: Iterables to map over.
729
+ concurrency: Optional concurrency limit.
730
+ task_name: Optional name for the task.
731
+ **kwargs: Additional keyword arguments.
732
+
733
+ Examples:
734
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
735
+ >>> result = await bound_method.any(iterable1, iterable2)
736
+ """
737
+ return await self.c_map(iterables, concurrency, task_name, kwargs).any(pop=True, sync=False)
738
+
739
+ async def all(
740
+ self,
741
+ *iterables: AnyIterable[I],
742
+ concurrency: Optional[int] = None,
743
+ task_name: str = "",
744
+ **kwargs: P.kwargs,
745
+ ) -> bool:
746
+ """
747
+ Check if all of the results are truthy.
748
+
749
+ Args:
750
+ *iterables: Iterables to map over.
751
+ concurrency: Optional concurrency limit.
752
+ task_name: Optional name for the task.
753
+ **kwargs: Additional keyword arguments.
754
+
755
+ Examples:
756
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
757
+ >>> result = await bound_method.all(iterable1, iterable2)
758
+ """
759
+ return await self.c_map(iterables, concurrency, task_name, kwargs).all(pop=True, sync=False)
760
+
761
+ async def min(
762
+ self,
763
+ *iterables: AnyIterable[I],
764
+ concurrency: Optional[int] = None,
765
+ task_name: str = "",
766
+ **kwargs: P.kwargs,
767
+ ) -> T:
768
+ """
769
+ Find the minimum result.
770
+
771
+ Args:
772
+ *iterables: Iterables to map over.
773
+ concurrency: Optional concurrency limit.
774
+ task_name: Optional name for the task.
775
+ **kwargs: Additional keyword arguments.
776
+
777
+ Examples:
778
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
779
+ >>> result = await bound_method.min(iterable1, iterable2)
780
+ """
781
+ return await self.c_map(iterables, concurrency, task_name, kwargs).min(pop=True, sync=False)
782
+
783
+ async def max(
784
+ self,
785
+ *iterables: AnyIterable[I],
786
+ concurrency: Optional[int] = None,
787
+ task_name: str = "",
788
+ **kwargs: P.kwargs,
789
+ ) -> T:
790
+ """
791
+ Find the maximum result.
792
+
793
+ Args:
794
+ *iterables: Iterables to map over.
795
+ concurrency: Optional concurrency limit.
796
+ task_name: Optional name for the task.
797
+ **kwargs: Additional keyword arguments.
798
+
799
+ Examples:
800
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
801
+ >>> result = await bound_method.max(iterable1, iterable2)
802
+ """
803
+ return await self.c_map(iterables, concurrency, task_name, kwargs).max(pop=True, sync=False)
804
+
805
+ async def sum(
806
+ self,
807
+ *iterables: AnyIterable[I],
808
+ concurrency: Optional[int] = None,
809
+ task_name: str = "",
810
+ **kwargs: P.kwargs,
811
+ ) -> T:
812
+ """
813
+ Calculate the sum of the results.
814
+
815
+ Args:
816
+ *iterables: Iterables to map over.
817
+ concurrency: Optional concurrency limit.
818
+ task_name: Optional name for the task.
819
+ **kwargs: Additional keyword arguments.
820
+
821
+ Examples:
822
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
823
+ >>> result = await bound_method.sum(iterable1, iterable2)
824
+ """
825
+ return await self.c_map(iterables, concurrency, task_name, kwargs).sum(pop=True, sync=False)
826
+
827
+
828
+ class ASyncBoundMethod(_ASyncBoundMethod, Generic[I, P, T]):
829
+ def __init__(
830
+ _ASyncFunction self,
831
+ instance: I,
832
+ unbound: AnyFn[Concatenate[I, P], T],
833
+ async_def: bool,
834
+ **modifiers: Unpack[ModifierKwargs],
835
+ ) -> None:
836
+ """
837
+ Initialize the bound method.
838
+
839
+ Args:
840
+ instance: The instance to bind the method to.
841
+ unbound: The unbound function.
842
+ async_def: Whether the original function is an async def.
843
+ **modifiers: Additional modifiers for the function.
844
+
845
+ Examples:
846
+ >>> class MyClass:
847
+ ... def __init__(self, value):
848
+ ... self.value = value
849
+ ...
850
+ ... @ASyncMethodDescriptor
851
+ ... async def my_method(self):
852
+ ... return self.value
853
+ ...
854
+ >>> obj = MyClass(42)
855
+ >>> bound_method = ASyncBoundMethod(obj, MyClass.my_method, True)
856
+ """
857
+ _ASyncBoundMethod.__init__(self, instance, unbound, async_def, modifiers)
858
+ update_wrapper(self, unbound)
859
+
860
+ @overload
861
+ def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
862
+ @overload
863
+ def __call__(
864
+ self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
865
+ ) -> Coroutine[Any, Any, T]: ...
866
+ @overload
867
+ def __call__(
868
+ self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
869
+ ) -> T: ...
870
+ @overload
871
+ def __call__(
872
+ self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
873
+ ) -> Coroutine[Any, Any, T]: ...
874
+ @overload
875
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]: ...
876
+
877
+ def __cancel_cache_handle(self, instance: I) -> None:
878
+ """
879
+ Cancel the cache handle.
880
+
881
+ Args:
882
+ instance: The instance associated with the cache handle.
883
+
884
+ Examples:
885
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
886
+ >>> bound_method.__cancel_cache_handle(instance)
887
+ """
888
+ handle = self._cache_handle
889
+ if handle is not None:
890
+ cancel_handle(handle)
891
+
892
+
893
+ class ASyncBoundMethodSyncDefault(ASyncBoundMethod[I, P, T]):
894
+ """
895
+ A bound method with synchronous default behavior.
896
+
897
+ This class is a specialized version of :class:`ASyncBoundMethod` that defaults to synchronous execution.
898
+ It overrides the `__call__` method to enforce synchronous default behavior.
899
+
900
+ Examples:
901
+ >>> class MyClass:
902
+ ... def __init__(self, value):
903
+ ... self.value = value
904
+ ...
905
+ ... @ASyncMethodDescriptorSyncDefault
906
+ ... def my_method(self):
907
+ ... return self.value
908
+ ...
909
+ >>> obj = MyClass(42)
910
+ >>> obj.my_method()
911
+ 42
912
+ >>> await obj.my_method(sync=False)
913
+ 42
914
+
915
+ See Also:
916
+ - :class:`ASyncBoundMethod`
917
+ - :class:`ASyncMethodDescriptorSyncDefault`
918
+ """
919
+
920
+ @overload
921
+ def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
922
+ @overload
923
+ def __call__(
924
+ self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
925
+ ) -> Coroutine[Any, Any, T]: ...
926
+ @overload
927
+ def __call__(
928
+ self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
929
+ ) -> T: ...
930
+ @overload
931
+ def __call__(
932
+ self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
933
+ ) -> Coroutine[Any, Any, T]: ...
934
+ @overload
935
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ...
936
+
937
+ def __call__(self, *args, **kwargs):
938
+ """
939
+ Call the bound method with synchronous default behavior.
940
+
941
+ Args:
942
+ *args: Positional arguments.
943
+ **kwargs: Keyword arguments.
944
+
945
+ Examples:
946
+ >>> bound_method = ASyncBoundMethodSyncDefault(instance, my_function, True)
947
+ >>> bound_method(arg1, arg2, kwarg1=value1)
948
+ """
949
+ return _ASyncBoundMethod.__call__(self, *args, **kwargs)
950
+
951
+
952
+ class ASyncBoundMethodAsyncDefault(ASyncBoundMethod[I, P, T]):
953
+ """
954
+ A bound method with asynchronous default behavior.
955
+
956
+ This class is a specialized version of :class:`ASyncBoundMethod` that defaults to asynchronous execution.
957
+ It overrides the `__call__` method to enforce asynchronous default behavior.
958
+
959
+ Examples:
960
+ >>> class MyClass:
961
+ ... def __init__(self, value):
962
+ ... self.value = value
963
+ ...
964
+ ... @ASyncMethodDescriptorAsyncDefault
965
+ ... async def my_method(self):
966
+ ... return self.value
967
+ ...
968
+ >>> obj = MyClass(42)
969
+ >>> await obj.my_method()
970
+ 42
971
+ >>> obj.my_method(sync=True)
972
+ 42
973
+
974
+ See Also:
975
+ - :class:`ASyncBoundMethod`
976
+ - :class:`ASyncMethodDescriptorAsyncDefault`
977
+ """
978
+
979
+ @overload
980
+ def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
981
+ @overload
982
+ def __call__(
983
+ self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
984
+ ) -> Coroutine[Any, Any, T]: ...
985
+ @overload
986
+ def __call__(
987
+ self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
988
+ ) -> T: ...
989
+ @overload
990
+ def __call__(
991
+ self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
992
+ ) -> Coroutine[Any, Any, T]: ...
993
+ @overload
994
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T]: ...
995
+
996
+ def __call__(self, *args, **kwargs):
997
+ """
998
+ Call the bound method with asynchronous default behavior.
999
+
1000
+ Args:
1001
+ *args: Positional arguments.
1002
+ **kwargs: Keyword arguments.
1003
+
1004
+ Examples:
1005
+ >>> bound_method = ASyncBoundMethodAsyncDefault(instance, my_function, True)
1006
+ >>> await bound_method(arg1, arg2, kwarg1=value1)
1007
+ """
1008
+ return _ASyncBoundMethod.__call__(self, *args, **kwargs)
1009
+
1010
+
1011
+ cdef inline void _import_ASyncABC():
1012
+ global ASyncABC
1013
+ from a_sync.a_sync.abstract import ASyncABC
1014
+
1015
+
1016
+ cdef inline void _import_TaskMapping():
1017
+ global TaskMapping
1018
+ from a_sync import TaskMapping
1019
+
1020
+
1021
+ del asyncio, inspect, typing, typing_extensions
1022
+ del _descriptor, function
1023
+