ez-a-sync 0.22.15__py3-none-any.whl → 0.22.16__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 +34 -3
- a_sync/__init__.py +32 -9
- a_sync/_smart.py +105 -6
- a_sync/_typing.py +56 -3
- a_sync/a_sync/_descriptor.py +174 -12
- a_sync/a_sync/_flags.py +64 -3
- a_sync/a_sync/_helpers.py +40 -8
- a_sync/a_sync/_kwargs.py +30 -6
- a_sync/a_sync/_meta.py +35 -6
- a_sync/a_sync/abstract.py +57 -9
- a_sync/a_sync/config.py +44 -7
- a_sync/a_sync/decorator.py +217 -37
- a_sync/a_sync/function.py +339 -47
- a_sync/a_sync/method.py +241 -52
- a_sync/a_sync/modifiers/__init__.py +39 -1
- a_sync/a_sync/modifiers/cache/__init__.py +75 -5
- a_sync/a_sync/modifiers/cache/memory.py +50 -6
- a_sync/a_sync/modifiers/limiter.py +55 -6
- a_sync/a_sync/modifiers/manager.py +46 -2
- a_sync/a_sync/modifiers/semaphores.py +84 -11
- a_sync/a_sync/singleton.py +43 -19
- a_sync/asyncio/__init__.py +137 -1
- a_sync/asyncio/as_completed.py +44 -38
- a_sync/asyncio/create_task.py +46 -10
- a_sync/asyncio/gather.py +72 -25
- a_sync/exceptions.py +178 -11
- a_sync/executor.py +51 -3
- a_sync/future.py +671 -29
- a_sync/iter.py +64 -7
- a_sync/primitives/_debug.py +59 -5
- a_sync/primitives/_loggable.py +36 -6
- a_sync/primitives/locks/counter.py +74 -7
- a_sync/primitives/locks/prio_semaphore.py +87 -8
- a_sync/primitives/locks/semaphore.py +68 -20
- a_sync/primitives/queue.py +65 -26
- a_sync/task.py +51 -15
- a_sync/utils/iterators.py +52 -16
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/METADATA +1 -1
- ez_a_sync-0.22.16.dist-info/RECORD +74 -0
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/WHEEL +1 -1
- tests/executor.py +150 -12
- tests/test_abstract.py +15 -0
- tests/test_base.py +198 -2
- tests/test_executor.py +23 -0
- tests/test_singleton.py +13 -1
- tests/test_task.py +45 -17
- ez_a_sync-0.22.15.dist-info/RECORD +0 -74
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/top_level.txt +0 -0
a_sync/ENVIRONMENT_VARIABLES.py
CHANGED
|
@@ -4,10 +4,41 @@ envs = EnvVarFactory("EZASYNC")
|
|
|
4
4
|
|
|
5
5
|
# We have some envs here to help you debug your custom class implementations
|
|
6
6
|
|
|
7
|
-
# If you're only interested in debugging a specific class, set this to the class name
|
|
8
7
|
DEBUG_CLASS_NAME = envs.create_env("DEBUG_CLASS_NAME", str, default="", verbose=False)
|
|
8
|
+
"""str: The name of the class to debug.
|
|
9
|
+
|
|
10
|
+
If you're only interested in debugging a specific class, set this to the class name.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
To debug a class named `MyClass`, set the environment variable:
|
|
14
|
+
|
|
15
|
+
.. code-block:: bash
|
|
16
|
+
|
|
17
|
+
export EZASYNC_DEBUG_CLASS_NAME=MyClass
|
|
18
|
+
|
|
19
|
+
See Also:
|
|
20
|
+
:func:`DEBUG_MODE` for enabling debug mode on all classes.
|
|
21
|
+
"""
|
|
9
22
|
|
|
10
|
-
# Set this to enable debug mode on all classes
|
|
11
23
|
DEBUG_MODE = envs.create_env(
|
|
12
|
-
"DEBUG_MODE", bool, default=DEBUG_CLASS_NAME, verbose=False
|
|
24
|
+
"DEBUG_MODE", bool, default=bool(DEBUG_CLASS_NAME), verbose=False
|
|
13
25
|
)
|
|
26
|
+
"""bool: Enables debug mode on all classes.
|
|
27
|
+
|
|
28
|
+
Set this environment variable to `True` to enable debug mode on all classes.
|
|
29
|
+
If `DEBUG_CLASS_NAME` is set to a truthy value other than an empty string,
|
|
30
|
+
`DEBUG_MODE` will default to `True`.
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
To enable debug mode globally, set the environment variable:
|
|
34
|
+
|
|
35
|
+
.. code-block:: bash
|
|
36
|
+
|
|
37
|
+
export EZASYNC_DEBUG_MODE=True
|
|
38
|
+
|
|
39
|
+
If you have set `DEBUG_CLASS_NAME` to a specific class, `DEBUG_MODE` will
|
|
40
|
+
automatically be `True` unless `DEBUG_CLASS_NAME` is an empty string.
|
|
41
|
+
|
|
42
|
+
See Also:
|
|
43
|
+
:func:`DEBUG_CLASS_NAME` for debugging a specific class.
|
|
44
|
+
"""
|
a_sync/__init__.py
CHANGED
|
@@ -8,17 +8,40 @@ that can operate in both synchronous and asynchronous contexts. Additionally, it
|
|
|
8
8
|
such as queues and locks, with extra functionality.
|
|
9
9
|
|
|
10
10
|
Modules and components included:
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- `
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
11
|
+
- :mod:`~aliases`, :mod:`~exceptions`, :mod:`~iter`, :mod:`~task`: Core modules of the library.
|
|
12
|
+
- :class:`~ASyncGenericBase`, :class:`~ASyncGenericSingleton`, :func:`~a_sync`: Base classes and decorators for dual-context execution.
|
|
13
|
+
- :class:`~ASyncCachedPropertyDescriptor`, :class:`~ASyncPropertyDescriptor`, `cached_property`, `property`: Property descriptors for async properties.
|
|
14
|
+
- :func:`~as_completed`, :func:`~create_task`, :func:`~gather`: Enhanced asyncio functions.
|
|
15
|
+
- Executors: :class:`~AsyncThreadPoolExecutor`, :class:`~AsyncProcessPoolExecutor`, :class:`~PruningThreadPoolExecutor` for async execution.
|
|
16
|
+
- Iterators: :class:`~ASyncFilter`, :class:`~ASyncSorter`, :class:`~ASyncIterable`, :class:`~ASyncIterator` for async iteration.
|
|
17
|
+
- Utilities: :func:`~all`, :func:`~any`, :func:`~as_yielded`, :func:`~exhaust_iterator`, :func:`~exhaust_iterators` for async utilities.
|
|
18
|
+
- :func:`~apply_semaphore`: Function to apply semaphores to coroutines.
|
|
19
19
|
|
|
20
20
|
Alias for backward compatibility:
|
|
21
|
-
-
|
|
21
|
+
- :class:`~ASyncBase` is an alias for :class:`~ASyncGenericBase`, which will be removed eventually, probably in version 0.1.0.
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
Using the `@a_sync` decorator:
|
|
25
|
+
>>> from a_sync import a_sync
|
|
26
|
+
>>> @a_sync
|
|
27
|
+
... async def my_function():
|
|
28
|
+
... return "Hello, World!"
|
|
29
|
+
>>> result = await my_function()
|
|
30
|
+
>>> print(result)
|
|
31
|
+
|
|
32
|
+
Using `ASyncGenericBase` for dual-context classes:
|
|
33
|
+
>>> from a_sync import ASyncGenericBase
|
|
34
|
+
>>> class MyClass(ASyncGenericBase):
|
|
35
|
+
... async def my_method(self):
|
|
36
|
+
... return "Hello from MyClass"
|
|
37
|
+
>>> obj = MyClass()
|
|
38
|
+
>>> result = await obj.my_method()
|
|
39
|
+
>>> print(result)
|
|
40
|
+
|
|
41
|
+
See Also:
|
|
42
|
+
- :mod:`a_sync.a_sync`: Contains the core classes and decorators.
|
|
43
|
+
- :mod:`a_sync.asyncio`: Provides enhanced asyncio functions.
|
|
44
|
+
- :mod:`a_sync.primitives`: Includes modified versions of standard asyncio primitives.
|
|
22
45
|
"""
|
|
23
46
|
|
|
24
47
|
from a_sync import aliases, exceptions, iter, task
|
a_sync/_smart.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module defines smart future and task utilities for the a_sync library.
|
|
3
3
|
These utilities provide enhanced functionality for managing asynchronous tasks and futures,
|
|
4
|
-
including
|
|
4
|
+
including a custom task factory for creating :class:`~SmartTask` instances and a shielding mechanism
|
|
5
|
+
to protect tasks from cancellation.
|
|
5
6
|
"""
|
|
6
7
|
|
|
7
8
|
import asyncio
|
|
@@ -37,6 +38,27 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
37
38
|
def __await__(self: Union["SmartFuture", "SmartTask"]) -> Generator[Any, None, T]:
|
|
38
39
|
"""
|
|
39
40
|
Await the smart future or task, handling waiters and logging.
|
|
41
|
+
|
|
42
|
+
Yields:
|
|
43
|
+
The result of the future or task.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
RuntimeError: If await wasn't used with future.
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
Awaiting a SmartFuture:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
future = SmartFuture()
|
|
53
|
+
result = await future
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Awaiting a SmartTask:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
task = SmartTask(coro=my_coroutine())
|
|
60
|
+
result = await task
|
|
61
|
+
```
|
|
40
62
|
"""
|
|
41
63
|
if self.done():
|
|
42
64
|
return self.result() # May raise too.
|
|
@@ -54,6 +76,12 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
54
76
|
# NOTE: we check .done() because the callback may not have ran yet and its very lightweight
|
|
55
77
|
"""
|
|
56
78
|
Get the number of waiters currently awaiting the future or task.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
```python
|
|
82
|
+
future = SmartFuture()
|
|
83
|
+
print(future.num_waiters)
|
|
84
|
+
```
|
|
57
85
|
"""
|
|
58
86
|
if self.done():
|
|
59
87
|
# if there are any waiters left, there won't be once the event loop runs once
|
|
@@ -67,6 +95,9 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
67
95
|
Callback to clean up waiters when a waiter task is done.
|
|
68
96
|
|
|
69
97
|
Removes the waiter from _waiters, and _queue._futs if applicable
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
waiter: The waiter task to clean up.
|
|
70
101
|
"""
|
|
71
102
|
if not self.done():
|
|
72
103
|
self._waiters.remove(waiter)
|
|
@@ -84,8 +115,16 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
84
115
|
"""
|
|
85
116
|
A smart future that tracks waiters and integrates with a smart processing queue.
|
|
86
117
|
|
|
87
|
-
Inherits from both _SmartFutureMixin and asyncio.Future
|
|
118
|
+
Inherits from both :class:`_SmartFutureMixin` and :class:`asyncio.Future`, providing additional functionality
|
|
88
119
|
for tracking waiters and integrating with a smart processing queue.
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
Creating and awaiting a SmartFuture:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
future = SmartFuture()
|
|
126
|
+
await future
|
|
127
|
+
```
|
|
89
128
|
"""
|
|
90
129
|
|
|
91
130
|
_queue = None
|
|
@@ -105,6 +144,11 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
105
144
|
queue: Optional; a smart processing queue.
|
|
106
145
|
key: Optional; a key identifying the future.
|
|
107
146
|
loop: Optional; the event loop.
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
```python
|
|
150
|
+
future = SmartFuture(queue=my_queue, key=my_key)
|
|
151
|
+
```
|
|
108
152
|
"""
|
|
109
153
|
super().__init__(loop=loop)
|
|
110
154
|
if queue:
|
|
@@ -125,8 +169,12 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
125
169
|
Args:
|
|
126
170
|
other: Another SmartFuture to compare with.
|
|
127
171
|
|
|
128
|
-
|
|
129
|
-
|
|
172
|
+
Example:
|
|
173
|
+
```python
|
|
174
|
+
future1 = SmartFuture()
|
|
175
|
+
future2 = SmartFuture()
|
|
176
|
+
print(future1 < future2)
|
|
177
|
+
```
|
|
130
178
|
"""
|
|
131
179
|
return self.num_waiters > other.num_waiters
|
|
132
180
|
|
|
@@ -138,7 +186,7 @@ def create_future(
|
|
|
138
186
|
loop: Optional[asyncio.AbstractEventLoop] = None,
|
|
139
187
|
) -> SmartFuture[V]:
|
|
140
188
|
"""
|
|
141
|
-
Create a SmartFuture instance.
|
|
189
|
+
Create a :class:`~SmartFuture` instance.
|
|
142
190
|
|
|
143
191
|
Args:
|
|
144
192
|
queue: Optional; a smart processing queue.
|
|
@@ -147,6 +195,13 @@ def create_future(
|
|
|
147
195
|
|
|
148
196
|
Returns:
|
|
149
197
|
A SmartFuture instance.
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
Creating a SmartFuture using the factory function:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
future = create_future(queue=my_queue, key=my_key)
|
|
204
|
+
```
|
|
150
205
|
"""
|
|
151
206
|
return SmartFuture(queue=queue, key=key, loop=loop or asyncio.get_event_loop())
|
|
152
207
|
|
|
@@ -155,8 +210,16 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
|
|
|
155
210
|
"""
|
|
156
211
|
A smart task that tracks waiters and integrates with a smart processing queue.
|
|
157
212
|
|
|
158
|
-
Inherits from both _SmartFutureMixin and asyncio.Task
|
|
213
|
+
Inherits from both :class:`_SmartFutureMixin` and :class:`asyncio.Task`, providing additional functionality
|
|
159
214
|
for tracking waiters and integrating with a smart processing queue.
|
|
215
|
+
|
|
216
|
+
Example:
|
|
217
|
+
Creating and awaiting a SmartTask:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
task = SmartTask(coro=my_coroutine())
|
|
221
|
+
await task
|
|
222
|
+
```
|
|
160
223
|
"""
|
|
161
224
|
|
|
162
225
|
def __init__(
|
|
@@ -173,6 +236,11 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
|
|
|
173
236
|
coro: The coroutine to run in the task.
|
|
174
237
|
loop: Optional; the event loop.
|
|
175
238
|
name: Optional; the name of the task.
|
|
239
|
+
|
|
240
|
+
Example:
|
|
241
|
+
```python
|
|
242
|
+
task = SmartTask(coro=my_coroutine(), name="my_task")
|
|
243
|
+
```
|
|
176
244
|
"""
|
|
177
245
|
super().__init__(coro, loop=loop, name=name)
|
|
178
246
|
self._waiters: Set["asyncio.Task[T]"] = set()
|
|
@@ -193,6 +261,17 @@ def smart_task_factory(
|
|
|
193
261
|
|
|
194
262
|
Returns:
|
|
195
263
|
A SmartTask instance running the provided coroutine.
|
|
264
|
+
|
|
265
|
+
Example:
|
|
266
|
+
Using the smart task factory to create a SmartTask:
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
loop = asyncio.get_event_loop()
|
|
270
|
+
task = smart_task_factory(loop, my_coroutine())
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
See Also:
|
|
274
|
+
- :func:`set_smart_task_factory`
|
|
196
275
|
"""
|
|
197
276
|
return SmartTask(coro, loop=loop)
|
|
198
277
|
|
|
@@ -203,6 +282,16 @@ def set_smart_task_factory(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
|
203
282
|
|
|
204
283
|
Args:
|
|
205
284
|
loop: Optional; the event loop. If None, the current event loop is used.
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
Setting the smart task factory for the current event loop:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
set_smart_task_factory()
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
See Also:
|
|
294
|
+
- :func:`smart_task_factory`
|
|
206
295
|
"""
|
|
207
296
|
if loop is None:
|
|
208
297
|
loop = a_sync.asyncio.get_event_loop()
|
|
@@ -241,6 +330,16 @@ def shield(
|
|
|
241
330
|
Args:
|
|
242
331
|
arg: The awaitable to shield from cancellation.
|
|
243
332
|
loop: Optional; the event loop. Deprecated since Python 3.8.
|
|
333
|
+
|
|
334
|
+
Example:
|
|
335
|
+
Using shield to protect a coroutine from cancellation:
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
result = await shield(my_coroutine())
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
See Also:
|
|
342
|
+
- :func:`asyncio.shield`
|
|
244
343
|
"""
|
|
245
344
|
if loop is not None:
|
|
246
345
|
warnings.warn(
|
a_sync/_typing.py
CHANGED
|
@@ -1,7 +1,60 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This module provides type definitions and type-related utilities for the a_sync library.
|
|
3
|
-
|
|
4
|
-
to enhance type checking and provide better IDE support.
|
|
2
|
+
This module provides type definitions and type-related utilities for the `a_sync` library.
|
|
3
|
+
|
|
4
|
+
It includes various type aliases and protocols used throughout the library to enhance type checking and provide better IDE support.
|
|
5
|
+
|
|
6
|
+
Examples:
|
|
7
|
+
The following examples demonstrate how to use some of the type aliases and protocols defined in this module.
|
|
8
|
+
|
|
9
|
+
Example of a function that can return either an awaitable or a direct value:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from a_sync._typing import MaybeAwaitable
|
|
13
|
+
from typing import Awaitable
|
|
14
|
+
|
|
15
|
+
async def process_data(data: MaybeAwaitable[int]) -> int:
|
|
16
|
+
if isinstance(data, Awaitable):
|
|
17
|
+
return await data
|
|
18
|
+
return data
|
|
19
|
+
|
|
20
|
+
# Usage
|
|
21
|
+
import asyncio
|
|
22
|
+
|
|
23
|
+
async def main():
|
|
24
|
+
result = await process_data(asyncio.sleep(1, result=42))
|
|
25
|
+
print(result) # Output: 42
|
|
26
|
+
|
|
27
|
+
result = await process_data(42)
|
|
28
|
+
print(result) # Output: 42
|
|
29
|
+
|
|
30
|
+
asyncio.run(main())
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Example of defining a coroutine function type:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from a_sync._typing import CoroFn
|
|
37
|
+
|
|
38
|
+
async def async_function(x: int) -> str:
|
|
39
|
+
return str(x)
|
|
40
|
+
|
|
41
|
+
coro_fn: CoroFn[[int], str] = async_function
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Example of defining a synchronous function type:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from a_sync._typing import SyncFn
|
|
48
|
+
|
|
49
|
+
def sync_function(x: int) -> str:
|
|
50
|
+
return str(x)
|
|
51
|
+
|
|
52
|
+
sync_fn: SyncFn[[int], str] = sync_function
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See Also:
|
|
56
|
+
- :mod:`typing`
|
|
57
|
+
- :mod:`asyncio`
|
|
5
58
|
"""
|
|
6
59
|
|
|
7
60
|
import asyncio
|
a_sync/a_sync/_descriptor.py
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This module contains the ASyncDescriptor class, which is used to create sync/async methods
|
|
2
|
+
This module contains the :class:`ASyncDescriptor` class, which is used to create dual-function sync/async methods
|
|
3
3
|
and properties.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The :class:`ASyncDescriptor` class provides functionality for mapping operations across multiple instances
|
|
6
|
+
and includes utility methods for common operations such as checking if all or any results are truthy,
|
|
7
|
+
and finding the minimum, maximum, or sum of results of the method or property mapped across multiple instances.
|
|
8
|
+
|
|
9
|
+
See Also:
|
|
10
|
+
- :class:`~a_sync.a_sync.function.ASyncFunction`
|
|
11
|
+
- :class:`~a_sync.a_sync.method.ASyncMethodDescriptor`
|
|
6
12
|
"""
|
|
7
13
|
|
|
8
14
|
import functools
|
|
@@ -23,6 +29,27 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
23
29
|
and includes utility methods for common operations such as checking if all or any
|
|
24
30
|
results are truthy, and finding the minimum, maximum, or sum of results of the method
|
|
25
31
|
or property mapped across multiple instances.
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
To create a dual-function method or property, subclass :class:`ASyncDescriptor` and implement
|
|
35
|
+
the desired functionality. You can then use the provided utility methods to perform operations
|
|
36
|
+
across multiple instances.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
class MyDescriptor(ASyncDescriptor):
|
|
40
|
+
def __init__(self, func):
|
|
41
|
+
super().__init__(func)
|
|
42
|
+
|
|
43
|
+
class MyClass:
|
|
44
|
+
my_method = MyDescriptor(lambda x: x * 2)
|
|
45
|
+
|
|
46
|
+
instance = MyClass()
|
|
47
|
+
result = instance.my_method.map([1, 2, 3])
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
See Also:
|
|
51
|
+
- :class:`~a_sync.a_sync.function.ASyncFunction`
|
|
52
|
+
- :class:`~a_sync.a_sync.method.ASyncMethodDescriptor`
|
|
26
53
|
"""
|
|
27
54
|
|
|
28
55
|
__wrapped__: AnyFn[Concatenate[I, P], T]
|
|
@@ -37,7 +64,7 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
37
64
|
**modifiers: ModifierKwargs,
|
|
38
65
|
) -> None:
|
|
39
66
|
"""
|
|
40
|
-
Initialize the
|
|
67
|
+
Initialize the :class:`ASyncDescriptor`.
|
|
41
68
|
|
|
42
69
|
Args:
|
|
43
70
|
_fget: The function to be wrapped.
|
|
@@ -61,7 +88,7 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
61
88
|
self.__wrapped__ = _fget
|
|
62
89
|
|
|
63
90
|
self.field_name = field_name or _fget.__name__
|
|
64
|
-
"""The name of the field the
|
|
91
|
+
"""The name of the field the :class:`ASyncDescriptor` is bound to."""
|
|
65
92
|
|
|
66
93
|
functools.update_wrapper(self, self.__wrapped__)
|
|
67
94
|
|
|
@@ -70,7 +97,7 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
70
97
|
|
|
71
98
|
def __set_name__(self, owner, name):
|
|
72
99
|
"""
|
|
73
|
-
Set the field name when the
|
|
100
|
+
Set the field name when the :class:`ASyncDescriptor` is assigned to a class.
|
|
74
101
|
|
|
75
102
|
Args:
|
|
76
103
|
owner: The class owning this descriptor.
|
|
@@ -82,14 +109,25 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
82
109
|
self, *instances: AnyIterable[I], **bound_method_kwargs: P.kwargs
|
|
83
110
|
) -> "TaskMapping[I, T]":
|
|
84
111
|
"""
|
|
85
|
-
Create a TaskMapping for the given instances.
|
|
112
|
+
Create a :class:`TaskMapping` for the given instances.
|
|
86
113
|
|
|
87
114
|
Args:
|
|
88
115
|
*instances: Iterable of instances to map over.
|
|
89
116
|
**bound_method_kwargs: Additional keyword arguments for the bound method.
|
|
90
117
|
|
|
91
118
|
Returns:
|
|
92
|
-
A TaskMapping object.
|
|
119
|
+
A :class:`TaskMapping` object.
|
|
120
|
+
|
|
121
|
+
Examples:
|
|
122
|
+
class MyDescriptor(ASyncDescriptor):
|
|
123
|
+
def __init__(self, func):
|
|
124
|
+
super().__init__(func)
|
|
125
|
+
|
|
126
|
+
class MyClass:
|
|
127
|
+
my_method = MyDescriptor(lambda x: x * 2)
|
|
128
|
+
|
|
129
|
+
instance = MyClass()
|
|
130
|
+
result = instance.my_method.map([1, 2, 3])
|
|
93
131
|
"""
|
|
94
132
|
from a_sync.task import TaskMapping
|
|
95
133
|
|
|
@@ -101,7 +139,18 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
101
139
|
Create an :class:`~ASyncFunction` that checks if all results are truthy.
|
|
102
140
|
|
|
103
141
|
Returns:
|
|
104
|
-
An ASyncFunction object.
|
|
142
|
+
An :class:`ASyncFunction` object.
|
|
143
|
+
|
|
144
|
+
Examples:
|
|
145
|
+
class MyDescriptor(ASyncDescriptor):
|
|
146
|
+
def __init__(self, func):
|
|
147
|
+
super().__init__(func)
|
|
148
|
+
|
|
149
|
+
class MyClass:
|
|
150
|
+
my_method = MyDescriptor(lambda x: x > 0)
|
|
151
|
+
|
|
152
|
+
instance = MyClass()
|
|
153
|
+
result = await instance.my_method.all([1, 2, 3])
|
|
105
154
|
"""
|
|
106
155
|
return decorator.a_sync(default=self.default)(self._all)
|
|
107
156
|
|
|
@@ -111,7 +160,18 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
111
160
|
Create an :class:`~ASyncFunction` that checks if any result is truthy.
|
|
112
161
|
|
|
113
162
|
Returns:
|
|
114
|
-
An ASyncFunction object.
|
|
163
|
+
An :class:`ASyncFunction` object.
|
|
164
|
+
|
|
165
|
+
Examples:
|
|
166
|
+
class MyDescriptor(ASyncDescriptor):
|
|
167
|
+
def __init__(self, func):
|
|
168
|
+
super().__init__(func)
|
|
169
|
+
|
|
170
|
+
class MyClass:
|
|
171
|
+
my_method = MyDescriptor(lambda x: x > 0)
|
|
172
|
+
|
|
173
|
+
instance = MyClass()
|
|
174
|
+
result = await instance.my_method.any([-1, 0, 1])
|
|
115
175
|
"""
|
|
116
176
|
return decorator.a_sync(default=self.default)(self._any)
|
|
117
177
|
|
|
@@ -121,7 +181,20 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
121
181
|
Create an :class:`~ASyncFunction` that returns the minimum result.
|
|
122
182
|
|
|
123
183
|
Returns:
|
|
124
|
-
An ASyncFunction object.
|
|
184
|
+
An :class:`ASyncFunction` object.
|
|
185
|
+
|
|
186
|
+
Examples:
|
|
187
|
+
```python
|
|
188
|
+
class MyDescriptor(ASyncDescriptor):
|
|
189
|
+
def __init__(self, func):
|
|
190
|
+
super().__init__(func)
|
|
191
|
+
|
|
192
|
+
class MyClass:
|
|
193
|
+
my_method = MyDescriptor(lambda x: x)
|
|
194
|
+
|
|
195
|
+
instance = MyClass()
|
|
196
|
+
result = await instance.my_method.min([3, 1, 2])
|
|
197
|
+
```
|
|
125
198
|
"""
|
|
126
199
|
return decorator.a_sync(default=self.default)(self._min)
|
|
127
200
|
|
|
@@ -131,7 +204,18 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
131
204
|
Create an :class:`~ASyncFunction` that returns the maximum result.
|
|
132
205
|
|
|
133
206
|
Returns:
|
|
134
|
-
An ASyncFunction object.
|
|
207
|
+
An :class:`ASyncFunction` object.
|
|
208
|
+
|
|
209
|
+
Examples:
|
|
210
|
+
class MyDescriptor(ASyncDescriptor):
|
|
211
|
+
def __init__(self, func):
|
|
212
|
+
super().__init__(func)
|
|
213
|
+
|
|
214
|
+
class MyClass:
|
|
215
|
+
my_method = MyDescriptor(lambda x: x)
|
|
216
|
+
|
|
217
|
+
instance = MyClass()
|
|
218
|
+
result = await instance.my_method.max([3, 1, 2])
|
|
135
219
|
"""
|
|
136
220
|
return decorator.a_sync(default=self.default)(self._max)
|
|
137
221
|
|
|
@@ -141,7 +225,20 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
141
225
|
Create an :class:`~ASyncFunction` that returns the sum of results.
|
|
142
226
|
|
|
143
227
|
Returns:
|
|
144
|
-
An ASyncFunction object.
|
|
228
|
+
An :class:`ASyncFunction` object.
|
|
229
|
+
|
|
230
|
+
Examples:
|
|
231
|
+
```python
|
|
232
|
+
class MyDescriptor(ASyncDescriptor):
|
|
233
|
+
def __init__(self, func):
|
|
234
|
+
super().__init__(func)
|
|
235
|
+
|
|
236
|
+
class MyClass:
|
|
237
|
+
my_method = MyDescriptor(lambda x: x)
|
|
238
|
+
|
|
239
|
+
instance = MyClass()
|
|
240
|
+
result = await instance.my_method.sum([1, 2, 3])
|
|
241
|
+
```
|
|
145
242
|
"""
|
|
146
243
|
return decorator.a_sync(default=self.default)(self._sum)
|
|
147
244
|
|
|
@@ -163,6 +260,19 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
163
260
|
|
|
164
261
|
Returns:
|
|
165
262
|
A boolean indicating if all results are truthy.
|
|
263
|
+
|
|
264
|
+
Examples:
|
|
265
|
+
```python
|
|
266
|
+
class MyDescriptor(ASyncDescriptor):
|
|
267
|
+
def __init__(self, func):
|
|
268
|
+
super().__init__(func)
|
|
269
|
+
|
|
270
|
+
class MyClass:
|
|
271
|
+
my_method = MyDescriptor(lambda x: x > 0)
|
|
272
|
+
|
|
273
|
+
instance = MyClass()
|
|
274
|
+
result = await instance.my_method._all([1, 2, 3])
|
|
275
|
+
```
|
|
166
276
|
"""
|
|
167
277
|
return await self.map(
|
|
168
278
|
*instances, concurrency=concurrency, name=name, **kwargs
|
|
@@ -186,6 +296,19 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
186
296
|
|
|
187
297
|
Returns:
|
|
188
298
|
A boolean indicating if any result is truthy.
|
|
299
|
+
|
|
300
|
+
Examples:
|
|
301
|
+
```python
|
|
302
|
+
class MyDescriptor(ASyncDescriptor):
|
|
303
|
+
def __init__(self, func):
|
|
304
|
+
super().__init__(func)
|
|
305
|
+
|
|
306
|
+
class MyClass:
|
|
307
|
+
my_method = MyDescriptor(lambda x: x > 0)
|
|
308
|
+
|
|
309
|
+
instance = MyClass()
|
|
310
|
+
result = await instance.my_method._any([-1, 0, 1])
|
|
311
|
+
```
|
|
189
312
|
"""
|
|
190
313
|
return await self.map(
|
|
191
314
|
*instances, concurrency=concurrency, name=name, **kwargs
|
|
@@ -209,6 +332,19 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
209
332
|
|
|
210
333
|
Returns:
|
|
211
334
|
The minimum result.
|
|
335
|
+
|
|
336
|
+
Examples:
|
|
337
|
+
```python
|
|
338
|
+
class MyDescriptor(ASyncDescriptor):
|
|
339
|
+
def __init__(self, func):
|
|
340
|
+
super().__init__(func)
|
|
341
|
+
|
|
342
|
+
class MyClass:
|
|
343
|
+
my_method = MyDescriptor(lambda x: x)
|
|
344
|
+
|
|
345
|
+
instance = MyClass()
|
|
346
|
+
result = await instance.my_method._min([3, 1, 2])
|
|
347
|
+
```
|
|
212
348
|
"""
|
|
213
349
|
return await self.map(
|
|
214
350
|
*instances, concurrency=concurrency, name=name, **kwargs
|
|
@@ -232,6 +368,19 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
232
368
|
|
|
233
369
|
Returns:
|
|
234
370
|
The maximum result.
|
|
371
|
+
|
|
372
|
+
Examples:
|
|
373
|
+
```python
|
|
374
|
+
class MyDescriptor(ASyncDescriptor):
|
|
375
|
+
def __init__(self, func):
|
|
376
|
+
super().__init__(func)
|
|
377
|
+
|
|
378
|
+
class MyClass:
|
|
379
|
+
my_method = MyDescriptor(lambda x: x)
|
|
380
|
+
|
|
381
|
+
instance = MyClass()
|
|
382
|
+
result = await instance.my_method._max([3, 1, 2])
|
|
383
|
+
```
|
|
235
384
|
"""
|
|
236
385
|
return await self.map(
|
|
237
386
|
*instances, concurrency=concurrency, name=name, **kwargs
|
|
@@ -255,6 +404,19 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
|
|
|
255
404
|
|
|
256
405
|
Returns:
|
|
257
406
|
The sum of the results.
|
|
407
|
+
|
|
408
|
+
Examples:
|
|
409
|
+
```python
|
|
410
|
+
class MyDescriptor(ASyncDescriptor):
|
|
411
|
+
def __init__(self, func):
|
|
412
|
+
super().__init__(func)
|
|
413
|
+
|
|
414
|
+
class MyClass:
|
|
415
|
+
my_method = MyDescriptor(lambda x: x)
|
|
416
|
+
|
|
417
|
+
instance = MyClass()
|
|
418
|
+
result = await instance.my_method._sum([1, 2, 3])
|
|
419
|
+
```
|
|
258
420
|
"""
|
|
259
421
|
return await self.map(
|
|
260
422
|
*instances, concurrency=concurrency, name=name, **kwargs
|