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,819 @@
1
+ import asyncio
2
+ import functools
3
+ import typing
4
+ from copy import copy as _copy
5
+ from logging import getLogger
6
+ from typing import Any, Awaitable, Callable, Generator, Optional, Tuple, Type, Union
7
+
8
+ import async_property as ap # type: ignore [import]
9
+ from typing_extensions import Concatenate, Self, Unpack
10
+
11
+ from a_sync._smart cimport shield
12
+ from a_sync._typing import (AnyFn, AnyGetterFunction, AnyIterable, AsyncGetterFunction,
13
+ DefaultMode, I, ModifierKwargs, P, T)
14
+ from a_sync.a_sync import _descriptor, config, function, method
15
+ from a_sync.a_sync._helpers cimport _asyncify, _await
16
+
17
+ from a_sync.a_sync.function cimport _ModifiedMixin
18
+ from a_sync.a_sync.method cimport _ASyncBoundMethod, _is_a_sync_instance, _update_cache_timer
19
+ from a_sync.async_property import cached
20
+ from a_sync.async_property.cached cimport AsyncCachedPropertyInstanceState
21
+ from a_sync.asyncio.create_task cimport ccreate_task_simple
22
+ from a_sync.functools cimport wraps
23
+
24
+ if typing.TYPE_CHECKING:
25
+ from a_sync.task import TaskMapping
26
+
27
+ else:
28
+ # to prevent circ import issues we will import this later
29
+ TaskMapping = None
30
+
31
+
32
+ # cdef asyncio
33
+ cdef object get_event_loop = asyncio.get_event_loop
34
+ cdef object iscoroutinefunction = asyncio.iscoroutinefunction
35
+ cdef object Lock = asyncio.Lock
36
+ cdef object Task = asyncio.Task
37
+ del asyncio
38
+
39
+ # cdef copy
40
+ cdef object copy = _copy
41
+ del _copy
42
+
43
+ # cdef functools
44
+ cdef object partial = functools.partial
45
+ del functools
46
+
47
+ # cdef logging
48
+ cdef public object logger = getLogger(__name__)
49
+ cdef object _logger_is_enabled = logger.isEnabledFor
50
+ cdef object _logger_debug = logger.debug
51
+ cdef object _logger_log = logger._log
52
+ cdef object DEBUG = 10
53
+ del getLogger
54
+
55
+ # cdef typing
56
+ cdef object Literal = typing.Literal
57
+ cdef object overload = typing.overload
58
+ del typing
59
+
60
+
61
+ # cdef a_sync.a_sync._descriptor
62
+ cdef object ASyncDescriptor = _descriptor.ASyncDescriptor
63
+ del _descriptor
64
+
65
+ # cdef a_sync.a_sync.function
66
+ cdef object ASyncFunction = function.ASyncFunction
67
+ cdef object ASyncFunctionAsyncDefault = function.ASyncFunctionAsyncDefault
68
+ cdef object ASyncFunctionSyncDefault = function.ASyncFunctionSyncDefault
69
+ del function
70
+
71
+ # cdef a_sync.a_sync.method
72
+ cdef object ASyncBoundMethod = method.ASyncBoundMethod
73
+ cdef object ASyncBoundMethodAsyncDefault = method.ASyncBoundMethodAsyncDefault
74
+ cdef object ASyncMethodDescriptorAsyncDefault = method.ASyncMethodDescriptorAsyncDefault
75
+ del method
76
+
77
+
78
+ class _ASyncPropertyDescriptorBase(ASyncDescriptor[I, Tuple[()], T]):
79
+ """Base class for creating asynchronous properties.
80
+
81
+ This class provides the foundation for defining properties that can be accessed
82
+ both synchronously and asynchronously. It includes utility methods for common
83
+ operations such as `any`, `all`, `min`, `max`, and `sum`.
84
+ """
85
+
86
+ any: ASyncFunction[AnyIterable[I], bool]
87
+ """An ASyncFunction that checks if any result is truthy."""
88
+
89
+ all: ASyncFunction[AnyIterable[I], bool]
90
+ """An ASyncFunction that checks if all results are truthy."""
91
+
92
+ min: ASyncFunction[AnyIterable[I], T]
93
+ """An ASyncFunction that returns the minimum result."""
94
+
95
+ max: ASyncFunction[AnyIterable[I], T]
96
+ """An ASyncFunction that returns the maximum result."""
97
+
98
+ sum: ASyncFunction[AnyIterable[I], T]
99
+ """An ASyncFunction that returns the sum of results."""
100
+
101
+ hidden_method_descriptor: "HiddenMethodDescriptor[T]"
102
+ """A descriptor for the hidden method."""
103
+
104
+ __wrapped__: Callable[[I], T]
105
+ """The wrapped function or method."""
106
+
107
+ __slots__ = "hidden_method_name", "hidden_method_descriptor", "_fget"
108
+
109
+ def __init__(
110
+ _ModifiedMixin self,
111
+ _fget: AsyncGetterFunction[I, T],
112
+ field_name: Optional[str] = None,
113
+ **modifiers: Unpack[ModifierKwargs],
114
+ ) -> None:
115
+ """Initializes the _ASyncPropertyDescriptorBase.
116
+
117
+ Args:
118
+ _fget: The function to be wrapped.
119
+ field_name: Optional name for the field. If not provided, the function's name will be used.
120
+ **modifiers: Additional modifier arguments.
121
+ """
122
+ cdef dict hidden_modifiers
123
+ ASyncDescriptor.__init__(self, _fget, field_name, **modifiers)
124
+ self.hidden_method_name = f"__{self.field_name}__"
125
+ hidden_modifiers = self.modifiers._modifiers.copy()
126
+ hidden_modifiers["default"] = "async"
127
+ self.hidden_method_descriptor = HiddenMethodDescriptor(
128
+ self.get, self.hidden_method_name, **hidden_modifiers
129
+ )
130
+ if iscoroutinefunction(_fget):
131
+ self._fget = self.__wrapped__
132
+ else:
133
+ self._fget = _asyncify(self.__wrapped__, self.modifiers.executor)
134
+
135
+ @overload
136
+ def __get__(self, instance: None, owner: Type[I]) -> Self: ...
137
+ @overload
138
+ def __get__(self, instance: I, owner: Type[I]) -> Awaitable[T]: ...
139
+ def __get__(
140
+ self, instance: Optional[I], owner: Type[I]
141
+ ) -> Union[Self, Awaitable[T]]:
142
+ """Retrieves the property value, either synchronously or asynchronously.
143
+
144
+ Args:
145
+ instance: The instance from which the property is accessed.
146
+ owner: The owner class of the property.
147
+
148
+ Returns:
149
+ The property value, either as an awaitable or directly.
150
+ """
151
+ if instance is None:
152
+ return self
153
+
154
+ cdef object awaitable = super().__get__(instance, owner)
155
+
156
+ # if the user didn't specify a default behavior, we will defer to the instance
157
+ cdef bint should_await
158
+ cdef str default = _ModifiedMixin.get_default(self)
159
+ if default:
160
+ should_await = default == "sync"
161
+ elif _is_a_sync_instance(instance):
162
+ should_await = instance.__a_sync_instance_should_await__
163
+ else:
164
+ should_await = not get_event_loop().is_running()
165
+
166
+ cdef object retval
167
+ cdef bint debug_logs = _logger_is_enabled(DEBUG)
168
+ if should_await:
169
+ if debug_logs:
170
+ _logger_log(
171
+ DEBUG,
172
+ "awaiting awaitable for %s for instance: %s owner: %s",
173
+ (awaitable, self, instance, owner),
174
+ )
175
+ retval = _await(awaitable)
176
+ else:
177
+ retval = awaitable
178
+
179
+ if debug_logs:
180
+ _logger_log(
181
+ DEBUG,
182
+ "returning %s for %s for instance: %s owner: %s",
183
+ (retval, self, instance, owner),
184
+ )
185
+
186
+ return retval
187
+
188
+ async def get(self, instance: I, owner: Optional[Type[I]] = None) -> T:
189
+ """Asynchronously retrieves the property value.
190
+
191
+ Args:
192
+ instance: The instance from which the property is accessed.
193
+ owner: The owner class of the property.
194
+
195
+ Returns:
196
+ The property value.
197
+ """
198
+ _logger_debug("awaiting %s for instance %s", self, instance)
199
+ return await super().__get__(instance, owner)
200
+
201
+ def map(
202
+ self,
203
+ instances: AnyIterable[I],
204
+ owner: Optional[Type[I]] = None,
205
+ concurrency: Optional[int] = None,
206
+ name: str = "",
207
+ ) -> "TaskMapping[I, T]":
208
+ """Maps the property across multiple instances.
209
+
210
+ Args:
211
+ instances: An iterable of instances.
212
+ owner: The owner class of the property.
213
+ concurrency: Optional concurrency limit.
214
+ name: Optional name for the task mapping.
215
+
216
+ Returns:
217
+ A TaskMapping object.
218
+ """
219
+ _logger_debug("mapping %s to instances: %s owner: %s", self, instances, owner)
220
+
221
+ """NOTE: This silly helper just fixes a circular import"""
222
+ if TaskMapping is None:
223
+ _import_TaskMapping()
224
+
225
+ return TaskMapping(
226
+ self,
227
+ instances,
228
+ owner=owner,
229
+ name=name or self.field_name,
230
+ concurrency=concurrency,
231
+ )
232
+
233
+
234
+ class ASyncPropertyDescriptor(
235
+ _ASyncPropertyDescriptorBase[I, T], ap.base.AsyncPropertyDescriptor
236
+ ):
237
+ """Descriptor class for asynchronous properties."""
238
+
239
+
240
+ class ASyncPropertyDescriptorSyncDefault(ASyncPropertyDescriptor[I, T]):
241
+ """
242
+ A variant of :class:`~ASyncPropertyDescriptor` that defaults to synchronous behavior.
243
+
244
+ This class is used when the property is primarily intended to be accessed
245
+ synchronously but can also be used asynchronously if needed.
246
+ """
247
+
248
+ # TODO give all of these docstrings
249
+ default = "sync"
250
+ # TODO and give these ones examples
251
+ any: ASyncFunctionSyncDefault[AnyIterable[I], bool]
252
+ all: ASyncFunctionSyncDefault[AnyIterable[I], bool]
253
+ min: ASyncFunctionSyncDefault[AnyIterable[I], T]
254
+ max: ASyncFunctionSyncDefault[AnyIterable[I], T]
255
+ sum: ASyncFunctionSyncDefault[AnyIterable[I], T]
256
+
257
+ @overload
258
+ def __get__(self, instance: None, owner: Type[I]) -> Self: ...
259
+ @overload
260
+ def __get__(self, instance: I, owner: Type[I]) -> T: ...
261
+
262
+ __get__ = _ASyncPropertyDescriptorBase.__get__
263
+ """Retrieves the property value, either synchronously or asynchronously.
264
+
265
+ Args:
266
+ instance: The instance from which the property is accessed.
267
+ owner: The owner class of the property.
268
+
269
+ Returns:
270
+ The property value, either as an awaitable or directly.
271
+ """
272
+
273
+
274
+ class ASyncPropertyDescriptorAsyncDefault(ASyncPropertyDescriptor[I, T]):
275
+ """
276
+ A variant of :class:`~ASyncPropertyDescriptor` that defaults to asynchronous behavior.
277
+
278
+ This class is used when the property is primarily intended to be accessed
279
+ asynchronously but can also be used synchronously if needed.
280
+ """
281
+
282
+ # TODO give all of these docstrings
283
+ default = "async"
284
+ # TODO and give these ones examples
285
+ any: ASyncFunctionAsyncDefault[AnyIterable[I], bool]
286
+ all: ASyncFunctionAsyncDefault[AnyIterable[I], bool]
287
+ min: ASyncFunctionAsyncDefault[AnyIterable[I], T]
288
+ max: ASyncFunctionAsyncDefault[AnyIterable[I], T]
289
+ sum: ASyncFunctionAsyncDefault[AnyIterable[I], T]
290
+
291
+
292
+ # Give all of these docstrings
293
+ ASyncPropertyDecorator = Callable[[AnyGetterFunction[I, T]], ASyncPropertyDescriptor[I, T]]
294
+ ASyncPropertyDecoratorSyncDefault = Callable[
295
+ [AnyGetterFunction[I, T]], ASyncPropertyDescriptorSyncDefault[I, T]
296
+ ]
297
+ ASyncPropertyDecoratorAsyncDefault = Callable[
298
+ [AnyGetterFunction[I, T]], ASyncPropertyDescriptorAsyncDefault[I, T]
299
+ ]
300
+
301
+
302
+ @overload
303
+ def a_sync_property( # type: ignore [misc]
304
+ func: Literal[None] = None,
305
+ **modifiers: Unpack[ModifierKwargs],
306
+ ) -> ASyncPropertyDecorator[I, T]: ...
307
+
308
+
309
+ @overload
310
+ def a_sync_property( # type: ignore [misc]
311
+ func: AnyGetterFunction[I, T],
312
+ **modifiers: Unpack[ModifierKwargs],
313
+ ) -> ASyncPropertyDescriptor[I, T]: ...
314
+
315
+
316
+ @overload
317
+ def a_sync_property( # type: ignore [misc]
318
+ func: Literal[None],
319
+ default: Literal["sync"],
320
+ **modifiers: Unpack[ModifierKwargs],
321
+ ) -> ASyncPropertyDecoratorSyncDefault[I, T]: ...
322
+
323
+
324
+ @overload
325
+ def a_sync_property( # type: ignore [misc]
326
+ func: Literal[None],
327
+ default: Literal["sync"],
328
+ **modifiers: Unpack[ModifierKwargs],
329
+ ) -> ASyncPropertyDecoratorSyncDefault[I, T]: ...
330
+
331
+
332
+ @overload
333
+ def a_sync_property( # type: ignore [misc]
334
+ func: Literal[None],
335
+ default: Literal["async"],
336
+ **modifiers: Unpack[ModifierKwargs],
337
+ ) -> ASyncPropertyDecoratorAsyncDefault[I, T]: ...
338
+
339
+
340
+ @overload
341
+ def a_sync_property( # type: ignore [misc]
342
+ func: Literal[None],
343
+ default: DefaultMode = config.DEFAULT_MODE,
344
+ **modifiers: Unpack[ModifierKwargs],
345
+ ) -> ASyncPropertyDecorator[I, T]: ...
346
+
347
+
348
+ @overload
349
+ def a_sync_property( # type: ignore [misc]
350
+ default: Literal["sync"],
351
+ **modifiers: Unpack[ModifierKwargs],
352
+ ) -> ASyncPropertyDecoratorSyncDefault[I, T]: ...
353
+
354
+
355
+ @overload
356
+ def a_sync_property( # type: ignore [misc]
357
+ default: Literal["async"],
358
+ **modifiers: Unpack[ModifierKwargs],
359
+ ) -> ASyncPropertyDecoratorAsyncDefault[I, T]: ...
360
+
361
+
362
+ @overload
363
+ def a_sync_property( # type: ignore [misc]
364
+ func: AnyGetterFunction[I, T],
365
+ default: Literal["sync"],
366
+ **modifiers: Unpack[ModifierKwargs],
367
+ ) -> ASyncPropertyDescriptorSyncDefault[I, T]: ...
368
+
369
+
370
+ @overload
371
+ def a_sync_property( # type: ignore [misc]
372
+ func: AnyGetterFunction[I, T],
373
+ default: Literal["async"],
374
+ **modifiers: Unpack[ModifierKwargs],
375
+ ) -> ASyncPropertyDescriptorAsyncDefault[I, T]: ...
376
+
377
+
378
+ @overload
379
+ def a_sync_property( # type: ignore [misc]
380
+ func: AnyGetterFunction[I, T],
381
+ default: DefaultMode = config.DEFAULT_MODE,
382
+ **modifiers: Unpack[ModifierKwargs],
383
+ ) -> ASyncPropertyDescriptor[I, T]: ...
384
+
385
+
386
+ def a_sync_property( # type: ignore [misc]
387
+ func: Union[AnyGetterFunction[I, T], DefaultMode] = None,
388
+ **modifiers: Unpack[ModifierKwargs],
389
+ ) -> Union[
390
+ ASyncPropertyDescriptor[I, T],
391
+ ASyncPropertyDescriptorSyncDefault[I, T],
392
+ ASyncPropertyDescriptorAsyncDefault[I, T],
393
+ ASyncPropertyDecorator[I, T],
394
+ ASyncPropertyDecoratorSyncDefault[I, T],
395
+ ASyncPropertyDecoratorAsyncDefault[I, T],
396
+ ]:
397
+ """Decorator for creating properties that can be accessed both synchronously and asynchronously.
398
+
399
+ Args:
400
+ func: The function to be wrapped.
401
+ **modifiers: Additional modifier arguments.
402
+
403
+ Returns:
404
+ A property descriptor that supports both sync and async access.
405
+ """
406
+ func, modifiers = _parse_args(func, <dict>modifiers)
407
+ cdef object descriptor_class
408
+ if (<dict>modifiers).get("default") == "sync":
409
+ descriptor_class = ASyncPropertyDescriptorSyncDefault
410
+ elif (<dict>modifiers).get("default") == "async":
411
+ descriptor_class = ASyncPropertyDescriptorAsyncDefault
412
+ else:
413
+ descriptor_class = ASyncPropertyDescriptor
414
+ decorator = partial(descriptor_class, **modifiers)
415
+ return decorator if func is None else decorator(func)
416
+
417
+
418
+ class ASyncCachedPropertyDescriptor(
419
+ _ASyncPropertyDescriptorBase[I, T], cached.AsyncCachedPropertyDescriptor
420
+ ):
421
+ """
422
+ A descriptor class for dual-function sync/async cached properties.
423
+
424
+ This class extends the API of ASyncPropertyDescriptor to provide
425
+ caching functionality, storing the computed value after the first access.
426
+ """
427
+
428
+ __slots__ = "_fset", "_fdel", "__async_property__"
429
+
430
+ def __init__(
431
+ self,
432
+ _fget: AsyncGetterFunction[I, T],
433
+ _fset=None,
434
+ _fdel=None,
435
+ field_name=None,
436
+ **modifiers: Unpack[ModifierKwargs],
437
+ ) -> None:
438
+ """Initializes the ASyncCachedPropertyDescriptor.
439
+
440
+ Args:
441
+ _fget: The function to be wrapped.
442
+ _fset: Optional setter function for the property.
443
+ _fdel: Optional deleter function for the property.
444
+ field_name: Optional name for the field. If not provided, the function's name will be used.
445
+ **modifiers: Additional modifier arguments.
446
+ """
447
+ _ASyncPropertyDescriptorBase.__init__(self, _fget, field_name, **modifiers)
448
+ self._check_method_sync(_fset, "setter")
449
+ self._fset = _fset
450
+ """Optional setter function for the property."""
451
+
452
+ self._check_method_sync(_fdel, "deleter")
453
+ self._fdel = _fdel
454
+ """Optional deleter function for the property."""
455
+
456
+ def get_lock(self, instance: I) -> "Task[T]":
457
+ """Retrieves the lock for the property.
458
+
459
+ Args:
460
+ instance: The instance from which the property is accessed.
461
+
462
+ Returns:
463
+ An asyncio Task representing the lock.
464
+ """
465
+ locks = (<AsyncCachedPropertyInstanceState>self.get_instance_state(instance)).locks
466
+ task = locks[self.field_name]
467
+ if isinstance(task, Lock):
468
+ # default behavior uses lock but we want to use a Task so all waiters wake up together
469
+ task = ccreate_task_simple(self._fget(instance))
470
+ locks[self.field_name] = task
471
+ return task
472
+
473
+ def get_loader(self, instance: I) -> Callable[[], T]:
474
+ """Retrieves the loader function for the property.
475
+
476
+ Args:
477
+ instance: The instance from which the property is accessed.
478
+
479
+ Returns:
480
+ A callable that loads the property value.
481
+ """
482
+ cdef str field_name
483
+
484
+ loader = self._load_value
485
+ if loader is None:
486
+ field_name = self.field_name
487
+
488
+ @wraps(self._fget)
489
+ async def loader(instance):
490
+ cdef AsyncCachedPropertyInstanceState cache_state
491
+ cache_state = self.get_instance_state(instance)
492
+
493
+ inner_task = cache_state.locks[field_name]
494
+ if isinstance(inner_task, Lock):
495
+ # default behavior uses lock but we want to use a Task so all waiters wake up together
496
+ inner_task = ccreate_task_simple(self._fget(instance))
497
+ cache_state.locks[field_name] = inner_task
498
+
499
+ try:
500
+ value = await shield(inner_task)
501
+ except Exception as e:
502
+ instance_context = {"property": self, "instance": instance}
503
+ if e.args and e.args[-1] != instance_context:
504
+ e.args = *e.args, instance_context
505
+ raise copy(e).with_traceback(e.__traceback__)
506
+
507
+ if self._fset is not None:
508
+ self._fset(instance, value)
509
+
510
+ if field_name not in cache_state.cache:
511
+ cache_state.cache[field_name] = value
512
+ cache_state.locks.pop(field_name)
513
+
514
+ return value
515
+
516
+ self._load_value = loader
517
+
518
+ return lambda: loader(instance)
519
+
520
+
521
+ class ASyncCachedPropertyDescriptorSyncDefault(ASyncCachedPropertyDescriptor[I, T]):
522
+ """
523
+ A variant of :class:`~ASyncCachedPropertyDescriptor` that defaults to synchronous behavior.
524
+
525
+ This class is used for cached properties that are primarily intended to be
526
+ accessed synchronously but can also be used asynchronously if needed.
527
+
528
+ Note:
529
+ You should never create these yourself. They are automatically generated by ez-a-sync internally.
530
+ """
531
+
532
+ default: Literal["sync"]
533
+
534
+ @overload
535
+ def __get__(self, instance: None, owner: Type[I]) -> Self: ...
536
+ @overload
537
+ def __get__(self, instance: I, owner: Type[I]) -> T: ...
538
+
539
+ __get__ = _ASyncPropertyDescriptorBase.__get__
540
+ """Retrieves the cached property value, either synchronously or asynchronously.
541
+
542
+ Args:
543
+ instance: The instance from which the property is accessed.
544
+ owner: The owner class of the property.
545
+
546
+ Returns:
547
+ The cached property value, either as an awaitable or directly.
548
+ """
549
+
550
+
551
+ class ASyncCachedPropertyDescriptorAsyncDefault(ASyncCachedPropertyDescriptor[I, T]):
552
+ """
553
+ A variant of :class:`~ASyncCachedPropertyDescriptor` that defaults to asynchronous behavior.
554
+
555
+ This class is used for cached properties that are primarily intended to be
556
+ accessed asynchronously but can also be used synchronously if needed.
557
+
558
+ Note:
559
+ You should never create these yourself. They are automatically generated by ez-a-sync internally.
560
+ """
561
+
562
+ default: Literal["async"]
563
+
564
+
565
+ ASyncCachedPropertyDecorator = Callable[
566
+ [AnyGetterFunction[I, T]], ASyncCachedPropertyDescriptor[I, T]
567
+ ]
568
+ ASyncCachedPropertyDecoratorSyncDefault = Callable[
569
+ [AnyGetterFunction[I, T]], ASyncCachedPropertyDescriptorSyncDefault[I, T]
570
+ ]
571
+ ASyncCachedPropertyDecoratorAsyncDefault = Callable[
572
+ [AnyGetterFunction[I, T]], ASyncCachedPropertyDescriptorAsyncDefault[I, T]
573
+ ]
574
+
575
+
576
+ @overload
577
+ def a_sync_cached_property( # type: ignore [misc]
578
+ func: Literal[None] = None,
579
+ **modifiers: Unpack[ModifierKwargs],
580
+ ) -> ASyncCachedPropertyDecorator[I, T]: ...
581
+
582
+
583
+ @overload
584
+ def a_sync_cached_property( # type: ignore [misc]
585
+ func: AnyGetterFunction[I, T],
586
+ **modifiers: Unpack[ModifierKwargs],
587
+ ) -> ASyncCachedPropertyDescriptor[I, T]: ...
588
+
589
+
590
+ @overload
591
+ def a_sync_cached_property( # type: ignore [misc]
592
+ func: Literal[None],
593
+ default: Literal["sync"],
594
+ **modifiers: Unpack[ModifierKwargs],
595
+ ) -> ASyncCachedPropertyDecoratorSyncDefault[I, T]: ...
596
+
597
+
598
+ @overload
599
+ def a_sync_cached_property( # type: ignore [misc]
600
+ func: Literal[None],
601
+ default: Literal["async"],
602
+ **modifiers: Unpack[ModifierKwargs],
603
+ ) -> ASyncCachedPropertyDecoratorAsyncDefault[I, T]: ...
604
+
605
+
606
+ @overload
607
+ def a_sync_cached_property( # type: ignore [misc]
608
+ func: Literal[None],
609
+ default: DefaultMode,
610
+ **modifiers: Unpack[ModifierKwargs],
611
+ ) -> ASyncCachedPropertyDecorator[I, T]: ...
612
+
613
+
614
+ @overload
615
+ def a_sync_cached_property( # type: ignore [misc]
616
+ default: Literal["sync"],
617
+ **modifiers: Unpack[ModifierKwargs],
618
+ ) -> ASyncCachedPropertyDecoratorSyncDefault[I, T]: ...
619
+
620
+
621
+ @overload
622
+ def a_sync_cached_property( # type: ignore [misc]
623
+ default: Literal["async"],
624
+ **modifiers: Unpack[ModifierKwargs],
625
+ ) -> ASyncCachedPropertyDecoratorAsyncDefault[I, T]: ...
626
+
627
+
628
+ @overload
629
+ def a_sync_cached_property( # type: ignore [misc]
630
+ func: AnyGetterFunction[I, T],
631
+ default: Literal["sync"],
632
+ **modifiers: Unpack[ModifierKwargs],
633
+ ) -> ASyncCachedPropertyDescriptorSyncDefault[I, T]: ...
634
+
635
+
636
+ @overload
637
+ def a_sync_cached_property( # type: ignore [misc]
638
+ func: AnyGetterFunction[I, T],
639
+ default: Literal["async"],
640
+ **modifiers: Unpack[ModifierKwargs],
641
+ ) -> ASyncCachedPropertyDescriptorAsyncDefault[I, T]: ...
642
+
643
+
644
+ @overload
645
+ def a_sync_cached_property( # type: ignore [misc]
646
+ func: AnyGetterFunction[I, T],
647
+ default: DefaultMode = config.DEFAULT_MODE,
648
+ **modifiers: Unpack[ModifierKwargs],
649
+ ) -> ASyncCachedPropertyDescriptor[I, T]: ...
650
+
651
+
652
+ def a_sync_cached_property( # type: ignore [misc]
653
+ func: Optional[AnyGetterFunction[I, T]] = None,
654
+ **modifiers: Unpack[ModifierKwargs],
655
+ ) -> Union[
656
+ ASyncCachedPropertyDescriptor[I, T],
657
+ ASyncCachedPropertyDescriptorSyncDefault[I, T],
658
+ ASyncCachedPropertyDescriptorAsyncDefault[I, T],
659
+ ASyncCachedPropertyDecorator[I, T],
660
+ ASyncCachedPropertyDecoratorSyncDefault[I, T],
661
+ ASyncCachedPropertyDecoratorAsyncDefault[I, T],
662
+ ]:
663
+ """Decorator for creating cached properties that can be accessed both synchronously and asynchronously.
664
+
665
+ Args:
666
+ func: The function to be wrapped.
667
+ **modifiers: Additional modifier arguments.
668
+
669
+ Returns:
670
+ A cached property descriptor that supports both sync and async access.
671
+ """
672
+ func, modifiers = _parse_args(func, <dict>modifiers)
673
+ cdef object descriptor_class
674
+ if (<dict>modifiers).get("default") == "sync":
675
+ descriptor_class = ASyncCachedPropertyDescriptorSyncDefault
676
+ elif (<dict>modifiers).get("default") == "async":
677
+ descriptor_class = ASyncCachedPropertyDescriptorAsyncDefault
678
+ else:
679
+ descriptor_class = ASyncCachedPropertyDescriptor
680
+ decorator = partial(descriptor_class, **modifiers)
681
+ return decorator if func is None else decorator(func)
682
+
683
+
684
+ class HiddenMethod(ASyncBoundMethodAsyncDefault[I, Tuple[()], T]):
685
+ """Represents a hidden method for asynchronous properties.
686
+
687
+ This class is used internally to manage hidden getter methods associated with a/sync properties.
688
+
689
+ Note:
690
+ You should never create these yourself. They are automatically generated by ez-a-sync internally.
691
+ """
692
+
693
+ def __init__(
694
+ self,
695
+ instance: I,
696
+ unbound: AnyFn[Concatenate[I, P], T],
697
+ async_def: bool,
698
+ field_name: str,
699
+ **modifiers: Unpack[ModifierKwargs],
700
+ ) -> None:
701
+ """Initializes the HiddenMethod.
702
+
703
+ Args:
704
+ instance: The instance to which the method is bound.
705
+ unbound: The unbound function to be wrapped.
706
+ async_def: Indicates if the method is asynchronous.
707
+ field_name: The name of the field associated with the method.
708
+ **modifiers: Additional modifier arguments.
709
+ """
710
+ # TODO: copy __init_subclass__ to this class and then use _ASyncBoundMethod.__init__ instead
711
+ ASyncBoundMethod.__init__(self, instance, unbound, async_def, **modifiers)
712
+ self.__name__ = field_name
713
+ """The name of the hidden method."""
714
+
715
+ def __repr__(_ASyncBoundMethod self) -> str:
716
+ """Returns a string representation of the HiddenMethod."""
717
+ instance = self.__c_self__()
718
+ instance_type = type(instance)
719
+ return "<{} for property {}.{}.{} bound to {}>".format(
720
+ self.__class__.__name__,
721
+ instance_type.__module__,
722
+ instance_type.__name__,
723
+ self.__name__[2:-2],
724
+ instance,
725
+ )
726
+
727
+ def __await__(_ASyncBoundMethod self) -> Generator[Any, None, T]:
728
+ """Returns an awaitable for the method."""
729
+ # NOTE: self(sync=False).__await__() would be cleaner but requires way more compute for no real gain
730
+ _logger_debug("awaiting %s", self)
731
+ return self.get_fn()(self.__c_self__(), sync=False).__await__()
732
+
733
+
734
+ class HiddenMethodDescriptor(ASyncMethodDescriptorAsyncDefault[I, Tuple[()], T]):
735
+ """Descriptor for hidden methods associated with asynchronous properties.
736
+
737
+ This class is used internally to manage hidden getter methods associated with a/sync properties.
738
+
739
+ Note:
740
+ You should never create these yourself. They are automatically generated by ez-a-sync internally.
741
+ """
742
+
743
+ def __init__(
744
+ self,
745
+ _fget: AnyFn[Concatenate[I, P], Awaitable[T]],
746
+ field_name: Optional[str] = None,
747
+ **modifiers: Unpack[ModifierKwargs],
748
+ ) -> None:
749
+ """
750
+ Initialize the HiddenMethodDescriptor.
751
+
752
+ Args:
753
+ _fget: The function to be wrapped.
754
+ field_name: Optional name for the field. If not provided, the function's name will be used.
755
+ **modifiers: Additional modifier arguments.
756
+
757
+ Raises:
758
+ ValueError: If _fget is not callable.
759
+ """
760
+ ASyncDescriptor.__init__(self, _fget, field_name, **modifiers)
761
+ if self.__doc__ is None:
762
+ self.__doc__ = f"A :class:`HiddenMethodDescriptor` for :meth:`{self.__wrapped__.__qualname__}`."
763
+ elif not self.__doc__:
764
+ self.__doc__ += f"A :class:`HiddenMethodDescriptor` for :meth:`{self.__wrapped__.__qualname__}`."
765
+ if self.__wrapped__.__doc__:
766
+ self.__doc__ += f"\n\nThe original docstring for :meth:`~{self.__wrapped__.__qualname__}` is shown below:\n\n{self.__wrapped__.__doc__}"
767
+
768
+ def __get__(_ModifiedMixin self, instance: I, owner: Type[I]) -> HiddenMethod[I, T]:
769
+ """Retrieves the hidden method for the property.
770
+
771
+ Args:
772
+ instance: The instance from which the method is accessed.
773
+ owner: The owner class of the method.
774
+
775
+ Returns:
776
+ The hidden method.
777
+ """
778
+ if instance is None:
779
+ return self
780
+
781
+ cdef _ASyncBoundMethod bound
782
+ cdef str field_name = self.field_name
783
+ bound = instance.__dict__.get(field_name)
784
+ if bound is None:
785
+ bound = HiddenMethod(
786
+ instance,
787
+ self.__wrapped__,
788
+ self.__is_async_def__,
789
+ field_name,
790
+ **self.modifiers._modifiers,
791
+ )
792
+ instance.__dict__[field_name] = bound
793
+ _logger_debug("new hidden method: %s", bound)
794
+ _update_cache_timer(field_name, instance, bound)
795
+ return bound
796
+
797
+
798
+ cdef object _parse_args(
799
+ func: Union[None, DefaultMode, AsyncGetterFunction[I, T]],
800
+ dict modifiers,
801
+ ):
802
+ """Parses the arguments for the property decorators.
803
+
804
+ Args:
805
+ func: The function to be wrapped.
806
+ modifiers: Additional modifier arguments.
807
+
808
+ Returns:
809
+ Tuple[Optional[AsyncGetterFunction[I, T]], ModifierKwargs] A tuple containing the parsed function and modifiers.
810
+ """
811
+ if func in ("sync", "async"):
812
+ modifiers["default"] = func
813
+ return None, modifiers
814
+ return func, modifiers
815
+
816
+
817
+ cdef inline void _import_TaskMapping():
818
+ global TaskMapping
819
+ from a_sync import TaskMapping