ez-a-sync 0.22.14__py3-none-any.whl → 0.22.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ez-a-sync might be problematic. Click here for more details.
- a_sync/ENVIRONMENT_VARIABLES.py +4 -3
- a_sync/__init__.py +30 -12
- a_sync/_smart.py +132 -28
- a_sync/_typing.py +56 -12
- a_sync/a_sync/__init__.py +35 -10
- a_sync/a_sync/_descriptor.py +74 -26
- a_sync/a_sync/_flags.py +14 -6
- a_sync/a_sync/_helpers.py +8 -7
- a_sync/a_sync/_kwargs.py +3 -2
- a_sync/a_sync/_meta.py +120 -28
- a_sync/a_sync/abstract.py +102 -28
- a_sync/a_sync/base.py +34 -16
- a_sync/a_sync/config.py +47 -13
- a_sync/a_sync/decorator.py +239 -117
- a_sync/a_sync/function.py +416 -146
- a_sync/a_sync/method.py +197 -59
- a_sync/a_sync/modifiers/__init__.py +47 -5
- a_sync/a_sync/modifiers/cache/__init__.py +46 -17
- a_sync/a_sync/modifiers/cache/memory.py +86 -20
- a_sync/a_sync/modifiers/limiter.py +52 -22
- a_sync/a_sync/modifiers/manager.py +98 -16
- a_sync/a_sync/modifiers/semaphores.py +48 -15
- a_sync/a_sync/property.py +383 -82
- a_sync/a_sync/singleton.py +1 -0
- a_sync/aliases.py +0 -1
- a_sync/asyncio/__init__.py +4 -1
- a_sync/asyncio/as_completed.py +177 -49
- a_sync/asyncio/create_task.py +31 -17
- a_sync/asyncio/gather.py +72 -52
- a_sync/asyncio/utils.py +3 -3
- a_sync/exceptions.py +78 -23
- a_sync/executor.py +118 -71
- a_sync/future.py +575 -158
- a_sync/iter.py +110 -50
- a_sync/primitives/__init__.py +14 -2
- a_sync/primitives/_debug.py +13 -13
- a_sync/primitives/_loggable.py +5 -4
- a_sync/primitives/locks/__init__.py +5 -2
- a_sync/primitives/locks/counter.py +38 -36
- a_sync/primitives/locks/event.py +21 -7
- a_sync/primitives/locks/prio_semaphore.py +182 -62
- a_sync/primitives/locks/semaphore.py +78 -77
- a_sync/primitives/queue.py +560 -58
- a_sync/sphinx/__init__.py +0 -1
- a_sync/sphinx/ext.py +160 -50
- a_sync/task.py +262 -97
- a_sync/utils/__init__.py +12 -6
- a_sync/utils/iterators.py +127 -43
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/METADATA +1 -1
- ez_a_sync-0.22.15.dist-info/RECORD +74 -0
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/WHEEL +1 -1
- tests/conftest.py +1 -2
- tests/executor.py +112 -9
- tests/fixtures.py +61 -32
- tests/test_abstract.py +7 -4
- tests/test_as_completed.py +54 -21
- tests/test_base.py +66 -17
- tests/test_cache.py +31 -15
- tests/test_decorator.py +54 -28
- tests/test_executor.py +8 -13
- tests/test_future.py +45 -8
- tests/test_gather.py +8 -2
- tests/test_helpers.py +2 -0
- tests/test_iter.py +55 -13
- tests/test_limiter.py +5 -3
- tests/test_meta.py +23 -9
- tests/test_modified.py +4 -1
- tests/test_semaphore.py +15 -8
- tests/test_singleton.py +15 -10
- tests/test_task.py +126 -28
- ez_a_sync-0.22.14.dist-info/RECORD +0 -74
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/top_level.txt +0 -0
a_sync/a_sync/property.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import functools
|
|
3
2
|
import logging
|
|
4
3
|
|
|
@@ -9,8 +8,15 @@ from a_sync import _smart, exceptions
|
|
|
9
8
|
from a_sync._typing import *
|
|
10
9
|
from a_sync.a_sync import _helpers, config
|
|
11
10
|
from a_sync.a_sync._descriptor import ASyncDescriptor
|
|
12
|
-
from a_sync.a_sync.function import
|
|
13
|
-
|
|
11
|
+
from a_sync.a_sync.function import (
|
|
12
|
+
ASyncFunction,
|
|
13
|
+
ASyncFunctionAsyncDefault,
|
|
14
|
+
ASyncFunctionSyncDefault,
|
|
15
|
+
)
|
|
16
|
+
from a_sync.a_sync.method import (
|
|
17
|
+
ASyncBoundMethodAsyncDefault,
|
|
18
|
+
ASyncMethodDescriptorAsyncDefault,
|
|
19
|
+
)
|
|
14
20
|
|
|
15
21
|
if TYPE_CHECKING:
|
|
16
22
|
from a_sync.task import TaskMapping
|
|
@@ -18,63 +24,169 @@ if TYPE_CHECKING:
|
|
|
18
24
|
|
|
19
25
|
logger = logging.getLogger(__name__)
|
|
20
26
|
|
|
27
|
+
|
|
21
28
|
class _ASyncPropertyDescriptorBase(ASyncDescriptor[I, Tuple[()], T]):
|
|
29
|
+
"""Base class for creating asynchronous properties.
|
|
30
|
+
|
|
31
|
+
This class provides the foundation for defining properties that can be accessed
|
|
32
|
+
both synchronously and asynchronously. It includes utility methods for common
|
|
33
|
+
operations such as `any`, `all`, `min`, `max`, and `sum`.
|
|
34
|
+
"""
|
|
35
|
+
|
|
22
36
|
any: ASyncFunction[AnyIterable[I], bool]
|
|
37
|
+
"""An ASyncFunction that checks if any result is truthy."""
|
|
38
|
+
|
|
23
39
|
all: ASyncFunction[AnyIterable[I], bool]
|
|
40
|
+
"""An ASyncFunction that checks if all results are truthy."""
|
|
41
|
+
|
|
24
42
|
min: ASyncFunction[AnyIterable[I], T]
|
|
43
|
+
"""An ASyncFunction that returns the minimum result."""
|
|
44
|
+
|
|
25
45
|
max: ASyncFunction[AnyIterable[I], T]
|
|
46
|
+
"""An ASyncFunction that returns the maximum result."""
|
|
47
|
+
|
|
26
48
|
sum: ASyncFunction[AnyIterable[I], T]
|
|
49
|
+
"""An ASyncFunction that returns the sum of results."""
|
|
50
|
+
|
|
51
|
+
hidden_method_descriptor: "HiddenMethodDescriptor[T]"
|
|
52
|
+
"""A descriptor for the hidden method."""
|
|
53
|
+
|
|
27
54
|
__wrapped__: Callable[[I], T]
|
|
55
|
+
"""The wrapped function or method."""
|
|
56
|
+
|
|
28
57
|
__slots__ = "hidden_method_name", "hidden_method_descriptor", "_fget"
|
|
58
|
+
|
|
29
59
|
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
_fget: AsyncGetterFunction[I, T],
|
|
60
|
+
self,
|
|
61
|
+
_fget: AsyncGetterFunction[I, T],
|
|
32
62
|
field_name: Optional[str] = None,
|
|
33
63
|
**modifiers: Unpack[ModifierKwargs],
|
|
34
64
|
) -> None:
|
|
65
|
+
"""Initializes the _ASyncPropertyDescriptorBase.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
_fget: The function to be wrapped.
|
|
69
|
+
field_name: Optional name for the field. If not provided, the function's name will be used.
|
|
70
|
+
**modifiers: Additional modifier arguments.
|
|
71
|
+
"""
|
|
35
72
|
super().__init__(_fget, field_name, **modifiers)
|
|
36
73
|
self.hidden_method_name = f"__{self.field_name}__"
|
|
37
74
|
hidden_modifiers = dict(self.modifiers)
|
|
38
75
|
hidden_modifiers["default"] = "async"
|
|
39
|
-
self.hidden_method_descriptor
|
|
76
|
+
self.hidden_method_descriptor = HiddenMethodDescriptor(
|
|
77
|
+
self.get, self.hidden_method_name, **hidden_modifiers
|
|
78
|
+
)
|
|
40
79
|
if asyncio.iscoroutinefunction(_fget):
|
|
41
80
|
self._fget = self.__wrapped__
|
|
42
81
|
else:
|
|
43
82
|
self._fget = _helpers._asyncify(self.__wrapped__, self.modifiers.executor)
|
|
83
|
+
|
|
44
84
|
@overload
|
|
45
|
-
def __get__(self, instance: None, owner: Type[I]) -> Self
|
|
85
|
+
def __get__(self, instance: None, owner: Type[I]) -> Self: ...
|
|
46
86
|
@overload
|
|
47
|
-
def __get__(self, instance: I, owner: Type[I]) -> Awaitable[T]
|
|
48
|
-
def __get__(
|
|
87
|
+
def __get__(self, instance: I, owner: Type[I]) -> Awaitable[T]: ...
|
|
88
|
+
def __get__(
|
|
89
|
+
self, instance: Optional[I], owner: Type[I]
|
|
90
|
+
) -> Union[Self, Awaitable[T]]:
|
|
91
|
+
"""Retrieves the property value, either synchronously or asynchronously.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
instance: The instance from which the property is accessed.
|
|
95
|
+
owner: The owner class of the property.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
The property value, either as an awaitable or directly.
|
|
99
|
+
"""
|
|
49
100
|
if instance is None:
|
|
50
101
|
return self
|
|
51
102
|
awaitable = super().__get__(instance, owner)
|
|
52
103
|
# if the user didn't specify a default behavior, we will defer to the instance
|
|
53
104
|
if _is_a_sync_instance(instance):
|
|
54
|
-
should_await =
|
|
105
|
+
should_await = (
|
|
106
|
+
self.default == "sync"
|
|
107
|
+
if self.default
|
|
108
|
+
else instance.__a_sync_instance_should_await__
|
|
109
|
+
)
|
|
55
110
|
else:
|
|
56
|
-
should_await =
|
|
111
|
+
should_await = (
|
|
112
|
+
self.default == "sync"
|
|
113
|
+
if self.default
|
|
114
|
+
else not asyncio.get_event_loop().is_running()
|
|
115
|
+
)
|
|
57
116
|
if should_await:
|
|
58
|
-
logger.debug(
|
|
117
|
+
logger.debug(
|
|
118
|
+
"awaiting awaitable for %s for instance: %s owner: %s",
|
|
119
|
+
awaitable,
|
|
120
|
+
self,
|
|
121
|
+
instance,
|
|
122
|
+
owner,
|
|
123
|
+
)
|
|
59
124
|
retval = _helpers._await(awaitable)
|
|
60
125
|
else:
|
|
61
126
|
retval = awaitable
|
|
62
|
-
logger.debug(
|
|
127
|
+
logger.debug(
|
|
128
|
+
"returning %s for %s for instance: %s owner: %s",
|
|
129
|
+
retval,
|
|
130
|
+
self,
|
|
131
|
+
instance,
|
|
132
|
+
owner,
|
|
133
|
+
)
|
|
63
134
|
return retval
|
|
135
|
+
|
|
64
136
|
async def get(self, instance: I, owner: Optional[Type[I]] = None) -> T:
|
|
137
|
+
"""Asynchronously retrieves the property value.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
instance: The instance from which the property is accessed.
|
|
141
|
+
owner: The owner class of the property.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
The property value.
|
|
145
|
+
"""
|
|
65
146
|
if instance is None:
|
|
66
147
|
raise ValueError(instance)
|
|
67
148
|
logger.debug("awaiting %s for instance %s", self, instance)
|
|
68
149
|
return await super().__get__(instance, owner)
|
|
69
|
-
|
|
150
|
+
|
|
151
|
+
def map(
|
|
152
|
+
self,
|
|
153
|
+
instances: AnyIterable[I],
|
|
154
|
+
owner: Optional[Type[I]] = None,
|
|
155
|
+
concurrency: Optional[int] = None,
|
|
156
|
+
name: str = "",
|
|
157
|
+
) -> "TaskMapping[I, T]":
|
|
158
|
+
"""Maps the property across multiple instances.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
instances: An iterable of instances.
|
|
162
|
+
owner: The owner class of the property.
|
|
163
|
+
concurrency: Optional concurrency limit.
|
|
164
|
+
name: Optional name for the task mapping.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
A TaskMapping object.
|
|
168
|
+
"""
|
|
70
169
|
from a_sync.task import TaskMapping
|
|
170
|
+
|
|
71
171
|
logger.debug("mapping %s to instances: %s owner: %s", self, instances, owner)
|
|
72
|
-
return TaskMapping(
|
|
172
|
+
return TaskMapping(
|
|
173
|
+
self,
|
|
174
|
+
instances,
|
|
175
|
+
owner=owner,
|
|
176
|
+
name=name or self.field_name,
|
|
177
|
+
concurrency=concurrency,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ASyncPropertyDescriptor(
|
|
182
|
+
_ASyncPropertyDescriptorBase[I, T], ap.base.AsyncPropertyDescriptor
|
|
183
|
+
):
|
|
184
|
+
"""Descriptor class for asynchronous properties."""
|
|
73
185
|
|
|
74
|
-
class ASyncPropertyDescriptor(_ASyncPropertyDescriptorBase[I, T], ap.base.AsyncPropertyDescriptor):
|
|
75
|
-
pass
|
|
76
186
|
|
|
77
|
-
class property(ASyncPropertyDescriptor[I, T])
|
|
187
|
+
class property(ASyncPropertyDescriptor[I, T]):
|
|
188
|
+
"""Descriptor for defining properties that can be accessed both synchronously and asynchronously."""
|
|
189
|
+
|
|
78
190
|
|
|
79
191
|
@final
|
|
80
192
|
class ASyncPropertyDescriptorSyncDefault(property[I, T]):
|
|
@@ -91,13 +203,24 @@ class ASyncPropertyDescriptorSyncDefault(property[I, T]):
|
|
|
91
203
|
min: ASyncFunctionSyncDefault[AnyIterable[I], T]
|
|
92
204
|
max: ASyncFunctionSyncDefault[AnyIterable[I], T]
|
|
93
205
|
sum: ASyncFunctionSyncDefault[AnyIterable[I], T]
|
|
206
|
+
|
|
94
207
|
@overload
|
|
95
|
-
def __get__(self, instance: None, owner: Type[I]) -> Self
|
|
208
|
+
def __get__(self, instance: None, owner: Type[I]) -> Self: ...
|
|
96
209
|
@overload
|
|
97
|
-
def __get__(self, instance: I, owner: Type[I]) -> T
|
|
210
|
+
def __get__(self, instance: I, owner: Type[I]) -> T: ...
|
|
98
211
|
def __get__(self, instance: Optional[I], owner: Type[I]) -> Union[Self, T]:
|
|
212
|
+
"""Retrieves the property value, either synchronously or asynchronously.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
instance: The instance from which the property is accessed.
|
|
216
|
+
owner: The owner class of the property.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
The property value, either as an awaitable or directly.
|
|
220
|
+
"""
|
|
99
221
|
return _ASyncPropertyDescriptorBase.__get__(self, instance, owner)
|
|
100
222
|
|
|
223
|
+
|
|
101
224
|
@final
|
|
102
225
|
class ASyncPropertyDescriptorAsyncDefault(property[I, T]):
|
|
103
226
|
"""
|
|
@@ -116,93 +239,118 @@ class ASyncPropertyDescriptorAsyncDefault(property[I, T]):
|
|
|
116
239
|
|
|
117
240
|
|
|
118
241
|
ASyncPropertyDecorator = Callable[[AnyGetterFunction[I, T]], property[I, T]]
|
|
119
|
-
ASyncPropertyDecoratorSyncDefault = Callable[
|
|
120
|
-
|
|
242
|
+
ASyncPropertyDecoratorSyncDefault = Callable[
|
|
243
|
+
[AnyGetterFunction[I, T]], ASyncPropertyDescriptorSyncDefault[I, T]
|
|
244
|
+
]
|
|
245
|
+
ASyncPropertyDecoratorAsyncDefault = Callable[
|
|
246
|
+
[AnyGetterFunction[I, T]], ASyncPropertyDescriptorAsyncDefault[I, T]
|
|
247
|
+
]
|
|
248
|
+
|
|
121
249
|
|
|
122
250
|
@overload
|
|
123
251
|
def a_sync_property( # type: ignore [misc]
|
|
124
252
|
func: Literal[None] = None,
|
|
125
253
|
**modifiers: Unpack[ModifierKwargs],
|
|
126
|
-
) -> ASyncPropertyDecorator[I, T]
|
|
254
|
+
) -> ASyncPropertyDecorator[I, T]: ...
|
|
255
|
+
|
|
127
256
|
|
|
128
257
|
@overload
|
|
129
258
|
def a_sync_property( # type: ignore [misc]
|
|
130
259
|
func: AnyGetterFunction[I, T],
|
|
131
260
|
**modifiers: Unpack[ModifierKwargs],
|
|
132
|
-
) -> ASyncPropertyDescriptor[I, T]
|
|
261
|
+
) -> ASyncPropertyDescriptor[I, T]: ...
|
|
262
|
+
|
|
133
263
|
|
|
134
264
|
@overload
|
|
135
265
|
def a_sync_property( # type: ignore [misc]
|
|
136
266
|
func: Literal[None],
|
|
137
267
|
default: Literal["sync"],
|
|
138
268
|
**modifiers: Unpack[ModifierKwargs],
|
|
139
|
-
) -> ASyncPropertyDecoratorSyncDefault[I, T]
|
|
269
|
+
) -> ASyncPropertyDecoratorSyncDefault[I, T]: ...
|
|
270
|
+
|
|
140
271
|
|
|
141
272
|
@overload
|
|
142
273
|
def a_sync_property( # type: ignore [misc]
|
|
143
274
|
func: Literal[None],
|
|
144
275
|
default: Literal["sync"],
|
|
145
276
|
**modifiers: Unpack[ModifierKwargs],
|
|
146
|
-
) -> ASyncPropertyDecoratorSyncDefault[I, T]
|
|
277
|
+
) -> ASyncPropertyDecoratorSyncDefault[I, T]: ...
|
|
278
|
+
|
|
147
279
|
|
|
148
280
|
@overload
|
|
149
281
|
def a_sync_property( # type: ignore [misc]
|
|
150
282
|
func: Literal[None],
|
|
151
283
|
default: Literal["async"],
|
|
152
284
|
**modifiers: Unpack[ModifierKwargs],
|
|
153
|
-
) -> ASyncPropertyDecoratorAsyncDefault[I, T]
|
|
285
|
+
) -> ASyncPropertyDecoratorAsyncDefault[I, T]: ...
|
|
286
|
+
|
|
154
287
|
|
|
155
288
|
@overload
|
|
156
289
|
def a_sync_property( # type: ignore [misc]
|
|
157
290
|
func: Literal[None],
|
|
158
291
|
default: DefaultMode = config.DEFAULT_MODE,
|
|
159
292
|
**modifiers: Unpack[ModifierKwargs],
|
|
160
|
-
) -> ASyncPropertyDecorator[I, T]
|
|
161
|
-
|
|
293
|
+
) -> ASyncPropertyDecorator[I, T]: ...
|
|
294
|
+
|
|
295
|
+
|
|
162
296
|
@overload
|
|
163
297
|
def a_sync_property( # type: ignore [misc]
|
|
164
298
|
default: Literal["sync"],
|
|
165
299
|
**modifiers: Unpack[ModifierKwargs],
|
|
166
|
-
) -> ASyncPropertyDecoratorSyncDefault[I, T]
|
|
167
|
-
|
|
300
|
+
) -> ASyncPropertyDecoratorSyncDefault[I, T]: ...
|
|
301
|
+
|
|
302
|
+
|
|
168
303
|
@overload
|
|
169
304
|
def a_sync_property( # type: ignore [misc]
|
|
170
305
|
default: Literal["async"],
|
|
171
306
|
**modifiers: Unpack[ModifierKwargs],
|
|
172
|
-
) -> ASyncPropertyDecoratorAsyncDefault[I, T]
|
|
173
|
-
|
|
307
|
+
) -> ASyncPropertyDecoratorAsyncDefault[I, T]: ...
|
|
308
|
+
|
|
309
|
+
|
|
174
310
|
@overload
|
|
175
311
|
def a_sync_property( # type: ignore [misc]
|
|
176
312
|
func: AnyGetterFunction[I, T],
|
|
177
313
|
default: Literal["sync"],
|
|
178
314
|
**modifiers: Unpack[ModifierKwargs],
|
|
179
|
-
) -> ASyncPropertyDescriptorSyncDefault[I, T]
|
|
180
|
-
|
|
315
|
+
) -> ASyncPropertyDescriptorSyncDefault[I, T]: ...
|
|
316
|
+
|
|
317
|
+
|
|
181
318
|
@overload
|
|
182
319
|
def a_sync_property( # type: ignore [misc]
|
|
183
320
|
func: AnyGetterFunction[I, T],
|
|
184
321
|
default: Literal["async"],
|
|
185
322
|
**modifiers: Unpack[ModifierKwargs],
|
|
186
|
-
) -> ASyncPropertyDescriptorAsyncDefault[I, T]
|
|
187
|
-
|
|
323
|
+
) -> ASyncPropertyDescriptorAsyncDefault[I, T]: ...
|
|
324
|
+
|
|
325
|
+
|
|
188
326
|
@overload
|
|
189
327
|
def a_sync_property( # type: ignore [misc]
|
|
190
328
|
func: AnyGetterFunction[I, T],
|
|
191
329
|
default: DefaultMode = config.DEFAULT_MODE,
|
|
192
330
|
**modifiers: Unpack[ModifierKwargs],
|
|
193
|
-
) -> ASyncPropertyDescriptor[I, T]
|
|
194
|
-
|
|
331
|
+
) -> ASyncPropertyDescriptor[I, T]: ...
|
|
332
|
+
|
|
333
|
+
|
|
195
334
|
def a_sync_property( # type: ignore [misc]
|
|
196
335
|
func: Union[AnyGetterFunction[I, T], DefaultMode] = None,
|
|
197
336
|
**modifiers: Unpack[ModifierKwargs],
|
|
198
337
|
) -> Union[
|
|
199
338
|
ASyncPropertyDescriptor[I, T],
|
|
200
|
-
ASyncPropertyDescriptorSyncDefault[I, T],
|
|
201
|
-
ASyncPropertyDescriptorAsyncDefault[I, T],
|
|
339
|
+
ASyncPropertyDescriptorSyncDefault[I, T],
|
|
340
|
+
ASyncPropertyDescriptorAsyncDefault[I, T],
|
|
202
341
|
ASyncPropertyDecorator[I, T],
|
|
203
342
|
ASyncPropertyDecoratorSyncDefault[I, T],
|
|
204
343
|
ASyncPropertyDecoratorAsyncDefault[I, T],
|
|
205
344
|
]:
|
|
345
|
+
"""Decorator for creating properties that can be accessed both synchronously and asynchronously.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
func: The function to be wrapped.
|
|
349
|
+
**modifiers: Additional modifier arguments.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
A property descriptor that supports both sync and async access.
|
|
353
|
+
"""
|
|
206
354
|
func, modifiers = _parse_args(func, modifiers)
|
|
207
355
|
if modifiers.get("default") == "sync":
|
|
208
356
|
descriptor_class = ASyncPropertyDescriptorSyncDefault
|
|
@@ -214,7 +362,9 @@ def a_sync_property( # type: ignore [misc]
|
|
|
214
362
|
return decorator if func is None else decorator(func)
|
|
215
363
|
|
|
216
364
|
|
|
217
|
-
class ASyncCachedPropertyDescriptor(
|
|
365
|
+
class ASyncCachedPropertyDescriptor(
|
|
366
|
+
_ASyncPropertyDescriptorBase[I, T], ap.cached.AsyncCachedPropertyDescriptor
|
|
367
|
+
):
|
|
218
368
|
"""
|
|
219
369
|
A descriptor class for dual-function sync/async cached properties.
|
|
220
370
|
|
|
@@ -223,21 +373,42 @@ class ASyncCachedPropertyDescriptor(_ASyncPropertyDescriptorBase[I, T], ap.cache
|
|
|
223
373
|
"""
|
|
224
374
|
|
|
225
375
|
__slots__ = "_fset", "_fdel", "__async_property__"
|
|
376
|
+
|
|
226
377
|
def __init__(
|
|
227
|
-
self,
|
|
228
|
-
_fget: AsyncGetterFunction[I, T],
|
|
229
|
-
_fset
|
|
230
|
-
_fdel
|
|
231
|
-
field_name=None,
|
|
378
|
+
self,
|
|
379
|
+
_fget: AsyncGetterFunction[I, T],
|
|
380
|
+
_fset=None,
|
|
381
|
+
_fdel=None,
|
|
382
|
+
field_name=None,
|
|
232
383
|
**modifiers: Unpack[ModifierKwargs],
|
|
233
384
|
) -> None:
|
|
385
|
+
"""Initializes the ASyncCachedPropertyDescriptor.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
_fget: The function to be wrapped.
|
|
389
|
+
_fset: Optional setter function for the property.
|
|
390
|
+
_fdel: Optional deleter function for the property.
|
|
391
|
+
field_name: Optional name for the field. If not provided, the function's name will be used.
|
|
392
|
+
**modifiers: Additional modifier arguments.
|
|
393
|
+
"""
|
|
234
394
|
super().__init__(_fget, field_name, **modifiers)
|
|
235
|
-
self._check_method_sync(_fset,
|
|
236
|
-
self._check_method_sync(_fdel, 'deleter')
|
|
395
|
+
self._check_method_sync(_fset, "setter")
|
|
237
396
|
self._fset = _fset
|
|
397
|
+
"""Optional setter function for the property."""
|
|
398
|
+
|
|
399
|
+
self._check_method_sync(_fdel, "deleter")
|
|
238
400
|
self._fdel = _fdel
|
|
401
|
+
"""Optional deleter function for the property."""
|
|
239
402
|
|
|
240
403
|
def get_lock(self, instance: I) -> "asyncio.Task[T]":
|
|
404
|
+
"""Retrieves the lock for the property.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
instance: The instance from which the property is accessed.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
An asyncio Task representing the lock.
|
|
411
|
+
"""
|
|
241
412
|
instance_state = self.get_instance_state(instance)
|
|
242
413
|
task = instance_state.lock[self.field_name]
|
|
243
414
|
if isinstance(task, asyncio.Lock):
|
|
@@ -245,11 +416,25 @@ class ASyncCachedPropertyDescriptor(_ASyncPropertyDescriptorBase[I, T], ap.cache
|
|
|
245
416
|
task = asyncio.create_task(self._fget(instance))
|
|
246
417
|
instance_state.lock[self.field_name] = task
|
|
247
418
|
return task
|
|
248
|
-
|
|
419
|
+
|
|
249
420
|
def pop_lock(self, instance: I) -> None:
|
|
421
|
+
"""Removes the lock for the property.
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
instance: The instance from which the property is accessed.
|
|
425
|
+
"""
|
|
250
426
|
self.get_instance_state(instance).lock.pop(self.field_name, None)
|
|
251
427
|
|
|
252
428
|
def get_loader(self, instance: I) -> Callable[[], T]:
|
|
429
|
+
"""Retrieves the loader function for the property.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
instance: The instance from which the property is accessed.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
A callable that loads the property value.
|
|
436
|
+
"""
|
|
437
|
+
|
|
253
438
|
@functools.wraps(self._fget)
|
|
254
439
|
async def load_value():
|
|
255
440
|
inner_task = self.get_lock(instance)
|
|
@@ -261,9 +446,13 @@ class ASyncCachedPropertyDescriptor(_ASyncPropertyDescriptorBase[I, T], ap.cache
|
|
|
261
446
|
self.__set__(instance, value)
|
|
262
447
|
self.pop_lock(instance)
|
|
263
448
|
return value
|
|
449
|
+
|
|
264
450
|
return load_value
|
|
265
|
-
|
|
266
|
-
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
class cached_property(ASyncCachedPropertyDescriptor[I, T]):
|
|
454
|
+
"""Descriptor for defining cached properties that can be accessed both synchronously and asynchronously."""
|
|
455
|
+
|
|
267
456
|
|
|
268
457
|
@final
|
|
269
458
|
class ASyncCachedPropertyDescriptorSyncDefault(cached_property[I, T]):
|
|
@@ -275,11 +464,21 @@ class ASyncCachedPropertyDescriptorSyncDefault(cached_property[I, T]):
|
|
|
275
464
|
"""
|
|
276
465
|
|
|
277
466
|
default: Literal["sync"]
|
|
467
|
+
|
|
278
468
|
@overload
|
|
279
|
-
def __get__(self, instance: None, owner: Type[I]) -> Self
|
|
469
|
+
def __get__(self, instance: None, owner: Type[I]) -> Self: ...
|
|
280
470
|
@overload
|
|
281
|
-
def __get__(self, instance: I, owner: Type[I]) -> T
|
|
471
|
+
def __get__(self, instance: I, owner: Type[I]) -> T: ...
|
|
282
472
|
def __get__(self, instance: Optional[I], owner: Type[I]) -> Union[Self, T]:
|
|
473
|
+
"""Retrieves the cached property value, either synchronously or asynchronously.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
instance: The instance from which the property is accessed.
|
|
477
|
+
owner: The owner class of the property.
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
The cached property value, either as an awaitable or directly.
|
|
481
|
+
"""
|
|
283
482
|
return _ASyncPropertyDescriptorBase.__get__(self, instance, owner)
|
|
284
483
|
|
|
285
484
|
|
|
@@ -294,126 +493,190 @@ class ASyncCachedPropertyDescriptorAsyncDefault(cached_property[I, T]):
|
|
|
294
493
|
|
|
295
494
|
default: Literal["async"]
|
|
296
495
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
496
|
+
|
|
497
|
+
ASyncCachedPropertyDecorator = Callable[
|
|
498
|
+
[AnyGetterFunction[I, T]], cached_property[I, T]
|
|
499
|
+
]
|
|
500
|
+
ASyncCachedPropertyDecoratorSyncDefault = Callable[
|
|
501
|
+
[AnyGetterFunction[I, T]], ASyncCachedPropertyDescriptorSyncDefault[I, T]
|
|
502
|
+
]
|
|
503
|
+
ASyncCachedPropertyDecoratorAsyncDefault = Callable[
|
|
504
|
+
[AnyGetterFunction[I, T]], ASyncCachedPropertyDescriptorAsyncDefault[I, T]
|
|
505
|
+
]
|
|
506
|
+
|
|
300
507
|
|
|
301
508
|
@overload
|
|
302
509
|
def a_sync_cached_property( # type: ignore [misc]
|
|
303
510
|
func: Literal[None] = None,
|
|
304
511
|
**modifiers: Unpack[ModifierKwargs],
|
|
305
|
-
) -> ASyncCachedPropertyDecorator[I, T]
|
|
512
|
+
) -> ASyncCachedPropertyDecorator[I, T]: ...
|
|
513
|
+
|
|
306
514
|
|
|
307
515
|
@overload
|
|
308
516
|
def a_sync_cached_property( # type: ignore [misc]
|
|
309
517
|
func: AnyGetterFunction[I, T],
|
|
310
518
|
**modifiers: Unpack[ModifierKwargs],
|
|
311
|
-
) -> ASyncCachedPropertyDescriptor[I, T]
|
|
519
|
+
) -> ASyncCachedPropertyDescriptor[I, T]: ...
|
|
520
|
+
|
|
312
521
|
|
|
313
522
|
@overload
|
|
314
523
|
def a_sync_cached_property( # type: ignore [misc]
|
|
315
524
|
func: Literal[None],
|
|
316
525
|
default: Literal["sync"],
|
|
317
526
|
**modifiers: Unpack[ModifierKwargs],
|
|
318
|
-
) -> ASyncCachedPropertyDecoratorSyncDefault[I, T]
|
|
527
|
+
) -> ASyncCachedPropertyDecoratorSyncDefault[I, T]: ...
|
|
528
|
+
|
|
319
529
|
|
|
320
530
|
@overload
|
|
321
531
|
def a_sync_cached_property( # type: ignore [misc]
|
|
322
532
|
func: Literal[None],
|
|
323
533
|
default: Literal["async"],
|
|
324
534
|
**modifiers: Unpack[ModifierKwargs],
|
|
325
|
-
) -> ASyncCachedPropertyDecoratorAsyncDefault[I, T]
|
|
535
|
+
) -> ASyncCachedPropertyDecoratorAsyncDefault[I, T]: ...
|
|
536
|
+
|
|
326
537
|
|
|
327
538
|
@overload
|
|
328
539
|
def a_sync_cached_property( # type: ignore [misc]
|
|
329
540
|
func: Literal[None],
|
|
330
541
|
default: DefaultMode,
|
|
331
542
|
**modifiers: Unpack[ModifierKwargs],
|
|
332
|
-
) -> ASyncCachedPropertyDecorator[I, T]
|
|
543
|
+
) -> ASyncCachedPropertyDecorator[I, T]: ...
|
|
544
|
+
|
|
333
545
|
|
|
334
546
|
@overload
|
|
335
547
|
def a_sync_cached_property( # type: ignore [misc]
|
|
336
548
|
default: Literal["sync"],
|
|
337
549
|
**modifiers: Unpack[ModifierKwargs],
|
|
338
|
-
) -> ASyncCachedPropertyDecoratorSyncDefault[I, T]
|
|
550
|
+
) -> ASyncCachedPropertyDecoratorSyncDefault[I, T]: ...
|
|
551
|
+
|
|
339
552
|
|
|
340
553
|
@overload
|
|
341
554
|
def a_sync_cached_property( # type: ignore [misc]
|
|
342
555
|
default: Literal["async"],
|
|
343
556
|
**modifiers: Unpack[ModifierKwargs],
|
|
344
|
-
) -> ASyncCachedPropertyDecoratorAsyncDefault[I, T]
|
|
345
|
-
|
|
557
|
+
) -> ASyncCachedPropertyDecoratorAsyncDefault[I, T]: ...
|
|
558
|
+
|
|
559
|
+
|
|
346
560
|
@overload
|
|
347
561
|
def a_sync_cached_property( # type: ignore [misc]
|
|
348
562
|
func: AnyGetterFunction[I, T],
|
|
349
563
|
default: Literal["sync"],
|
|
350
564
|
**modifiers: Unpack[ModifierKwargs],
|
|
351
|
-
) -> ASyncCachedPropertyDescriptorSyncDefault[I, T]
|
|
565
|
+
) -> ASyncCachedPropertyDescriptorSyncDefault[I, T]: ...
|
|
566
|
+
|
|
352
567
|
|
|
353
568
|
@overload
|
|
354
569
|
def a_sync_cached_property( # type: ignore [misc]
|
|
355
570
|
func: AnyGetterFunction[I, T],
|
|
356
571
|
default: Literal["async"],
|
|
357
572
|
**modifiers: Unpack[ModifierKwargs],
|
|
358
|
-
) -> ASyncCachedPropertyDescriptorAsyncDefault[I, T]
|
|
573
|
+
) -> ASyncCachedPropertyDescriptorAsyncDefault[I, T]: ...
|
|
574
|
+
|
|
359
575
|
|
|
360
576
|
@overload
|
|
361
577
|
def a_sync_cached_property( # type: ignore [misc]
|
|
362
578
|
func: AnyGetterFunction[I, T],
|
|
363
579
|
default: DefaultMode = config.DEFAULT_MODE,
|
|
364
580
|
**modifiers: Unpack[ModifierKwargs],
|
|
365
|
-
) -> ASyncCachedPropertyDescriptor[I, T]
|
|
366
|
-
|
|
581
|
+
) -> ASyncCachedPropertyDescriptor[I, T]: ...
|
|
582
|
+
|
|
583
|
+
|
|
367
584
|
def a_sync_cached_property( # type: ignore [misc]
|
|
368
585
|
func: Optional[AnyGetterFunction[I, T]] = None,
|
|
369
586
|
**modifiers: Unpack[ModifierKwargs],
|
|
370
587
|
) -> Union[
|
|
371
588
|
ASyncCachedPropertyDescriptor[I, T],
|
|
372
|
-
ASyncCachedPropertyDescriptorSyncDefault[I, T],
|
|
373
|
-
ASyncCachedPropertyDescriptorAsyncDefault[I, T],
|
|
589
|
+
ASyncCachedPropertyDescriptorSyncDefault[I, T],
|
|
590
|
+
ASyncCachedPropertyDescriptorAsyncDefault[I, T],
|
|
374
591
|
ASyncCachedPropertyDecorator[I, T],
|
|
375
592
|
ASyncCachedPropertyDecoratorSyncDefault[I, T],
|
|
376
593
|
ASyncCachedPropertyDecoratorAsyncDefault[I, T],
|
|
377
594
|
]:
|
|
595
|
+
"""Decorator for creating cached properties that can be accessed both synchronously and asynchronously.
|
|
596
|
+
|
|
597
|
+
Args:
|
|
598
|
+
func: The function to be wrapped.
|
|
599
|
+
**modifiers: Additional modifier arguments.
|
|
600
|
+
|
|
601
|
+
Returns:
|
|
602
|
+
A cached property descriptor that supports both sync and async access.
|
|
603
|
+
"""
|
|
378
604
|
func, modifiers = _parse_args(func, modifiers)
|
|
379
605
|
if modifiers.get("default") == "sync":
|
|
380
606
|
descriptor_class = ASyncCachedPropertyDescriptorSyncDefault
|
|
381
|
-
elif modifiers.get("default") == "
|
|
607
|
+
elif modifiers.get("default") == "async":
|
|
382
608
|
descriptor_class = ASyncCachedPropertyDescriptorAsyncDefault
|
|
383
609
|
else:
|
|
384
610
|
descriptor_class = ASyncCachedPropertyDescriptor
|
|
385
611
|
decorator = functools.partial(descriptor_class, **modifiers)
|
|
386
612
|
return decorator if func is None else decorator(func)
|
|
387
613
|
|
|
614
|
+
|
|
388
615
|
@final
|
|
389
616
|
class HiddenMethod(ASyncBoundMethodAsyncDefault[I, Tuple[()], T]):
|
|
617
|
+
"""Represents a hidden method for asynchronous properties.
|
|
618
|
+
|
|
619
|
+
This class is used internally to manage hidden methods associated with
|
|
620
|
+
asynchronous properties.
|
|
621
|
+
"""
|
|
622
|
+
|
|
390
623
|
def __init__(
|
|
391
|
-
self,
|
|
392
|
-
instance: I,
|
|
393
|
-
unbound: AnyFn[Concatenate[I, P], T],
|
|
624
|
+
self,
|
|
625
|
+
instance: I,
|
|
626
|
+
unbound: AnyFn[Concatenate[I, P], T],
|
|
394
627
|
async_def: bool,
|
|
395
628
|
field_name: str,
|
|
396
629
|
**modifiers: Unpack[ModifierKwargs],
|
|
397
630
|
) -> None:
|
|
631
|
+
"""Initializes the HiddenMethod.
|
|
632
|
+
|
|
633
|
+
Args:
|
|
634
|
+
instance: The instance to which the method is bound.
|
|
635
|
+
unbound: The unbound function to be wrapped.
|
|
636
|
+
async_def: Indicates if the method is asynchronous.
|
|
637
|
+
field_name: The name of the field associated with the method.
|
|
638
|
+
**modifiers: Additional modifier arguments.
|
|
639
|
+
"""
|
|
398
640
|
super().__init__(instance, unbound, async_def, **modifiers)
|
|
399
641
|
self.__name__ = field_name
|
|
642
|
+
"""The name of the hidden method."""
|
|
643
|
+
|
|
400
644
|
def __repr__(self) -> str:
|
|
645
|
+
"""Returns a string representation of the HiddenMethod."""
|
|
401
646
|
instance_type = type(self.__self__)
|
|
402
647
|
return f"<{self.__class__.__name__} for property {instance_type.__module__}.{instance_type.__name__}.{self.__name__[2:-2]} bound to {self.__self__}>"
|
|
648
|
+
|
|
403
649
|
def _should_await(self, kwargs: dict) -> bool:
|
|
650
|
+
"""Determines if the method should be awaited.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
kwargs: The keyword arguments passed to the method.
|
|
654
|
+
|
|
655
|
+
Returns:
|
|
656
|
+
A boolean indicating if the method should be awaited.
|
|
657
|
+
"""
|
|
404
658
|
try:
|
|
405
659
|
return self.__self__.__a_sync_should_await_from_kwargs__(kwargs)
|
|
406
660
|
except (AttributeError, exceptions.NoFlagsFound):
|
|
407
661
|
return False
|
|
662
|
+
|
|
408
663
|
def __await__(self) -> Generator[Any, None, T]:
|
|
664
|
+
"""Returns an awaitable for the method."""
|
|
409
665
|
return self(sync=False).__await__()
|
|
410
666
|
|
|
667
|
+
|
|
411
668
|
@final
|
|
412
669
|
class HiddenMethodDescriptor(ASyncMethodDescriptorAsyncDefault[I, Tuple[()], T]):
|
|
670
|
+
"""Descriptor for hidden methods associated with asynchronous properties.
|
|
671
|
+
|
|
672
|
+
This class is used internally to manage hidden methods associated with
|
|
673
|
+
asynchronous properties.
|
|
674
|
+
"""
|
|
675
|
+
|
|
413
676
|
def __init__(
|
|
414
|
-
self,
|
|
415
|
-
_fget: AnyFn[Concatenate[I, P], Awaitable[T]],
|
|
416
|
-
field_name: Optional[str] = None,
|
|
677
|
+
self,
|
|
678
|
+
_fget: AnyFn[Concatenate[I, P], Awaitable[T]],
|
|
679
|
+
field_name: Optional[str] = None,
|
|
417
680
|
**modifiers: Unpack[ModifierKwargs],
|
|
418
681
|
) -> None:
|
|
419
682
|
"""
|
|
@@ -434,30 +697,68 @@ class HiddenMethodDescriptor(ASyncMethodDescriptorAsyncDefault[I, Tuple[()], T])
|
|
|
434
697
|
self.__doc__ += f"A :class:`HiddenMethodDescriptor` for :meth:`{self.__wrapped__.__qualname__}`."
|
|
435
698
|
if self.__wrapped__.__doc__:
|
|
436
699
|
self.__doc__ += f"\n\nThe original docstring for :meth:`~{self.__wrapped__.__qualname__}` is shown below:\n\n{self.__wrapped__.__doc__}"
|
|
700
|
+
|
|
437
701
|
def __get__(self, instance: I, owner: Type[I]) -> HiddenMethod[I, T]:
|
|
702
|
+
"""Retrieves the hidden method for the property.
|
|
703
|
+
|
|
704
|
+
Args:
|
|
705
|
+
instance: The instance from which the method is accessed.
|
|
706
|
+
owner: The owner class of the method.
|
|
707
|
+
|
|
708
|
+
Returns:
|
|
709
|
+
The hidden method.
|
|
710
|
+
"""
|
|
438
711
|
if instance is None:
|
|
439
712
|
return self
|
|
440
713
|
try:
|
|
441
714
|
bound = instance.__dict__[self.field_name]
|
|
442
715
|
bound._cache_handle.cancel()
|
|
443
716
|
except KeyError:
|
|
444
|
-
bound = HiddenMethod(
|
|
717
|
+
bound = HiddenMethod(
|
|
718
|
+
instance,
|
|
719
|
+
self.__wrapped__,
|
|
720
|
+
self.__is_async_def__,
|
|
721
|
+
self.field_name,
|
|
722
|
+
**self.modifiers,
|
|
723
|
+
)
|
|
445
724
|
instance.__dict__[self.field_name] = bound
|
|
446
725
|
logger.debug("new hidden method: %s", bound)
|
|
447
726
|
bound._cache_handle = self._get_cache_handle(instance)
|
|
448
727
|
return bound
|
|
449
728
|
|
|
729
|
+
|
|
450
730
|
def _is_a_sync_instance(instance: object) -> bool:
|
|
731
|
+
"""Checks if an instance is an ASync instance.
|
|
732
|
+
|
|
733
|
+
Args:
|
|
734
|
+
instance: The instance to check.
|
|
735
|
+
|
|
736
|
+
Returns:
|
|
737
|
+
A boolean indicating if the instance is an ASync instance.
|
|
738
|
+
"""
|
|
451
739
|
try:
|
|
452
740
|
return instance.__is_a_sync_instance__ # type: ignore [attr-defined]
|
|
453
741
|
except AttributeError:
|
|
454
742
|
from a_sync.a_sync.abstract import ASyncABC
|
|
743
|
+
|
|
455
744
|
is_a_sync = isinstance(instance, ASyncABC)
|
|
456
745
|
instance.__is_a_sync_instance__ = is_a_sync
|
|
457
746
|
return is_a_sync
|
|
458
747
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
748
|
+
|
|
749
|
+
def _parse_args(
|
|
750
|
+
func: Union[None, DefaultMode, AsyncGetterFunction[I, T]], modifiers: ModifierKwargs
|
|
751
|
+
) -> Tuple[Optional[AsyncGetterFunction[I, T]], ModifierKwargs]:
|
|
752
|
+
"""Parses the arguments for the property decorators.
|
|
753
|
+
|
|
754
|
+
Args:
|
|
755
|
+
func: The function to be wrapped.
|
|
756
|
+
modifiers: Additional modifier arguments.
|
|
757
|
+
|
|
758
|
+
Returns:
|
|
759
|
+
A tuple containing the parsed function and modifiers.
|
|
760
|
+
"""
|
|
761
|
+
if func in ["sync", "async"]:
|
|
762
|
+
modifiers["default"] = func
|
|
462
763
|
func = None
|
|
463
764
|
return func, modifiers
|