ez-a-sync 0.22.14__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 +37 -5
- a_sync/__init__.py +53 -12
- a_sync/_smart.py +231 -28
- a_sync/_typing.py +112 -15
- a_sync/a_sync/__init__.py +35 -10
- a_sync/a_sync/_descriptor.py +248 -38
- a_sync/a_sync/_flags.py +78 -9
- a_sync/a_sync/_helpers.py +46 -13
- a_sync/a_sync/_kwargs.py +33 -8
- a_sync/a_sync/_meta.py +149 -28
- a_sync/a_sync/abstract.py +150 -28
- a_sync/a_sync/base.py +34 -16
- a_sync/a_sync/config.py +85 -14
- a_sync/a_sync/decorator.py +441 -139
- a_sync/a_sync/function.py +709 -147
- a_sync/a_sync/method.py +437 -110
- a_sync/a_sync/modifiers/__init__.py +85 -5
- a_sync/a_sync/modifiers/cache/__init__.py +116 -17
- a_sync/a_sync/modifiers/cache/memory.py +130 -20
- a_sync/a_sync/modifiers/limiter.py +101 -22
- a_sync/a_sync/modifiers/manager.py +142 -16
- a_sync/a_sync/modifiers/semaphores.py +121 -15
- a_sync/a_sync/property.py +383 -82
- a_sync/a_sync/singleton.py +44 -19
- a_sync/aliases.py +0 -1
- a_sync/asyncio/__init__.py +140 -1
- a_sync/asyncio/as_completed.py +213 -79
- a_sync/asyncio/create_task.py +70 -20
- a_sync/asyncio/gather.py +125 -58
- a_sync/asyncio/utils.py +3 -3
- a_sync/exceptions.py +248 -26
- a_sync/executor.py +164 -69
- a_sync/future.py +1227 -168
- a_sync/iter.py +173 -56
- a_sync/primitives/__init__.py +14 -2
- a_sync/primitives/_debug.py +72 -18
- a_sync/primitives/_loggable.py +41 -10
- a_sync/primitives/locks/__init__.py +5 -2
- a_sync/primitives/locks/counter.py +107 -38
- a_sync/primitives/locks/event.py +21 -7
- a_sync/primitives/locks/prio_semaphore.py +262 -63
- a_sync/primitives/locks/semaphore.py +138 -89
- a_sync/primitives/queue.py +601 -60
- a_sync/sphinx/__init__.py +0 -1
- a_sync/sphinx/ext.py +160 -50
- a_sync/task.py +313 -112
- a_sync/utils/__init__.py +12 -6
- a_sync/utils/iterators.py +170 -50
- {ez_a_sync-0.22.14.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.14.dist-info → ez_a_sync-0.22.16.dist-info}/WHEEL +1 -1
- tests/conftest.py +1 -2
- tests/executor.py +250 -9
- tests/fixtures.py +61 -32
- tests/test_abstract.py +22 -4
- tests/test_as_completed.py +54 -21
- tests/test_base.py +264 -19
- tests/test_cache.py +31 -15
- tests/test_decorator.py +54 -28
- tests/test_executor.py +31 -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 +28 -11
- tests/test_task.py +162 -36
- ez_a_sync-0.22.14.dist-info/RECORD +0 -74
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.16.dist-info}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.16.dist-info}/top_level.txt +0 -0
a_sync/asyncio/create_task.py
CHANGED
|
@@ -12,28 +12,50 @@ from a_sync._typing import *
|
|
|
12
12
|
|
|
13
13
|
logger = logging.getLogger(__name__)
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
def create_task(
|
|
16
|
-
coro: Awaitable[T],
|
|
17
|
-
*,
|
|
18
|
-
name: Optional[str] = None,
|
|
17
|
+
coro: Awaitable[T],
|
|
18
|
+
*,
|
|
19
|
+
name: Optional[str] = None,
|
|
19
20
|
skip_gc_until_done: bool = False,
|
|
20
21
|
log_destroy_pending: bool = True,
|
|
21
22
|
) -> "asyncio.Task[T]":
|
|
22
23
|
"""
|
|
23
|
-
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
|
+
|
|
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.
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
enhanced error management by wrapping exceptions in a custom exception.
|
|
29
|
+
Note:
|
|
30
|
+
The `__await` function is designed to handle any Awaitable, implicitly managing non-coroutine Awaitables by awaiting them.
|
|
28
31
|
|
|
29
32
|
Args:
|
|
30
|
-
coro: An Awaitable object from which to create the task.
|
|
33
|
+
coro: An :class:`Awaitable` object from which to create the task.
|
|
31
34
|
name: Optional name for the task, aiding in debugging.
|
|
32
35
|
skip_gc_until_done: If True, the task is kept alive until it completes, preventing garbage collection.
|
|
36
|
+
Exceptions are wrapped in :class:`PersistedTaskException` for special handling within the
|
|
37
|
+
`__persisted_task_exc_wrap` function.
|
|
33
38
|
log_destroy_pending: If False, asyncio's default error log when a pending task is destroyed is suppressed.
|
|
34
39
|
|
|
35
40
|
Returns:
|
|
36
|
-
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`
|
|
37
59
|
"""
|
|
38
60
|
|
|
39
61
|
if not asyncio.iscoroutine(coro):
|
|
@@ -50,8 +72,26 @@ def create_task(
|
|
|
50
72
|
|
|
51
73
|
__persisted_tasks: Set["asyncio.Task[Any]"] = set()
|
|
52
74
|
|
|
75
|
+
|
|
53
76
|
async def __await(awaitable: Awaitable[T]) -> T:
|
|
54
|
-
"""Wait for the completion of an Awaitable.
|
|
77
|
+
"""Wait for the completion of an Awaitable.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
awaitable: The :class:`Awaitable` object to wait for.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
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`
|
|
94
|
+
"""
|
|
55
95
|
try:
|
|
56
96
|
return await awaitable
|
|
57
97
|
except RuntimeError as e:
|
|
@@ -60,38 +100,48 @@ async def __await(awaitable: Awaitable[T]) -> T:
|
|
|
60
100
|
args.append(awaitable._children)
|
|
61
101
|
raise RuntimeError(*args) from None
|
|
62
102
|
|
|
103
|
+
|
|
63
104
|
def __prune_persisted_tasks():
|
|
64
|
-
"""Remove completed tasks from the set of persisted tasks.
|
|
105
|
+
"""Remove completed tasks from the set of persisted tasks.
|
|
106
|
+
|
|
107
|
+
This function checks each task in the persisted tasks set. If a task is done and has an exception,
|
|
108
|
+
it logs the exception and raises it if it's not a :class:`PersistedTaskException`. It also logs the traceback
|
|
109
|
+
manually since the usual handler will not run after retrieving the exception.
|
|
110
|
+
|
|
111
|
+
See Also:
|
|
112
|
+
- :class:`PersistedTaskException`
|
|
113
|
+
"""
|
|
65
114
|
for task in tuple(__persisted_tasks):
|
|
66
115
|
if task.done() and (e := task.exception()):
|
|
67
116
|
# force exceptions related to this lib to bubble up
|
|
68
117
|
if not isinstance(e, exceptions.PersistedTaskException):
|
|
69
118
|
logger.exception(e)
|
|
70
119
|
raise e
|
|
71
|
-
# we have to manually log the traceback that asyncio would usually log
|
|
120
|
+
# we have to manually log the traceback that asyncio would usually log
|
|
72
121
|
# since we already got the exception from the task and the usual handler will now not run
|
|
73
122
|
context = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
123
|
+
"message": f"{task.__class__.__name__} exception was never retrieved",
|
|
124
|
+
"exception": e,
|
|
125
|
+
"future": task,
|
|
77
126
|
}
|
|
78
127
|
if task._source_traceback:
|
|
79
|
-
context[
|
|
128
|
+
context["source_traceback"] = task._source_traceback
|
|
80
129
|
task._loop.call_exception_handler(context)
|
|
81
130
|
__persisted_tasks.discard(task)
|
|
82
131
|
|
|
132
|
+
|
|
83
133
|
async def __persisted_task_exc_wrap(task: "asyncio.Task[T]") -> T:
|
|
84
134
|
"""
|
|
85
135
|
Wrap a task to handle its exception in a specialized manner.
|
|
86
136
|
|
|
87
137
|
Args:
|
|
88
|
-
task: The asyncio
|
|
89
|
-
|
|
90
|
-
Returns:
|
|
91
|
-
The result of the task, if successful.
|
|
138
|
+
task: The :class:`asyncio.Task` to wrap.
|
|
92
139
|
|
|
93
140
|
Raises:
|
|
94
141
|
PersistedTaskException: Wraps any exception raised by the task for special handling.
|
|
142
|
+
|
|
143
|
+
See Also:
|
|
144
|
+
- :class:`PersistedTaskException`
|
|
95
145
|
"""
|
|
96
146
|
try:
|
|
97
147
|
return await task
|
a_sync/asyncio/gather.py
CHANGED
|
@@ -2,104 +2,163 @@
|
|
|
2
2
|
This module provides an enhanced version of :func:`asyncio.gather`.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
8
9
|
|
|
9
10
|
try:
|
|
10
11
|
from tqdm.asyncio import tqdm_asyncio
|
|
11
12
|
except ImportError as e:
|
|
13
|
+
|
|
12
14
|
class tqdm_asyncio: # type: ignore [no-redef]
|
|
15
|
+
@staticmethod
|
|
13
16
|
async def gather(*args, **kwargs):
|
|
14
|
-
raise ImportError(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from a_sync.asyncio.as_completed import as_completed_mapping, _exc_wrap
|
|
17
|
+
raise ImportError(
|
|
18
|
+
"You must have tqdm installed in order to use this feature"
|
|
19
|
+
)
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
Excluder = Callable[[T], bool]
|
|
21
23
|
|
|
24
|
+
|
|
22
25
|
@overload
|
|
23
26
|
async def gather(
|
|
24
|
-
|
|
25
|
-
return_exceptions: bool = False,
|
|
26
|
-
exclude_if: Optional[Excluder[V]] = None,
|
|
27
|
-
tqdm: bool = False,
|
|
27
|
+
awaitables: Mapping[K, Awaitable[V]],
|
|
28
|
+
return_exceptions: bool = False,
|
|
29
|
+
exclude_if: Optional[Excluder[V]] = None,
|
|
30
|
+
tqdm: bool = False,
|
|
28
31
|
**tqdm_kwargs: Any,
|
|
29
32
|
) -> Dict[K, V]:
|
|
30
|
-
|
|
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
|
+
|
|
31
56
|
@overload
|
|
32
57
|
async def gather(
|
|
33
|
-
*awaitables: Awaitable[T],
|
|
34
|
-
return_exceptions: bool = False,
|
|
58
|
+
*awaitables: Awaitable[T],
|
|
59
|
+
return_exceptions: bool = False,
|
|
35
60
|
exclude_if: Optional[Excluder[T]] = None,
|
|
36
61
|
tqdm: bool = False,
|
|
37
62
|
**tqdm_kwargs: Any,
|
|
38
63
|
) -> List[T]:
|
|
39
|
-
|
|
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
|
+
|
|
40
86
|
async def gather(
|
|
41
|
-
*awaitables: Union[Awaitable[T], Mapping[K, Awaitable[V]]],
|
|
42
|
-
return_exceptions: bool = False,
|
|
43
|
-
exclude_if: Optional[Excluder[T]] = None,
|
|
44
|
-
tqdm: bool = False,
|
|
87
|
+
*awaitables: Union[Awaitable[T], Mapping[K, Awaitable[V]]],
|
|
88
|
+
return_exceptions: bool = False,
|
|
89
|
+
exclude_if: Optional[Excluder[T]] = None,
|
|
90
|
+
tqdm: bool = False,
|
|
45
91
|
**tqdm_kwargs: Any,
|
|
46
92
|
) -> Union[List[T], Dict[K, V]]:
|
|
47
93
|
"""
|
|
48
|
-
Concurrently awaits a list of awaitable objects or
|
|
94
|
+
Concurrently awaits a list of awaitable objects or a k:v mapping of awaitables, and returns the results.
|
|
49
95
|
|
|
50
|
-
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.
|
|
51
98
|
|
|
52
|
-
Differences from asyncio.gather
|
|
99
|
+
Differences from :func:`asyncio.gather`:
|
|
53
100
|
- Uses type hints for use with static type checkers.
|
|
54
101
|
- Supports gathering either individual awaitables or a k:v mapping of awaitables.
|
|
55
102
|
- Provides progress reporting using tqdm if 'tqdm' is set to True.
|
|
56
|
-
|
|
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.
|
|
104
|
+
|
|
57
105
|
Args:
|
|
58
|
-
*awaitables: The awaitables to await concurrently. It can be a
|
|
59
|
-
return_exceptions (optional): If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
60
|
-
|
|
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.
|
|
61
110
|
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
62
111
|
|
|
63
|
-
Returns:
|
|
64
|
-
A list of results when awaiting individual awaitables or a dictionary of results when awaiting mappings.
|
|
65
|
-
|
|
66
112
|
Examples:
|
|
67
113
|
Awaiting individual awaitables:
|
|
68
|
-
|
|
69
|
-
- Results will be a list containing the result of each awaitable in sequential order.
|
|
70
114
|
|
|
71
|
-
```
|
|
72
115
|
>>> results = await gather(thing1(), thing2())
|
|
73
116
|
>>> results
|
|
74
117
|
['result', 123]
|
|
75
|
-
```
|
|
76
118
|
|
|
77
|
-
Awaiting
|
|
78
|
-
|
|
79
|
-
- Results will be a dictionary with 'key1' mapped to the result of thing1() and 'key2' mapped to the result of thing2.
|
|
80
|
-
|
|
81
|
-
```
|
|
119
|
+
Awaiting a mapping of awaitables:
|
|
120
|
+
|
|
82
121
|
>>> mapping = {'key1': thing1(), 'key2': thing2()}
|
|
83
122
|
>>> results = await gather(mapping)
|
|
84
123
|
>>> results
|
|
85
124
|
{'key1': 'result', 'key2': 123}
|
|
86
|
-
|
|
125
|
+
|
|
126
|
+
See Also:
|
|
127
|
+
:func:`asyncio.gather`
|
|
87
128
|
"""
|
|
88
129
|
is_mapping = _is_mapping(awaitables)
|
|
89
130
|
results = await (
|
|
90
|
-
gather_mapping(
|
|
91
|
-
|
|
92
|
-
|
|
131
|
+
gather_mapping(
|
|
132
|
+
awaitables[0],
|
|
133
|
+
return_exceptions=return_exceptions,
|
|
134
|
+
exclude_if=exclude_if,
|
|
135
|
+
tqdm=tqdm,
|
|
136
|
+
**tqdm_kwargs,
|
|
137
|
+
)
|
|
138
|
+
if is_mapping
|
|
139
|
+
else (
|
|
140
|
+
tqdm_asyncio.gather(
|
|
141
|
+
*(
|
|
142
|
+
(_exc_wrap(a) for a in awaitables)
|
|
143
|
+
if return_exceptions
|
|
144
|
+
else awaitables
|
|
145
|
+
),
|
|
146
|
+
**tqdm_kwargs,
|
|
147
|
+
)
|
|
148
|
+
if tqdm
|
|
149
|
+
else asyncio.gather(*awaitables, return_exceptions=return_exceptions)
|
|
150
|
+
) # type: ignore [arg-type]
|
|
93
151
|
)
|
|
94
152
|
if exclude_if and not is_mapping:
|
|
95
153
|
results = [r for r in results if not exclude_if(r)]
|
|
96
154
|
return results
|
|
97
|
-
|
|
155
|
+
|
|
156
|
+
|
|
98
157
|
async def gather_mapping(
|
|
99
|
-
mapping: Mapping[K, Awaitable[V]],
|
|
100
|
-
return_exceptions: bool = False,
|
|
158
|
+
mapping: Mapping[K, Awaitable[V]],
|
|
159
|
+
return_exceptions: bool = False,
|
|
101
160
|
exclude_if: Optional[Excluder[V]] = None,
|
|
102
|
-
tqdm: bool = False,
|
|
161
|
+
tqdm: bool = False,
|
|
103
162
|
**tqdm_kwargs: Any,
|
|
104
163
|
) -> Dict[K, V]:
|
|
105
164
|
"""
|
|
@@ -108,32 +167,40 @@ async def gather_mapping(
|
|
|
108
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.
|
|
109
168
|
|
|
110
169
|
Args:
|
|
111
|
-
mapping: A dictionary-like object where keys are of type K and values are awaitable objects of type V.
|
|
112
|
-
return_exceptions (optional): If True, exceptions are returned as results instead of raising them. Defaults to False.
|
|
113
|
-
|
|
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.
|
|
114
174
|
**tqdm_kwargs: Additional keyword arguments for tqdm if progress reporting is enabled.
|
|
115
175
|
|
|
116
|
-
Returns:
|
|
117
|
-
A dictionary with keys corresponding to the keys of the input mapping and values containing the results of the corresponding awaitables.
|
|
118
|
-
|
|
119
176
|
Example:
|
|
120
177
|
The 'results' dictionary will contain the awaited results, where keys match the keys in the 'mapping' and values contain the results of the corresponding awaitables.
|
|
121
|
-
|
|
178
|
+
|
|
122
179
|
>>> mapping = {'task1': async_function1(), 'task2': async_function2(), 'task3': async_function3()}
|
|
123
180
|
>>> results = await gather_mapping(mapping)
|
|
124
181
|
>>> results
|
|
125
182
|
{'task1': "result", 'task2': 123, 'task3': None}
|
|
126
|
-
|
|
183
|
+
|
|
184
|
+
See Also:
|
|
185
|
+
:func:`asyncio.gather`
|
|
127
186
|
"""
|
|
128
187
|
results = {
|
|
129
|
-
k: v
|
|
130
|
-
async for k, v in as_completed_mapping(
|
|
188
|
+
k: v
|
|
189
|
+
async for k, v in as_completed_mapping(
|
|
190
|
+
mapping,
|
|
191
|
+
return_exceptions=return_exceptions,
|
|
192
|
+
aiter=True,
|
|
193
|
+
tqdm=tqdm,
|
|
194
|
+
**tqdm_kwargs,
|
|
195
|
+
)
|
|
131
196
|
if exclude_if is None or not exclude_if(v)
|
|
132
197
|
}
|
|
133
198
|
# return data in same order as input mapping
|
|
134
|
-
return {k: results[k] for k in mapping}
|
|
199
|
+
return {k: results[k] for k in mapping}
|
|
135
200
|
|
|
136
201
|
|
|
137
|
-
_is_mapping = lambda awaitables: len(awaitables) == 1 and isinstance(
|
|
202
|
+
_is_mapping = lambda awaitables: len(awaitables) == 1 and isinstance(
|
|
203
|
+
awaitables[0], Mapping
|
|
204
|
+
)
|
|
138
205
|
|
|
139
206
|
__all__ = ["gather", "gather_mapping"]
|
a_sync/asyncio/utils.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
1
|
import asyncio
|
|
3
2
|
|
|
3
|
+
|
|
4
4
|
def get_event_loop() -> asyncio.AbstractEventLoop:
|
|
5
5
|
try:
|
|
6
6
|
loop = asyncio.get_event_loop()
|
|
7
|
-
except RuntimeError as e:
|
|
7
|
+
except RuntimeError as e: # Necessary for use with multi-threaded applications.
|
|
8
8
|
if not str(e).startswith("There is no current event loop in thread"):
|
|
9
9
|
raise
|
|
10
10
|
loop = asyncio.new_event_loop()
|
|
11
11
|
asyncio.set_event_loop(loop)
|
|
12
|
-
return loop
|
|
12
|
+
return loop
|