ez-a-sync 0.32.9__cp38-cp38-musllinux_1_2_i686.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 +144 -0
  4. a_sync/_smart.c +22623 -0
  5. a_sync/_smart.cpython-38-i386-linux-gnu.so +0 -0
  6. a_sync/_smart.pxd +2 -0
  7. a_sync/_smart.pyi +202 -0
  8. a_sync/_smart.pyx +652 -0
  9. a_sync/_typing.py +258 -0
  10. a_sync/a_sync/__init__.py +60 -0
  11. a_sync/a_sync/_descriptor.c +19745 -0
  12. a_sync/a_sync/_descriptor.cpython-38-i386-linux-gnu.so +0 -0
  13. a_sync/a_sync/_descriptor.pyi +34 -0
  14. a_sync/a_sync/_descriptor.pyx +422 -0
  15. a_sync/a_sync/_flags.c +5687 -0
  16. a_sync/a_sync/_flags.cpython-38-i386-linux-gnu.so +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 +13718 -0
  20. a_sync/a_sync/_helpers.cpython-38-i386-linux-gnu.so +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 +10672 -0
  25. a_sync/a_sync/_kwargs.cpython-38-i386-linux-gnu.so +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 +11350 -0
  30. a_sync/a_sync/abstract.cpython-38-i386-linux-gnu.so +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 +14066 -0
  34. a_sync/a_sync/base.cpython-38-i386-linux-gnu.so +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 +562 -0
  39. a_sync/a_sync/flags.c +4471 -0
  40. a_sync/a_sync/flags.cpython-38-i386-linux-gnu.so +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 +37747 -0
  45. a_sync/a_sync/function.cpython-38-i386-linux-gnu.so +0 -0
  46. a_sync/a_sync/function.pxd +24 -0
  47. a_sync/a_sync/function.pyi +556 -0
  48. a_sync/a_sync/function.pyx +1363 -0
  49. a_sync/a_sync/method.c +28387 -0
  50. a_sync/a_sync/method.cpython-38-i386-linux-gnu.so +0 -0
  51. a_sync/a_sync/method.pxd +2 -0
  52. a_sync/a_sync/method.pyi +524 -0
  53. a_sync/a_sync/method.pyx +999 -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 +15262 -0
  60. a_sync/a_sync/modifiers/manager.cpython-38-i386-linux-gnu.so +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 +296 -0
  64. a_sync/a_sync/modifiers/semaphores.py +173 -0
  65. a_sync/a_sync/property.c +27952 -0
  66. a_sync/a_sync/property.cpython-38-i386-linux-gnu.so +0 -0
  67. a_sync/a_sync/property.pyi +376 -0
  68. a_sync/a_sync/property.pyx +813 -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 +20542 -0
  74. a_sync/async_property/cached.cpython-38-i386-linux-gnu.so +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 +36410 -0
  79. a_sync/async_property/proxy.cpython-38-i386-linux-gnu.so +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 +18198 -0
  86. a_sync/asyncio/as_completed.cpython-38-i386-linux-gnu.so +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 +15032 -0
  91. a_sync/asyncio/create_task.cpython-38-i386-linux-gnu.so +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 +268 -0
  95. a_sync/asyncio/gather.c +15735 -0
  96. a_sync/asyncio/gather.cpython-38-i386-linux-gnu.so +0 -0
  97. a_sync/asyncio/gather.pyi +107 -0
  98. a_sync/asyncio/gather.pyx +218 -0
  99. a_sync/asyncio/igather.c +12334 -0
  100. a_sync/asyncio/igather.cpython-38-i386-linux-gnu.so +0 -0
  101. a_sync/asyncio/igather.pxd +1 -0
  102. a_sync/asyncio/igather.pyi +7 -0
  103. a_sync/asyncio/igather.pyx +175 -0
  104. a_sync/asyncio/sleep.c +8916 -0
  105. a_sync/asyncio/sleep.cpython-38-i386-linux-gnu.so +0 -0
  106. a_sync/asyncio/sleep.pyi +14 -0
  107. a_sync/asyncio/sleep.pyx +49 -0
  108. a_sync/debugging.c +15156 -0
  109. a_sync/debugging.cpython-38-i386-linux-gnu.so +0 -0
  110. a_sync/debugging.pyi +73 -0
  111. a_sync/debugging.pyx +107 -0
  112. a_sync/exceptions.c +12952 -0
  113. a_sync/exceptions.cpython-38-i386-linux-gnu.so +0 -0
  114. a_sync/exceptions.pyi +376 -0
  115. a_sync/exceptions.pyx +443 -0
  116. a_sync/executor.py +575 -0
  117. a_sync/functools.c +11489 -0
  118. a_sync/functools.cpython-38-i386-linux-gnu.so +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 +37567 -0
  124. a_sync/iter.cpython-38-i386-linux-gnu.so +0 -0
  125. a_sync/iter.pxd +9 -0
  126. a_sync/iter.pyi +366 -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 +14737 -0
  131. a_sync/primitives/_debug.cpython-38-i386-linux-gnu.so +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 +10569 -0
  136. a_sync/primitives/_loggable.cpython-38-i386-linux-gnu.so +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 +16972 -0
  143. a_sync/primitives/locks/counter.cpython-38-i386-linux-gnu.so +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 +16127 -0
  148. a_sync/primitives/locks/event.cpython-38-i386-linux-gnu.so +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 +183 -0
  152. a_sync/primitives/locks/prio_semaphore.c +24084 -0
  153. a_sync/primitives/locks/prio_semaphore.cpython-38-i386-linux-gnu.so +0 -0
  154. a_sync/primitives/locks/prio_semaphore.pxd +24 -0
  155. a_sync/primitives/locks/prio_semaphore.pyi +217 -0
  156. a_sync/primitives/locks/prio_semaphore.pyx +554 -0
  157. a_sync/primitives/locks/semaphore.c +25816 -0
  158. a_sync/primitives/locks/semaphore.cpython-38-i386-linux-gnu.so +0 -0
  159. a_sync/primitives/locks/semaphore.pxd +21 -0
  160. a_sync/primitives/locks/semaphore.pyi +196 -0
  161. a_sync/primitives/locks/semaphore.pyx +452 -0
  162. a_sync/primitives/queue.py +1018 -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 +916 -0
  167. a_sync/utils/__init__.py +105 -0
  168. a_sync/utils/iterators.py +297 -0
  169. a_sync/utils/repr.c +14354 -0
  170. a_sync/utils/repr.cpython-38-i386-linux-gnu.so +0 -0
  171. a_sync/utils/repr.pyi +2 -0
  172. a_sync/utils/repr.pyx +73 -0
  173. ez_a_sync-0.32.9.dist-info/LICENSE.txt +17 -0
  174. ez_a_sync-0.32.9.dist-info/METADATA +356 -0
  175. ez_a_sync-0.32.9.dist-info/RECORD +177 -0
  176. ez_a_sync-0.32.9.dist-info/WHEEL +5 -0
  177. ez_a_sync-0.32.9.dist-info/top_level.txt +1 -0
@@ -0,0 +1,999 @@
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, instance: I, bound: "ASyncBoundMethod"):
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(_ASyncFunction 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(self.__self__):
511
+ self.__self__: "ASyncABC"
512
+ return self.__self__.__a_sync_should_await__(kwargs)
513
+ return self._is_async_def
514
+
515
+
516
+ class ASyncBoundMethod(function.ASyncFunction[P, T], Generic[I, P, T]):
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
+ # NOTE: this is created by the Descriptor
546
+
547
+ _cache_handle: TimerHandle = None
548
+ """An asyncio handle used to pop the bound method from `instance.__dict__` 5 minutes after its last use."""
549
+
550
+ __weakself__: "ref[I]"
551
+ """A weak reference to the instance the function is bound to."""
552
+
553
+ __wrapped__: AnyFn[Concatenate[I, P], T]
554
+ """The original unbound method that was wrapped."""
555
+
556
+ __slots__ = "_is_async_def", "__weakself__"
557
+
558
+ def __init__(
559
+ _ASyncFunction self,
560
+ instance: I,
561
+ unbound: AnyFn[Concatenate[I, P], T],
562
+ async_def: bool,
563
+ **modifiers: Unpack[ModifierKwargs],
564
+ ) -> None:
565
+ """
566
+ Initialize the bound method.
567
+
568
+ Args:
569
+ instance: The instance to bind the method to.
570
+ unbound: The unbound function.
571
+ async_def: Whether the original function is an async def.
572
+ **modifiers: Additional modifiers for the function.
573
+
574
+ Examples:
575
+ >>> class MyClass:
576
+ ... def __init__(self, value):
577
+ ... self.value = value
578
+ ...
579
+ ... @ASyncMethodDescriptor
580
+ ... async def my_method(self):
581
+ ... return self.value
582
+ ...
583
+ >>> obj = MyClass(42)
584
+ >>> bound_method = ASyncBoundMethod(obj, MyClass.my_method, True)
585
+ """
586
+ # First we bind the method to a weak reference
587
+ # - bind and create a strong reference to the cache handle method
588
+ weakref_callback = self.__cancel_cache_handle
589
+ # - we do this so the bound callback method does not get garbage collected until this ASyncBoundMethod dies
590
+ self.__cancel_cache_handle = weakref_callback
591
+ self.__weakself__ = <object>PyWeakref_NewRef(<PyObject*>instance, <PyObject*>weakref_callback)
592
+
593
+ # Then we unwrap the coro_fn and rewrap it so overriding flag kwargs are handled automagically.
594
+ if isinstance(unbound, _ASyncFunction):
595
+ (<dict>modifiers).update((<_ASyncFunction>unbound).modifiers._modifiers)
596
+ unbound = (<_ASyncFunction>unbound).__wrapped__
597
+ # NOTE: the wrapped function was validated when the descriptor was initialized
598
+ _ASyncFunction.__init__(self, unbound, _skip_validate=True, **<dict>modifiers)
599
+ self._is_async_def = async_def
600
+ """True if `self.__wrapped__` is a coroutine function, False otherwise."""
601
+ update_wrapper(self, unbound)
602
+
603
+ def __repr__(self) -> str:
604
+ """
605
+ Return a string representation of the bound method.
606
+
607
+ Examples:
608
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
609
+ >>> repr(bound_method)
610
+ '<ASyncBoundMethod for function module.ClassName.method_name bound to instance>'
611
+ """
612
+ cdef object instance_type
613
+ try:
614
+ instance_type = type(self.__self__)
615
+ return "<{} for function {}.{}.{} bound to {}>".format(
616
+ self.__class__.__name__,
617
+ instance_type.__module__,
618
+ instance_type.__name__,
619
+ self.__name__,
620
+ self.__self__
621
+ )
622
+ except ReferenceError:
623
+ return "<{} for function COLLECTED.COLLECTED.{} bound to {}>".format(
624
+ self.__class__.__name__,
625
+ self.__name__,
626
+ self.__weakself__
627
+ )
628
+
629
+ @overload
630
+ def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
631
+ @overload
632
+ def __call__(
633
+ self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
634
+ ) -> Coroutine[Any, Any, T]: ...
635
+ @overload
636
+ def __call__(
637
+ self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
638
+ ) -> T: ...
639
+ @overload
640
+ def __call__(
641
+ self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
642
+ ) -> Coroutine[Any, Any, T]: ...
643
+ @overload
644
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]: ...
645
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> MaybeCoro[T]:
646
+ """
647
+ Call the bound method.
648
+
649
+ This method handles both synchronous and asynchronous calls based on
650
+ the provided flags and the method's configuration.
651
+
652
+ Args:
653
+ *args: Positional arguments.
654
+ **kwargs: Keyword arguments.
655
+
656
+ Examples:
657
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
658
+ >>> await bound_method(arg1, arg2, kwarg1=value1)
659
+ >>> bound_method(arg1, arg2, kwarg1=value1, sync=True)
660
+ """
661
+ cdef object retval, coro
662
+ cdef bint debug_logs
663
+ if debug_logs := _logger_is_enabled(DEBUG):
664
+ _logger_log(DEBUG, "calling %s with args: %s kwargs: %s", (self, args, kwargs))
665
+ # This could either be a coroutine or a return value from an awaited coroutine,
666
+ # depending on if an overriding flag kwarg was passed into the function call.
667
+ retval = coro = _ASyncFunction.__call__(self, self.__self__, *args, **kwargs)
668
+ if not isawaitable(retval):
669
+ # The coroutine was already awaited due to the use of an overriding flag kwarg.
670
+ # We can return the value.
671
+ pass
672
+ elif _should_await(self, kwargs):
673
+ # The awaitable was not awaited, so now we need to check the flag as defined on 'self' and await if appropriate.
674
+ if debug_logs:
675
+ _logger_log(
676
+ DEBUG, "awaiting %s for %s args: %s kwargs: %s", (coro, self, args, kwargs)
677
+ )
678
+ retval = _await(coro)
679
+ if debug_logs:
680
+ _logger_log(
681
+ DEBUG, "returning %s for %s args: %s kwargs: %s", (retval, self, args, kwargs)
682
+ )
683
+ return retval # type: ignore [call-overload, return-value]
684
+
685
+ @property
686
+ def __self__(self) -> I:
687
+ """
688
+ Get the instance the method is bound to.
689
+
690
+ Raises:
691
+ ReferenceError: If the instance has been garbage collected.
692
+
693
+ Examples:
694
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
695
+ >>> bound_method.__self__
696
+ <MyClass instance>
697
+ """
698
+ cdef PyObject *self_ptr
699
+ if PyWeakref_GetRef(<PyObject*>self.__weakself__, &self_ptr) == 1:
700
+ # 1 is success
701
+ return <object>self_ptr
702
+ raise ReferenceError(self)
703
+
704
+ def map(
705
+ self,
706
+ *iterables: AnyIterable[I],
707
+ concurrency: Optional[int] = None,
708
+ task_name: str = "",
709
+ **kwargs: P.kwargs,
710
+ ) -> "TaskMapping[I, T]":
711
+ """
712
+ Create a TaskMapping for this method.
713
+
714
+ Args:
715
+ *iterables: Iterables to map over.
716
+ concurrency: Optional concurrency limit.
717
+ task_name: Optional name for the task.
718
+ **kwargs: Additional keyword arguments.
719
+
720
+ Returns:
721
+ A TaskMapping instance for this method.
722
+
723
+ Examples:
724
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
725
+ >>> task_mapping = bound_method.map(iterable1, iterable2, concurrency=5)
726
+ TODO briefly include how someone would then use task_mapping
727
+ """
728
+ if TaskMapping is None:
729
+ _import_TaskMapping()
730
+
731
+ return TaskMapping(
732
+ self, *iterables, concurrency=concurrency, name=task_name, **kwargs
733
+ )
734
+
735
+ async def any(
736
+ self,
737
+ *iterables: AnyIterable[I],
738
+ concurrency: Optional[int] = None,
739
+ task_name: str = "",
740
+ **kwargs: P.kwargs,
741
+ ) -> bool:
742
+ """
743
+ Check if any of the results are truthy.
744
+
745
+ Args:
746
+ *iterables: Iterables to map over.
747
+ concurrency: Optional concurrency limit.
748
+ task_name: Optional name for the task.
749
+ **kwargs: Additional keyword arguments.
750
+
751
+ Examples:
752
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
753
+ >>> result = await bound_method.any(iterable1, iterable2)
754
+ """
755
+ return await self.map(
756
+ *iterables, concurrency=concurrency, task_name=task_name, **kwargs
757
+ ).any(pop=True, sync=False)
758
+
759
+ async def all(
760
+ self,
761
+ *iterables: AnyIterable[I],
762
+ concurrency: Optional[int] = None,
763
+ task_name: str = "",
764
+ **kwargs: P.kwargs,
765
+ ) -> bool:
766
+ """
767
+ Check if all of the results are truthy.
768
+
769
+ Args:
770
+ *iterables: Iterables to map over.
771
+ concurrency: Optional concurrency limit.
772
+ task_name: Optional name for the task.
773
+ **kwargs: Additional keyword arguments.
774
+
775
+ Examples:
776
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
777
+ >>> result = await bound_method.all(iterable1, iterable2)
778
+ """
779
+ return await self.map(
780
+ *iterables, concurrency=concurrency, task_name=task_name, **kwargs
781
+ ).all(pop=True, sync=False)
782
+
783
+ async def min(
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 minimum 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.min(iterable1, iterable2)
802
+ """
803
+ return await self.map(
804
+ *iterables, concurrency=concurrency, task_name=task_name, **kwargs
805
+ ).min(pop=True, sync=False)
806
+
807
+ async def max(
808
+ self,
809
+ *iterables: AnyIterable[I],
810
+ concurrency: Optional[int] = None,
811
+ task_name: str = "",
812
+ **kwargs: P.kwargs,
813
+ ) -> T:
814
+ """
815
+ Find the maximum result.
816
+
817
+ Args:
818
+ *iterables: Iterables to map over.
819
+ concurrency: Optional concurrency limit.
820
+ task_name: Optional name for the task.
821
+ **kwargs: Additional keyword arguments.
822
+
823
+ Examples:
824
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
825
+ >>> result = await bound_method.max(iterable1, iterable2)
826
+ """
827
+ return await self.map(
828
+ *iterables, concurrency=concurrency, task_name=task_name, **kwargs
829
+ ).max(pop=True, sync=False)
830
+
831
+ async def sum(
832
+ self,
833
+ *iterables: AnyIterable[I],
834
+ concurrency: Optional[int] = None,
835
+ task_name: str = "",
836
+ **kwargs: P.kwargs,
837
+ ) -> T:
838
+ """
839
+ Calculate the sum of the results.
840
+
841
+ Args:
842
+ *iterables: Iterables to map over.
843
+ concurrency: Optional concurrency limit.
844
+ task_name: Optional name for the task.
845
+ **kwargs: Additional keyword arguments.
846
+
847
+ Examples:
848
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
849
+ >>> result = await bound_method.sum(iterable1, iterable2)
850
+ """
851
+ return await self.map(
852
+ *iterables, concurrency=concurrency, task_name=task_name, **kwargs
853
+ ).sum(pop=True, sync=False)
854
+
855
+ def __cancel_cache_handle(self, instance: I) -> None:
856
+ """
857
+ Cancel the cache handle.
858
+
859
+ Args:
860
+ instance: The instance associated with the cache handle.
861
+
862
+ Examples:
863
+ >>> bound_method = ASyncBoundMethod(instance, my_function, True)
864
+ >>> bound_method.__cancel_cache_handle(instance)
865
+ """
866
+ handle = self._cache_handle
867
+ if handle is not None:
868
+ cancel_handle(handle)
869
+
870
+
871
+ class ASyncBoundMethodSyncDefault(ASyncBoundMethod[I, P, T]):
872
+ """
873
+ A bound method with synchronous default behavior.
874
+
875
+ This class is a specialized version of :class:`ASyncBoundMethod` that defaults to synchronous execution.
876
+ It overrides the `__call__` method to enforce synchronous default behavior.
877
+
878
+ Examples:
879
+ >>> class MyClass:
880
+ ... def __init__(self, value):
881
+ ... self.value = value
882
+ ...
883
+ ... @ASyncMethodDescriptorSyncDefault
884
+ ... def my_method(self):
885
+ ... return self.value
886
+ ...
887
+ >>> obj = MyClass(42)
888
+ >>> obj.my_method()
889
+ 42
890
+ >>> await obj.my_method(sync=False)
891
+ 42
892
+
893
+ See Also:
894
+ - :class:`ASyncBoundMethod`
895
+ - :class:`ASyncMethodDescriptorSyncDefault`
896
+ """
897
+
898
+ @overload
899
+ def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
900
+ @overload
901
+ def __call__(
902
+ self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
903
+ ) -> Coroutine[Any, Any, T]: ...
904
+ @overload
905
+ def __call__(
906
+ self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
907
+ ) -> T: ...
908
+ @overload
909
+ def __call__(
910
+ self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
911
+ ) -> Coroutine[Any, Any, T]: ...
912
+ @overload
913
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ...
914
+
915
+ __call__ = ASyncBoundMethod.__call__
916
+ """
917
+ Call the bound method with synchronous default behavior.
918
+
919
+ Args:
920
+ *args: Positional arguments.
921
+ **kwargs: Keyword arguments.
922
+
923
+ Examples:
924
+ >>> bound_method = ASyncBoundMethodSyncDefault(instance, my_function, True)
925
+ >>> bound_method(arg1, arg2, kwarg1=value1)
926
+ """
927
+
928
+
929
+ class ASyncBoundMethodAsyncDefault(ASyncBoundMethod[I, P, T]):
930
+ """
931
+ A bound method with asynchronous default behavior.
932
+
933
+ This class is a specialized version of :class:`ASyncBoundMethod` that defaults to asynchronous execution.
934
+ It overrides the `__call__` method to enforce asynchronous default behavior.
935
+
936
+ Examples:
937
+ >>> class MyClass:
938
+ ... def __init__(self, value):
939
+ ... self.value = value
940
+ ...
941
+ ... @ASyncMethodDescriptorAsyncDefault
942
+ ... async def my_method(self):
943
+ ... return self.value
944
+ ...
945
+ >>> obj = MyClass(42)
946
+ >>> await obj.my_method()
947
+ 42
948
+ >>> obj.my_method(sync=True)
949
+ 42
950
+
951
+ See Also:
952
+ - :class:`ASyncBoundMethod`
953
+ - :class:`ASyncMethodDescriptorAsyncDefault`
954
+ """
955
+
956
+ @overload
957
+ def __call__(self, *args: P.args, sync: Literal[True], **kwargs: P.kwargs) -> T: ...
958
+ @overload
959
+ def __call__(
960
+ self, *args: P.args, sync: Literal[False], **kwargs: P.kwargs
961
+ ) -> Coroutine[Any, Any, T]: ...
962
+ @overload
963
+ def __call__(
964
+ self, *args: P.args, asynchronous: Literal[False], **kwargs: P.kwargs
965
+ ) -> T: ...
966
+ @overload
967
+ def __call__(
968
+ self, *args: P.args, asynchronous: Literal[True], **kwargs: P.kwargs
969
+ ) -> Coroutine[Any, Any, T]: ...
970
+ @overload
971
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T]: ...
972
+
973
+ __call__ = ASyncBoundMethod.__call__
974
+ """
975
+ Call the bound method with asynchronous default behavior.
976
+
977
+ Args:
978
+ *args: Positional arguments.
979
+ **kwargs: Keyword arguments.
980
+
981
+ Examples:
982
+ >>> bound_method = ASyncBoundMethodAsyncDefault(instance, my_function, True)
983
+ >>> await bound_method(arg1, arg2, kwarg1=value1)
984
+ """
985
+
986
+
987
+ cdef inline void _import_ASyncABC():
988
+ global ASyncABC
989
+ from a_sync.a_sync.abstract import ASyncABC
990
+
991
+
992
+ cdef inline void _import_TaskMapping():
993
+ global TaskMapping
994
+ from a_sync import TaskMapping
995
+
996
+
997
+ del asyncio, inspect, typing, typing_extensions
998
+ del _descriptor, function
999
+