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/asyncio/__init__.py
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This package provides custom utilities and extensions to the
|
|
2
|
+
This package provides custom utilities and extensions to the built-in `asyncio` package.
|
|
3
3
|
|
|
4
4
|
These utilities include enhanced versions of common asyncio functions, offering additional
|
|
5
5
|
features and improved functionality for asynchronous programming.
|
|
6
|
+
|
|
7
|
+
Modules:
|
|
8
|
+
- :func:`create_task`: Extends `asyncio.create_task` to support any `Awaitable`, manage task lifecycle, and enhance error handling.
|
|
9
|
+
- :func:`gather`: Provides an enhanced version of `asyncio.gather` with additional features like progress reporting and exclusion of results based on a condition.
|
|
10
|
+
- :func:`as_completed`: Extends `asyncio.as_completed` with additional functionality such as progress reporting using `tqdm`.
|
|
11
|
+
- :func:`get_event_loop`: Utility to get the current event loop, handling cases where no current event loop exists by raising a `RuntimeError`.
|
|
12
|
+
|
|
13
|
+
See Also:
|
|
14
|
+
- `asyncio <https://docs.python.org/3/library/asyncio.html>`_: The standard asyncio library documentation for more details on the original functions.
|
|
6
15
|
"""
|
|
7
16
|
|
|
8
17
|
from a_sync.asyncio.as_completed import as_completed
|
|
@@ -11,3 +20,130 @@ from a_sync.asyncio.gather import gather
|
|
|
11
20
|
from a_sync.asyncio.utils import get_event_loop
|
|
12
21
|
|
|
13
22
|
__all__ = ["create_task", "gather", "as_completed", "get_event_loop"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Function: create_task
|
|
26
|
+
"""
|
|
27
|
+
Extends `asyncio.create_task` to support any `Awaitable`, manage task lifecycle, and enhance error handling.
|
|
28
|
+
|
|
29
|
+
This function accepts any `Awaitable`, ensuring broader compatibility. If the `Awaitable` is not a coroutine,
|
|
30
|
+
it attempts to convert it to one. It optionally prevents the task from being garbage-collected until completion
|
|
31
|
+
and provides enhanced error management by wrapping exceptions in a custom exception when `skip_gc_until_done` is True.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
coro: An `Awaitable` object from which to create the task. If not a coroutine, it will be converted.
|
|
35
|
+
name: Optional name for the task, aiding in debugging.
|
|
36
|
+
skip_gc_until_done: If True, the task is kept alive until it completes, preventing garbage collection.
|
|
37
|
+
Exceptions are wrapped in `PersistedTaskException` for special handling.
|
|
38
|
+
log_destroy_pending: If False, asyncio's default error log when a pending task is destroyed is suppressed.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
Basic usage:
|
|
42
|
+
```
|
|
43
|
+
task = create_task(some_coroutine())
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
With options:
|
|
47
|
+
```
|
|
48
|
+
task = create_task(some_coroutine(), name="MyTask", skip_gc_until_done=True)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
See Also:
|
|
52
|
+
- :func:`asyncio.create_task`: The original asyncio function.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Function: gather
|
|
57
|
+
"""
|
|
58
|
+
Provides an enhanced version of :func:`asyncio.gather`.
|
|
59
|
+
|
|
60
|
+
This function extends Python's `asyncio.gather`, providing additional features for handling either individual awaitable objects or a mapping of awaitables.
|
|
61
|
+
|
|
62
|
+
Differences from `asyncio.gather`:
|
|
63
|
+
- Uses type hints for use with static type checkers.
|
|
64
|
+
- Supports gathering either individual awaitables or a k:v mapping of awaitables.
|
|
65
|
+
- Provides progress reporting using `tqdm` if 'tqdm' is set to True.
|
|
66
|
+
- Allows exclusion of results based on a condition using the 'exclude_if' parameter.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
*awaitables: The awaitables to await concurrently. It can be a list of individual awaitables or a mapping of awaitables.
|
|
70
|
+
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
71
|
+
exclude_if: A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None.
|
|
72
|
+
tqdm: If True, enables progress reporting using `tqdm`. Defaults to False.
|
|
73
|
+
**tqdm_kwargs: Additional keyword arguments for `tqdm` if progress reporting is enabled.
|
|
74
|
+
|
|
75
|
+
Examples:
|
|
76
|
+
Awaiting individual awaitables:
|
|
77
|
+
```
|
|
78
|
+
results = await gather(thing1(), thing2())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Awaiting a mapping of awaitables:
|
|
82
|
+
```
|
|
83
|
+
mapping = {'key1': thing1(), 'key2': thing2()}
|
|
84
|
+
results = await gather(mapping)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
See Also:
|
|
88
|
+
- :func:`asyncio.gather`: The original asyncio function.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# Function: as_completed
|
|
93
|
+
"""
|
|
94
|
+
Extends Python's :func:`asyncio.as_completed` with additional functionality.
|
|
95
|
+
|
|
96
|
+
This function extends Python's `asyncio.as_completed`, providing additional features for mixed use cases of individual awaitable objects and mappings of awaitables.
|
|
97
|
+
|
|
98
|
+
Differences from `asyncio.as_completed`:
|
|
99
|
+
- Uses type hints for use with static type checkers.
|
|
100
|
+
- Supports either individual awaitables or a k:v mapping of awaitables.
|
|
101
|
+
- Can be used as an async iterator which yields the result values.
|
|
102
|
+
- Provides progress reporting using `tqdm` if 'tqdm' is set to True.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
fs: The awaitables to await concurrently. It can be a list of individual awaitables or a mapping of awaitables.
|
|
106
|
+
timeout: The maximum time, in seconds, to wait for the completion of awaitables. Defaults to None (no timeout).
|
|
107
|
+
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
108
|
+
aiter: If True, returns an async iterator of results. Defaults to False.
|
|
109
|
+
tqdm: If True, enables progress reporting using `tqdm`. Defaults to False.
|
|
110
|
+
**tqdm_kwargs: Additional keyword arguments for `tqdm` if progress reporting is enabled.
|
|
111
|
+
|
|
112
|
+
Examples:
|
|
113
|
+
Awaiting individual awaitables:
|
|
114
|
+
```
|
|
115
|
+
awaitables = [async_function1(), async_function2()]
|
|
116
|
+
for coro in as_completed(awaitables):
|
|
117
|
+
val = await coro
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Awaiting mappings of awaitables:
|
|
121
|
+
```
|
|
122
|
+
mapping = {'key1': async_function1(), 'key2': async_function2()}
|
|
123
|
+
for coro in as_completed(mapping):
|
|
124
|
+
k, v = await coro
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
See Also:
|
|
128
|
+
- :func:`asyncio.as_completed`: The original asyncio function.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# Function: get_event_loop
|
|
133
|
+
"""
|
|
134
|
+
Utility to get the current event loop, handling cases where no current event loop exists by raising a `RuntimeError`.
|
|
135
|
+
|
|
136
|
+
This function attempts to get the current event loop. If no event loop is found (which can occur in multi-threaded applications), it raises a `RuntimeError`.
|
|
137
|
+
|
|
138
|
+
Examples:
|
|
139
|
+
Basic usage:
|
|
140
|
+
```
|
|
141
|
+
try:
|
|
142
|
+
loop = get_event_loop()
|
|
143
|
+
except RuntimeError:
|
|
144
|
+
print("No current event loop found.")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
See Also:
|
|
148
|
+
- :func:`asyncio.get_event_loop`: The original asyncio function.
|
|
149
|
+
"""
|
a_sync/asyncio/as_completed.py
CHANGED
|
@@ -9,6 +9,7 @@ try:
|
|
|
9
9
|
except ImportError as e:
|
|
10
10
|
|
|
11
11
|
class tqdm_asyncio: # type: ignore [no-redef]
|
|
12
|
+
@staticmethod
|
|
12
13
|
def as_completed(*args, **kwargs):
|
|
13
14
|
raise ImportError("You must have tqdm installed to use this feature")
|
|
14
15
|
|
|
@@ -69,45 +70,49 @@ def as_completed(
|
|
|
69
70
|
"""
|
|
70
71
|
Concurrently awaits a list of awaitable objects or mappings of awaitables and returns an iterator of results.
|
|
71
72
|
|
|
72
|
-
This function extends Python's asyncio.as_completed
|
|
73
|
+
This function extends Python's :func:`asyncio.as_completed`, providing additional features for mixed use cases of individual awaitable objects and mappings of awaitables.
|
|
73
74
|
|
|
74
|
-
Differences from asyncio.as_completed
|
|
75
|
+
Differences from :func:`asyncio.as_completed`:
|
|
75
76
|
- Uses type hints for use with static type checkers.
|
|
76
77
|
- Supports either individual awaitables or a k:v mapping of awaitables.
|
|
77
|
-
- Can be used as an async iterator which yields the result values.
|
|
78
|
-
- Provides progress reporting using tqdm if 'tqdm' is set to True.
|
|
78
|
+
- Can be used as an async iterator which yields the result values.
|
|
79
|
+
- Provides progress reporting using :mod:`tqdm` if 'tqdm' is set to True.
|
|
80
|
+
|
|
81
|
+
Note:
|
|
82
|
+
The `return_exceptions` parameter is partially implemented. While exceptions can be wrapped and returned instead of being raised, this behavior may not be fully consistent across all scenarios. Users should test their specific use cases to ensure the desired behavior.
|
|
79
83
|
|
|
80
84
|
Args:
|
|
81
85
|
fs: The awaitables to await concurrently. It can be a list of individual awaitables or a mapping of awaitables.
|
|
82
86
|
timeout: The maximum time, in seconds, to wait for the completion of awaitables. Defaults to None (no timeout).
|
|
83
|
-
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
87
|
+
return_exceptions: If True, exceptions are wrapped and returned as results instead of raising them. Defaults to False.
|
|
84
88
|
aiter: If True, returns an async iterator of results. Defaults to False.
|
|
85
|
-
tqdm: If True, enables progress reporting using tqdm
|
|
86
|
-
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
89
|
+
tqdm: If True, enables progress reporting using :mod:`tqdm`. Defaults to False.
|
|
90
|
+
**tqdm_kwargs: Additional keyword arguments for :mod:`tqdm` if progress reporting is enabled.
|
|
87
91
|
|
|
88
92
|
Examples:
|
|
89
93
|
Awaiting individual awaitables:
|
|
90
|
-
```
|
|
91
|
-
awaitables = [async_function1(), async_function2()]
|
|
92
|
-
for coro in as_completed(awaitables):
|
|
93
|
-
val = await coro
|
|
94
|
-
...
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
>>> awaitables = [async_function1(), async_function2()]
|
|
96
|
+
>>> for coro in as_completed(awaitables):
|
|
97
|
+
... val = await coro
|
|
98
|
+
... ...
|
|
99
|
+
|
|
100
|
+
>>> async for val in as_completed(awaitables, aiter=True):
|
|
101
|
+
... ...
|
|
99
102
|
|
|
100
103
|
Awaiting mappings of awaitables:
|
|
101
|
-
```
|
|
102
|
-
mapping = {'key1': async_function1(), 'key2': async_function2()}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
>>> mapping = {'key1': async_function1(), 'key2': async_function2()}
|
|
106
|
+
>>> for coro in as_completed(mapping):
|
|
107
|
+
... k, v = await coro
|
|
108
|
+
... ...
|
|
109
|
+
|
|
110
|
+
>>> async for k, v in as_completed(mapping, aiter=True):
|
|
111
|
+
... ...
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
See Also:
|
|
114
|
+
- :func:`asyncio.as_completed`
|
|
115
|
+
- :class:`ASyncIterator`
|
|
111
116
|
"""
|
|
112
117
|
if isinstance(fs, Mapping):
|
|
113
118
|
return as_completed_mapping(
|
|
@@ -170,22 +175,23 @@ def as_completed_mapping(
|
|
|
170
175
|
Args:
|
|
171
176
|
mapping: A dictionary-like object where keys are of type K and values are awaitable objects of type V.
|
|
172
177
|
timeout: The maximum time, in seconds, to wait for the completion of awaitables. Defaults to None (no timeout).
|
|
173
|
-
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
178
|
+
return_exceptions: If True, exceptions are wrapped and returned as results instead of raising them. Defaults to False.
|
|
174
179
|
aiter: If True, returns an async iterator of results. Defaults to False.
|
|
175
|
-
tqdm: If True, enables progress reporting using tqdm
|
|
176
|
-
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
180
|
+
tqdm: If True, enables progress reporting using :mod:`tqdm`. Defaults to False.
|
|
181
|
+
**tqdm_kwargs: Additional keyword arguments for :mod:`tqdm` if progress reporting is enabled.
|
|
177
182
|
|
|
178
183
|
Example:
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
>>> mapping = {'key1': async_function1(), 'key2': async_function2()}
|
|
185
|
+
>>> for coro in as_completed_mapping(mapping):
|
|
186
|
+
... k, v = await coro
|
|
187
|
+
... ...
|
|
181
188
|
|
|
182
|
-
for
|
|
183
|
-
|
|
184
|
-
...
|
|
189
|
+
>>> async for k, v in as_completed_mapping(mapping, aiter=True):
|
|
190
|
+
... ...
|
|
185
191
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
See Also:
|
|
193
|
+
- :func:`as_completed`
|
|
194
|
+
- :class:`ASyncIterator`
|
|
189
195
|
"""
|
|
190
196
|
return as_completed(
|
|
191
197
|
[
|
|
@@ -227,9 +233,9 @@ async def __yield_as_completed(
|
|
|
227
233
|
Args:
|
|
228
234
|
futs: The awaitables to await.
|
|
229
235
|
timeout: The maximum time, in seconds, to wait for the completion of awaitables. Defaults to None (no timeout).
|
|
230
|
-
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
231
|
-
tqdm: If True, enables progress reporting using tqdm
|
|
232
|
-
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
236
|
+
return_exceptions: If True, exceptions are wrapped and returned as results instead of raising them. Defaults to False.
|
|
237
|
+
tqdm: If True, enables progress reporting using :mod:`tqdm`. Defaults to False.
|
|
238
|
+
**tqdm_kwargs: Additional keyword arguments for :mod:`tqdm` if progress reporting is enabled.
|
|
233
239
|
"""
|
|
234
240
|
for fut in as_completed(
|
|
235
241
|
futs,
|
|
@@ -257,7 +263,7 @@ async def __mapping_wrap(
|
|
|
257
263
|
Args:
|
|
258
264
|
k: The key associated with the awaitable.
|
|
259
265
|
v: The awaitable to wrap.
|
|
260
|
-
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
266
|
+
return_exceptions: If True, exceptions are wrapped and returned as results instead of raising them. Defaults to False.
|
|
261
267
|
|
|
262
268
|
Returns:
|
|
263
269
|
A tuple of the key and the result of the awaitable or the exception if one is raised.
|
a_sync/asyncio/create_task.py
CHANGED
|
@@ -21,21 +21,41 @@ def create_task(
|
|
|
21
21
|
log_destroy_pending: bool = True,
|
|
22
22
|
) -> "asyncio.Task[T]":
|
|
23
23
|
"""
|
|
24
|
-
Extends asyncio.create_task to support any Awaitable
|
|
24
|
+
Extends :func:`asyncio.create_task` to support any :class:`Awaitable`, manage task lifecycle, and enhance error handling.
|
|
25
25
|
|
|
26
|
-
This function accepts any Awaitable
|
|
27
|
-
it
|
|
28
|
-
|
|
26
|
+
This function accepts any :class:`Awaitable`, ensuring broader compatibility. If the Awaitable is not a coroutine,
|
|
27
|
+
it is awaited directly using a private helper function `__await`, which can handle any Awaitable object.
|
|
28
|
+
|
|
29
|
+
Note:
|
|
30
|
+
The `__await` function is designed to handle any Awaitable, implicitly managing non-coroutine Awaitables by awaiting them.
|
|
29
31
|
|
|
30
32
|
Args:
|
|
31
|
-
coro: An Awaitable object from which to create the task.
|
|
33
|
+
coro: An :class:`Awaitable` object from which to create the task.
|
|
32
34
|
name: Optional name for the task, aiding in debugging.
|
|
33
35
|
skip_gc_until_done: If True, the task is kept alive until it completes, preventing garbage collection.
|
|
34
|
-
|
|
36
|
+
Exceptions are wrapped in :class:`PersistedTaskException` for special handling within the
|
|
37
|
+
`__persisted_task_exc_wrap` function.
|
|
35
38
|
log_destroy_pending: If False, asyncio's default error log when a pending task is destroyed is suppressed.
|
|
36
39
|
|
|
37
40
|
Returns:
|
|
38
|
-
An asyncio.Task object created from the provided Awaitable.
|
|
41
|
+
An :class:`asyncio.Task` object created from the provided Awaitable.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
Create a simple task with a coroutine:
|
|
45
|
+
|
|
46
|
+
>>> async def my_coroutine():
|
|
47
|
+
... return "Hello, World!"
|
|
48
|
+
>>> task = create_task(my_coroutine())
|
|
49
|
+
|
|
50
|
+
Create a task with a non-coroutine Awaitable:
|
|
51
|
+
|
|
52
|
+
>>> from concurrent.futures import Future
|
|
53
|
+
>>> future = Future()
|
|
54
|
+
>>> task = create_task(future)
|
|
55
|
+
|
|
56
|
+
See Also:
|
|
57
|
+
- :func:`asyncio.create_task`
|
|
58
|
+
- :class:`asyncio.Task`
|
|
39
59
|
"""
|
|
40
60
|
|
|
41
61
|
if not asyncio.iscoroutine(coro):
|
|
@@ -57,10 +77,20 @@ async def __await(awaitable: Awaitable[T]) -> T:
|
|
|
57
77
|
"""Wait for the completion of an Awaitable.
|
|
58
78
|
|
|
59
79
|
Args:
|
|
60
|
-
awaitable: The Awaitable object to wait for.
|
|
80
|
+
awaitable: The :class:`Awaitable` object to wait for.
|
|
61
81
|
|
|
62
82
|
Raises:
|
|
63
83
|
RuntimeError: If a RuntimeError occurs during the await, it is raised with additional context.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
Await a simple coroutine:
|
|
87
|
+
|
|
88
|
+
>>> async def my_coroutine():
|
|
89
|
+
... return "Hello, World!"
|
|
90
|
+
>>> result = await __await(my_coroutine())
|
|
91
|
+
|
|
92
|
+
See Also:
|
|
93
|
+
- :class:`Awaitable`
|
|
64
94
|
"""
|
|
65
95
|
try:
|
|
66
96
|
return await awaitable
|
|
@@ -75,8 +105,11 @@ def __prune_persisted_tasks():
|
|
|
75
105
|
"""Remove completed tasks from the set of persisted tasks.
|
|
76
106
|
|
|
77
107
|
This function checks each task in the persisted tasks set. If a task is done and has an exception,
|
|
78
|
-
it logs the exception and raises it if it's not a PersistedTaskException
|
|
108
|
+
it logs the exception and raises it if it's not a :class:`PersistedTaskException`. It also logs the traceback
|
|
79
109
|
manually since the usual handler will not run after retrieving the exception.
|
|
110
|
+
|
|
111
|
+
See Also:
|
|
112
|
+
- :class:`PersistedTaskException`
|
|
80
113
|
"""
|
|
81
114
|
for task in tuple(__persisted_tasks):
|
|
82
115
|
if task.done() and (e := task.exception()):
|
|
@@ -102,10 +135,13 @@ async def __persisted_task_exc_wrap(task: "asyncio.Task[T]") -> T:
|
|
|
102
135
|
Wrap a task to handle its exception in a specialized manner.
|
|
103
136
|
|
|
104
137
|
Args:
|
|
105
|
-
task: The asyncio
|
|
138
|
+
task: The :class:`asyncio.Task` to wrap.
|
|
106
139
|
|
|
107
140
|
Raises:
|
|
108
141
|
PersistedTaskException: Wraps any exception raised by the task for special handling.
|
|
142
|
+
|
|
143
|
+
See Also:
|
|
144
|
+
- :class:`PersistedTaskException`
|
|
109
145
|
"""
|
|
110
146
|
try:
|
|
111
147
|
return await task
|
a_sync/asyncio/gather.py
CHANGED
|
@@ -2,35 +2,57 @@
|
|
|
2
2
|
This module provides an enhanced version of :func:`asyncio.gather`.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
from typing import Any, Awaitable, Dict, List, Mapping, Union, overload
|
|
6
|
+
|
|
7
|
+
from a_sync._typing import *
|
|
8
|
+
from a_sync.asyncio.as_completed import as_completed_mapping, _exc_wrap
|
|
7
9
|
|
|
8
10
|
try:
|
|
9
11
|
from tqdm.asyncio import tqdm_asyncio
|
|
10
12
|
except ImportError as e:
|
|
11
13
|
|
|
12
14
|
class tqdm_asyncio: # type: ignore [no-redef]
|
|
15
|
+
@staticmethod
|
|
13
16
|
async def gather(*args, **kwargs):
|
|
14
17
|
raise ImportError(
|
|
15
18
|
"You must have tqdm installed in order to use this feature"
|
|
16
19
|
)
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
from a_sync._typing import *
|
|
20
|
-
from a_sync.asyncio.as_completed import as_completed_mapping, _exc_wrap
|
|
21
|
-
|
|
22
|
-
|
|
23
22
|
Excluder = Callable[[T], bool]
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
@overload
|
|
27
26
|
async def gather(
|
|
28
|
-
|
|
27
|
+
awaitables: Mapping[K, Awaitable[V]],
|
|
29
28
|
return_exceptions: bool = False,
|
|
30
29
|
exclude_if: Optional[Excluder[V]] = None,
|
|
31
30
|
tqdm: bool = False,
|
|
32
31
|
**tqdm_kwargs: Any,
|
|
33
|
-
) -> Dict[K, V]:
|
|
32
|
+
) -> Dict[K, V]:
|
|
33
|
+
"""
|
|
34
|
+
Concurrently awaits a k:v mapping of awaitables and returns the results.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
awaitables (Mapping[K, Awaitable[V]]): A mapping of keys to awaitable objects.
|
|
38
|
+
return_exceptions (bool, optional): If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
39
|
+
exclude_if (Optional[Excluder[V]], optional): A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None. Note: This is only applied when the input is not a mapping.
|
|
40
|
+
tqdm (bool, optional): If True, enables progress reporting using tqdm. Defaults to False.
|
|
41
|
+
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
Awaiting a mapping of awaitables:
|
|
45
|
+
|
|
46
|
+
>>> mapping = {'key1': thing1(), 'key2': thing2()}
|
|
47
|
+
>>> results = await gather(mapping)
|
|
48
|
+
>>> results
|
|
49
|
+
{'key1': 'result', 'key2': 123}
|
|
50
|
+
|
|
51
|
+
See Also:
|
|
52
|
+
:func:`asyncio.gather`
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
|
|
34
56
|
@overload
|
|
35
57
|
async def gather(
|
|
36
58
|
*awaitables: Awaitable[T],
|
|
@@ -38,7 +60,29 @@ async def gather(
|
|
|
38
60
|
exclude_if: Optional[Excluder[T]] = None,
|
|
39
61
|
tqdm: bool = False,
|
|
40
62
|
**tqdm_kwargs: Any,
|
|
41
|
-
) -> List[T]:
|
|
63
|
+
) -> List[T]:
|
|
64
|
+
"""
|
|
65
|
+
Concurrently awaits a series of awaitable objects and returns the results.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
*awaitables (Awaitable[T]): The awaitables to await concurrently.
|
|
69
|
+
return_exceptions (bool, optional): If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
70
|
+
exclude_if (Optional[Excluder[T]], optional): A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None.
|
|
71
|
+
tqdm (bool, optional): If True, enables progress reporting using tqdm. Defaults to False.
|
|
72
|
+
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
Awaiting individual awaitables:
|
|
76
|
+
|
|
77
|
+
>>> results = await gather(thing1(), thing2())
|
|
78
|
+
>>> results
|
|
79
|
+
['result', 123]
|
|
80
|
+
|
|
81
|
+
See Also:
|
|
82
|
+
:func:`asyncio.gather`
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
|
|
42
86
|
async def gather(
|
|
43
87
|
*awaitables: Union[Awaitable[T], Mapping[K, Awaitable[V]]],
|
|
44
88
|
return_exceptions: bool = False,
|
|
@@ -47,40 +91,40 @@ async def gather(
|
|
|
47
91
|
**tqdm_kwargs: Any,
|
|
48
92
|
) -> Union[List[T], Dict[K, V]]:
|
|
49
93
|
"""
|
|
50
|
-
Concurrently awaits a list of awaitable objects or a mapping of awaitables and returns the results.
|
|
94
|
+
Concurrently awaits a list of awaitable objects or a k:v mapping of awaitables, and returns the results.
|
|
51
95
|
|
|
52
|
-
This function extends Python's asyncio.gather
|
|
96
|
+
This function extends Python's :func:`asyncio.gather`, providing additional features for handling either individual
|
|
97
|
+
awaitable objects or a single mapping of awaitables.
|
|
53
98
|
|
|
54
|
-
Differences from asyncio.gather
|
|
99
|
+
Differences from :func:`asyncio.gather`:
|
|
55
100
|
- Uses type hints for use with static type checkers.
|
|
56
101
|
- Supports gathering either individual awaitables or a k:v mapping of awaitables.
|
|
57
102
|
- Provides progress reporting using tqdm if 'tqdm' is set to True.
|
|
58
|
-
- Allows exclusion of results based on a condition using the 'exclude_if' parameter.
|
|
103
|
+
- Allows exclusion of results based on a condition using the 'exclude_if' parameter. Note: This is only applied when the input is not a mapping.
|
|
59
104
|
|
|
60
105
|
Args:
|
|
61
|
-
*awaitables: The awaitables to await concurrently. It can be a list of individual awaitables or a mapping of awaitables.
|
|
62
|
-
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
63
|
-
exclude_if: A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None.
|
|
64
|
-
tqdm: If True, enables progress reporting using tqdm. Defaults to False.
|
|
106
|
+
*awaitables (Union[Awaitable[T], Mapping[K, Awaitable[V]]]): The awaitables to await concurrently. It can be a list of individual awaitables or a single mapping of awaitables.
|
|
107
|
+
return_exceptions (bool, optional): If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
108
|
+
exclude_if (Optional[Excluder[T]], optional): A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None. Note: This is only applied when the input is not a mapping.
|
|
109
|
+
tqdm (bool, optional): If True, enables progress reporting using tqdm. Defaults to False.
|
|
65
110
|
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
66
111
|
|
|
67
112
|
Examples:
|
|
68
113
|
Awaiting individual awaitables:
|
|
69
114
|
|
|
70
|
-
- Results will be a list containing the result of each awaitable in sequential order.
|
|
71
|
-
|
|
72
115
|
>>> results = await gather(thing1(), thing2())
|
|
73
116
|
>>> results
|
|
74
117
|
['result', 123]
|
|
75
118
|
|
|
76
119
|
Awaiting a mapping of awaitables:
|
|
77
120
|
|
|
78
|
-
- Results will be a dictionary with 'key1' mapped to the result of thing1() and 'key2' mapped to the result of thing2.
|
|
79
|
-
|
|
80
121
|
>>> mapping = {'key1': thing1(), 'key2': thing2()}
|
|
81
122
|
>>> results = await gather(mapping)
|
|
82
123
|
>>> results
|
|
83
124
|
{'key1': 'result', 'key2': 123}
|
|
125
|
+
|
|
126
|
+
See Also:
|
|
127
|
+
:func:`asyncio.gather`
|
|
84
128
|
"""
|
|
85
129
|
is_mapping = _is_mapping(awaitables)
|
|
86
130
|
results = await (
|
|
@@ -123,10 +167,10 @@ async def gather_mapping(
|
|
|
123
167
|
This function is designed to await a mapping of awaitable objects, where each key-value pair represents a unique awaitable. It enables concurrent execution and gathers results into a dictionary.
|
|
124
168
|
|
|
125
169
|
Args:
|
|
126
|
-
mapping: A dictionary-like object where keys are of type K and values are awaitable objects of type V.
|
|
127
|
-
return_exceptions: If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
128
|
-
exclude_if: A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None.
|
|
129
|
-
tqdm: If True, enables progress reporting using tqdm. Defaults to False.
|
|
170
|
+
mapping (Mapping[K, Awaitable[V]]): A dictionary-like object where keys are of type K and values are awaitable objects of type V.
|
|
171
|
+
return_exceptions (bool, optional): If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
172
|
+
exclude_if (Optional[Excluder[V]], optional): A callable that takes a result and returns True if the result should be excluded from the final output. Defaults to None. Note: This is not applied when the input is a mapping.
|
|
173
|
+
tqdm (bool, optional): If True, enables progress reporting using tqdm. Defaults to False.
|
|
130
174
|
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
131
175
|
|
|
132
176
|
Example:
|
|
@@ -136,6 +180,9 @@ async def gather_mapping(
|
|
|
136
180
|
>>> results = await gather_mapping(mapping)
|
|
137
181
|
>>> results
|
|
138
182
|
{'task1': "result", 'task2': 123, 'task3': None}
|
|
183
|
+
|
|
184
|
+
See Also:
|
|
185
|
+
:func:`asyncio.gather`
|
|
139
186
|
"""
|
|
140
187
|
results = {
|
|
141
188
|
k: v
|