ez-a-sync 0.22.6__py3-none-any.whl → 0.22.7__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/_typing.py +4 -0
- a_sync/a_sync/_descriptor.py +9 -3
- a_sync/a_sync/method.py +4 -1
- a_sync/a_sync/property.py +34 -2
- a_sync/iter.py +84 -29
- a_sync/utils/iterators.py +9 -12
- {ez_a_sync-0.22.6.dist-info → ez_a_sync-0.22.7.dist-info}/METADATA +1 -1
- {ez_a_sync-0.22.6.dist-info → ez_a_sync-0.22.7.dist-info}/RECORD +11 -11
- {ez_a_sync-0.22.6.dist-info → ez_a_sync-0.22.7.dist-info}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.6.dist-info → ez_a_sync-0.22.7.dist-info}/WHEEL +0 -0
- {ez_a_sync-0.22.6.dist-info → ez_a_sync-0.22.7.dist-info}/top_level.txt +0 -0
a_sync/_typing.py
CHANGED
|
@@ -25,9 +25,13 @@ T = TypeVar("T")
|
|
|
25
25
|
K = TypeVar("K")
|
|
26
26
|
V = TypeVar("V")
|
|
27
27
|
I = TypeVar("I")
|
|
28
|
+
"""A :class:`TypeVar` that is used to represent instances of a common class."""
|
|
29
|
+
|
|
28
30
|
E = TypeVar('E', bound=Exception)
|
|
29
31
|
TYPE = TypeVar("TYPE", bound=Type)
|
|
32
|
+
|
|
30
33
|
P = ParamSpec("P")
|
|
34
|
+
"""A :class:`ParamSpec` used everywhere in the lib."""
|
|
31
35
|
|
|
32
36
|
Numeric = Union[int, float, Decimal]
|
|
33
37
|
"""Type alias for numeric values of types int, float, or Decimal."""
|
a_sync/a_sync/_descriptor.py
CHANGED
|
@@ -34,7 +34,7 @@ class ASyncDescriptor(ModifiedMixin, Generic[I, P, T]):
|
|
|
34
34
|
**modifiers: ModifierKwargs,
|
|
35
35
|
) -> None:
|
|
36
36
|
"""
|
|
37
|
-
Initialize the
|
|
37
|
+
Initialize the {cls}.
|
|
38
38
|
|
|
39
39
|
Args:
|
|
40
40
|
_fget: The function to be wrapped.
|
|
@@ -56,7 +56,7 @@ class ASyncDescriptor(ModifiedMixin, Generic[I, P, T]):
|
|
|
56
56
|
self.__wrapped__ = _fget
|
|
57
57
|
|
|
58
58
|
self.field_name = field_name or _fget.__name__
|
|
59
|
-
"""The name of the field
|
|
59
|
+
"""The name of the field the {cls} is bound to."""
|
|
60
60
|
|
|
61
61
|
functools.update_wrapper(self, self.__wrapped__)
|
|
62
62
|
|
|
@@ -65,7 +65,7 @@ class ASyncDescriptor(ModifiedMixin, Generic[I, P, T]):
|
|
|
65
65
|
|
|
66
66
|
def __set_name__(self, owner, name):
|
|
67
67
|
"""
|
|
68
|
-
Set the field name when the
|
|
68
|
+
Set the field name when the {cls} is assigned to a class.
|
|
69
69
|
|
|
70
70
|
Args:
|
|
71
71
|
owner: The class owning this descriptor.
|
|
@@ -211,3 +211,9 @@ class ASyncDescriptor(ModifiedMixin, Generic[I, P, T]):
|
|
|
211
211
|
The sum of the results.
|
|
212
212
|
"""
|
|
213
213
|
return await self.map(*instances, concurrency=concurrency, name=name, **kwargs).sum(pop=True, sync=False)
|
|
214
|
+
|
|
215
|
+
def __init_subclass__(cls) -> None:
|
|
216
|
+
for attr in cls.__dict__.values():
|
|
217
|
+
if attr.__doc__ and "{cls}" in attr.__doc__:
|
|
218
|
+
attr.__doc__ = attr.__doc__.replace("{cls}", f":class:`{cls.__name__}`")
|
|
219
|
+
return super().__init_subclass__()
|
a_sync/a_sync/method.py
CHANGED
|
@@ -31,7 +31,7 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
33
|
__wrapped__: AnyFn[P, T]
|
|
34
|
-
"""The
|
|
34
|
+
"""The unbound function which will be bound to an instance when :meth:`__get__` is called."""
|
|
35
35
|
|
|
36
36
|
async def __call__(self, instance: I, *args: P.args, **kwargs: P.kwargs) -> T:
|
|
37
37
|
"""
|
|
@@ -267,6 +267,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
267
267
|
__weakself__: "weakref.ref[I]"
|
|
268
268
|
"A weak reference to the instance the function is bound to."
|
|
269
269
|
|
|
270
|
+
__wrapped__: AnyFn[Concatenate[I, P], T]
|
|
271
|
+
"""The original unbound method that was wrapped."""
|
|
272
|
+
|
|
270
273
|
__slots__ = "_is_async_def", "__weakself__"
|
|
271
274
|
|
|
272
275
|
def __init__(
|
a_sync/a_sync/property.py
CHANGED
|
@@ -3,6 +3,7 @@ import functools
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
import async_property as ap # type: ignore [import]
|
|
6
|
+
from typing_extensions import Unpack
|
|
6
7
|
|
|
7
8
|
from a_sync import _smart, exceptions
|
|
8
9
|
from a_sync._typing import *
|
|
@@ -29,7 +30,7 @@ class _ASyncPropertyDescriptorBase(ASyncDescriptor[I, Tuple[()], T]):
|
|
|
29
30
|
self,
|
|
30
31
|
_fget: AsyncGetterFunction[I, T],
|
|
31
32
|
field_name: Optional[str] = None,
|
|
32
|
-
**modifiers:
|
|
33
|
+
**modifiers: Unpack[ModifierKwargs],
|
|
33
34
|
) -> None:
|
|
34
35
|
super().__init__(_fget, field_name, **modifiers)
|
|
35
36
|
self.hidden_method_name = f"__{self.field_name}__"
|
|
@@ -390,7 +391,14 @@ def a_sync_cached_property( # type: ignore [misc]
|
|
|
390
391
|
|
|
391
392
|
@final
|
|
392
393
|
class HiddenMethod(ASyncBoundMethodAsyncDefault[I, Tuple[()], T]):
|
|
393
|
-
def __init__(
|
|
394
|
+
def __init__(
|
|
395
|
+
self,
|
|
396
|
+
instance: I,
|
|
397
|
+
unbound: AnyFn[Concatenate[I, P], T],
|
|
398
|
+
async_def: bool,
|
|
399
|
+
field_name: str,
|
|
400
|
+
**modifiers: Unpack[ModifierKwargs],
|
|
401
|
+
) -> None:
|
|
394
402
|
super().__init__(instance, unbound, async_def, **modifiers)
|
|
395
403
|
self.__name__ = field_name
|
|
396
404
|
def __repr__(self) -> str:
|
|
@@ -406,6 +414,30 @@ class HiddenMethod(ASyncBoundMethodAsyncDefault[I, Tuple[()], T]):
|
|
|
406
414
|
|
|
407
415
|
@final
|
|
408
416
|
class HiddenMethodDescriptor(ASyncMethodDescriptorAsyncDefault[I, Tuple[()], T]):
|
|
417
|
+
def __init__(
|
|
418
|
+
self,
|
|
419
|
+
_fget: AnyFn[Concatenate[I, P], Awaitable[T]],
|
|
420
|
+
field_name: Optional[str] = None,
|
|
421
|
+
**modifiers: Unpack[ModifierKwargs],
|
|
422
|
+
) -> None:
|
|
423
|
+
"""
|
|
424
|
+
Initialize the HiddenMethodDescriptor.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
_fget: The function to be wrapped.
|
|
428
|
+
field_name: Optional name for the field. If not provided, the function's name will be used.
|
|
429
|
+
**modifiers: Additional modifier arguments.
|
|
430
|
+
|
|
431
|
+
Raises:
|
|
432
|
+
ValueError: If _fget is not callable.
|
|
433
|
+
"""
|
|
434
|
+
super().__init__(_fget, field_name, **modifiers)
|
|
435
|
+
if self.__doc__ is None:
|
|
436
|
+
self.__doc__ = f"A :class:`HiddenMethodDescriptor` for :meth:`{self.__wrapped__.__qualname__}`."
|
|
437
|
+
elif not self.__doc__:
|
|
438
|
+
self.__doc__ += f"A :class:`HiddenMethodDescriptor` for :meth:`{self.__wrapped__.__qualname__}`."
|
|
439
|
+
if self.__wrapped__.__doc__:
|
|
440
|
+
self.__doc__ += f"\n\nThe original docstring for :meth:`~{self.__wrapped__.__qualname__}` is shown below:\n\n{self.__wrapped__.__doc__}"
|
|
409
441
|
def __get__(self, instance: I, owner: Type[I]) -> HiddenMethod[I, T]:
|
|
410
442
|
if instance is None:
|
|
411
443
|
return self
|
a_sync/iter.py
CHANGED
|
@@ -43,27 +43,29 @@ class _AwaitableAsyncIterableMixin(AsyncIterable[T]):
|
|
|
43
43
|
```
|
|
44
44
|
"""
|
|
45
45
|
__wrapped__: AsyncIterable[T]
|
|
46
|
-
|
|
47
|
-
def __init_subclass__(cls, **kwargs) -> None:
|
|
48
|
-
new = "When awaited, a list of all elements will be returned."
|
|
49
|
-
if cls.__doc__ is None:
|
|
50
|
-
cls.__doc__ = new
|
|
51
|
-
else:
|
|
52
|
-
cls.__doc__ += f"\n\n{new}"
|
|
53
|
-
return super().__init_subclass__(**kwargs)
|
|
54
46
|
|
|
55
47
|
def __await__(self) -> Generator[Any, Any, List[T]]:
|
|
56
|
-
"""
|
|
48
|
+
"""
|
|
49
|
+
Asynchronously iterate through the {cls} and return all objects.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
A list of the objects yielded by the {cls}.
|
|
53
|
+
"""
|
|
57
54
|
return self._materialized.__await__()
|
|
58
55
|
|
|
59
56
|
@property
|
|
60
57
|
def materialized(self) -> List[T]:
|
|
61
|
-
"""
|
|
58
|
+
"""
|
|
59
|
+
Synchronously iterate through the {cls} and return all objects.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
A list of the objects yielded by the {cls}.
|
|
63
|
+
"""
|
|
62
64
|
return _helpers._await(self._materialized)
|
|
63
65
|
|
|
64
66
|
def sort(self, *, key: SortKey[T] = None, reverse: bool = False) -> "ASyncSorter[T]":
|
|
65
67
|
"""
|
|
66
|
-
|
|
68
|
+
Sort the contents of the {cls}.
|
|
67
69
|
|
|
68
70
|
Args:
|
|
69
71
|
key (optional): A function of one argument that is used to extract a comparison key from each list element. If None, the elements themselves will be sorted. Defaults to None.
|
|
@@ -76,21 +78,42 @@ class _AwaitableAsyncIterableMixin(AsyncIterable[T]):
|
|
|
76
78
|
|
|
77
79
|
def filter(self, function: ViewFn[T]) -> "ASyncFilter[T]":
|
|
78
80
|
"""
|
|
79
|
-
Filters the contents of the
|
|
81
|
+
Filters the contents of the {cls} based on a function.
|
|
80
82
|
|
|
81
83
|
Args:
|
|
82
84
|
function: A function that returns a boolean that indicates if an item should be included in the filtered result. Can be sync or async.
|
|
83
85
|
|
|
84
86
|
Returns:
|
|
85
|
-
An instance of :class:`~ASyncFilter` that
|
|
87
|
+
An instance of :class:`~ASyncFilter` that yields the filtered objects from the {cls}.
|
|
86
88
|
"""
|
|
87
89
|
return ASyncFilter(function, self)
|
|
88
90
|
|
|
89
91
|
@async_cached_property
|
|
90
92
|
async def _materialized(self) -> List[T]:
|
|
91
|
-
"""
|
|
93
|
+
"""
|
|
94
|
+
Asynchronously iterate through the {cls} and return all objects.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
A list of the objects yielded by the {cls}.
|
|
98
|
+
"""
|
|
92
99
|
return [obj async for obj in self]
|
|
93
100
|
|
|
101
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
102
|
+
new = "When awaited, a list of all elements will be returned."
|
|
103
|
+
|
|
104
|
+
# modify the class docstring
|
|
105
|
+
if cls.__doc__ is None:
|
|
106
|
+
cls.__doc__ = new
|
|
107
|
+
else:
|
|
108
|
+
cls.__doc__ += f"\n\n{new}"
|
|
109
|
+
|
|
110
|
+
# format the member docstrings
|
|
111
|
+
for attr in cls.__dict__.values():
|
|
112
|
+
if attr.__doc__ and "{cls}" in attr.__doc__:
|
|
113
|
+
attr.__doc__ = attr.__doc__.replace("{cls}", f":class:`{cls.__name__}`")
|
|
114
|
+
|
|
115
|
+
return super().__init_subclass__(**kwargs)
|
|
116
|
+
|
|
94
117
|
__slots__ = '__async_property__',
|
|
95
118
|
|
|
96
119
|
class ASyncIterable(_AwaitableAsyncIterableMixin[T], Iterable[T]):
|
|
@@ -128,14 +151,20 @@ AsyncGenFunc = Callable[P, Union[AsyncGenerator[T, None], AsyncIterator[T]]]
|
|
|
128
151
|
|
|
129
152
|
class ASyncIterator(_AwaitableAsyncIterableMixin[T], Iterator[T]):
|
|
130
153
|
"""
|
|
131
|
-
|
|
132
|
-
A hybrid Iterator/AsyncIterator implementation that bridges the gap between synchronous and asynchronous iteration. This class provides a unified interface for iteration that can seamlessly operate in both synchronous (`for` loop) and asynchronous (`async for` loop) contexts. It allows the wrapping of asynchronous iterable objects or async generator functions, making them usable in synchronous code without explicitly managing event loops or asynchronous context switches.
|
|
154
|
+
A hybrid Iterator/AsyncIterator implementation that bridges the gap between synchronous and asynchronous iteration. This class provides a unified interface for iteration that can seamlessly operate in both synchronous (`for` loop) and asynchronous (`async for` loop) contexts. It allows the wrapping of asynchronous iterable objects or async generator functions, making them usable in synchronous code without explicitly managing event loops or asynchronous context switches.
|
|
133
155
|
|
|
134
|
-
|
|
156
|
+
By implementing both `__next__` and `__anext__` methods, ASyncIterator enables objects to be iterated using standard iteration protocols while internally managing the complexities of asynchronous iteration. This design simplifies the use of asynchronous iterables in environments or frameworks that are not inherently asynchronous, such as standard synchronous functions or older codebases being gradually migrated to asynchronous IO.
|
|
135
157
|
|
|
136
|
-
|
|
158
|
+
This class is particularly useful for library developers seeking to provide a consistent iteration interface across synchronous and asynchronous code, reducing the cognitive load on users and promoting code reusability and simplicity.
|
|
137
159
|
"""
|
|
160
|
+
|
|
138
161
|
def __next__(self) -> T:
|
|
162
|
+
"""
|
|
163
|
+
Synchronously fetch the next item from the {cls}.
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
:class:`StopIteration`: Once all items have been fetched from the {cls}.
|
|
167
|
+
"""
|
|
139
168
|
try:
|
|
140
169
|
return asyncio.get_event_loop().run_until_complete(self.__anext__())
|
|
141
170
|
except StopAsyncIteration as e:
|
|
@@ -164,24 +193,32 @@ class ASyncIterator(_AwaitableAsyncIterableMixin[T], Iterator[T]):
|
|
|
164
193
|
if not isinstance(async_iterator, AsyncIterator):
|
|
165
194
|
raise TypeError(f"`async_iterator` must be an AsyncIterator. You passed {async_iterator}")
|
|
166
195
|
self.__wrapped__ = async_iterator
|
|
167
|
-
"The wrapped
|
|
196
|
+
"The wrapped :class:`AsyncIterator`."
|
|
168
197
|
|
|
169
198
|
async def __anext__(self) -> T:
|
|
170
|
-
"
|
|
199
|
+
"""
|
|
200
|
+
Asynchronously fetch the next item from the {cls}.
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
:class:`StopAsyncIteration`: Once all items have been fetched from the {cls}.
|
|
204
|
+
"""
|
|
171
205
|
return await self.__wrapped__.__anext__()
|
|
172
206
|
|
|
173
|
-
def
|
|
174
|
-
"
|
|
207
|
+
def __iter__(self) -> Self:
|
|
208
|
+
"Return the {cls} for iteration."
|
|
209
|
+
return self
|
|
210
|
+
|
|
211
|
+
def __aiter__(self) -> Self:
|
|
212
|
+
"Return the {cls} for aiteration."
|
|
175
213
|
return self
|
|
176
214
|
|
|
177
215
|
class ASyncGeneratorFunction(Generic[P, T]):
|
|
178
216
|
"""
|
|
179
|
-
|
|
180
|
-
Encapsulates an asynchronous generator function, providing a mechanism to use it as an asynchronous iterator with enhanced capabilities. This class wraps an async generator function, allowing it to be called with parameters and return an :class:`~ASyncIterator` object. It is particularly useful for situations where an async generator function needs to be used in a manner that is consistent with both synchronous and asynchronous execution contexts.
|
|
217
|
+
Encapsulates an asynchronous generator function, providing a mechanism to use it as an asynchronous iterator with enhanced capabilities. This class wraps an async generator function, allowing it to be called with parameters and return an :class:`~ASyncIterator` object. It is particularly useful for situations where an async generator function needs to be used in a manner that is consistent with both synchronous and asynchronous execution contexts.
|
|
181
218
|
|
|
182
|
-
|
|
219
|
+
The ASyncGeneratorFunction class supports dynamic binding to instances, enabling it to be used as a method on class instances. When accessed as a descriptor, it automatically handles the binding to the instance, thereby allowing the wrapped async generator function to be invoked with instance context ('self') automatically provided. This feature is invaluable for designing classes that need to expose asynchronous generators as part of their interface while maintaining the ease of use and calling semantics similar to regular methods.
|
|
183
220
|
|
|
184
|
-
|
|
221
|
+
By providing a unified interface to asynchronous generator functions, this class facilitates the creation of APIs that are flexible and easy to use in a wide range of asynchronous programming scenarios. It abstracts away the complexities involved in managing asynchronous generator lifecycles and invocation semantics, making it easier for developers to integrate asynchronous iteration patterns into their applications.
|
|
185
222
|
"""
|
|
186
223
|
|
|
187
224
|
_cache_handle: asyncio.TimerHandle
|
|
@@ -191,11 +228,20 @@ class ASyncGeneratorFunction(Generic[P, T]):
|
|
|
191
228
|
"A weak reference to the instance the function is bound to, if any."
|
|
192
229
|
|
|
193
230
|
def __init__(self, async_gen_func: AsyncGenFunc[P, T], instance: Any = None) -> None:
|
|
194
|
-
"
|
|
231
|
+
"""
|
|
232
|
+
Initializes the ASyncGeneratorFunction with the given async generator function and optionally an instance.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
async_gen_func: The async generator function to wrap.
|
|
236
|
+
instance (optional): The object to bind to the function, if applicable.
|
|
237
|
+
"""
|
|
238
|
+
|
|
195
239
|
self.field_name = async_gen_func.__name__
|
|
196
240
|
"The name of the async generator function."
|
|
241
|
+
|
|
197
242
|
self.__wrapped__ = async_gen_func
|
|
198
243
|
"The actual async generator function."
|
|
244
|
+
|
|
199
245
|
if instance is not None:
|
|
200
246
|
self._cache_handle = self.__get_cache_handle(instance)
|
|
201
247
|
self.__weakself__ = weakref.ref(instance, self.__cancel_cache_handle)
|
|
@@ -205,7 +251,16 @@ class ASyncGeneratorFunction(Generic[P, T]):
|
|
|
205
251
|
return f"<{type(self).__name__} for {self.__wrapped__} at {hex(id(self))}>"
|
|
206
252
|
|
|
207
253
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> ASyncIterator[T]:
|
|
208
|
-
"
|
|
254
|
+
"""
|
|
255
|
+
Calls the wrapped async generator function with the given arguments and keyword arguments, returning an :class:`ASyncIterator`.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
*args: Positional arguments for the function.
|
|
259
|
+
**kwargs: Keyword arguments for the function.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
An :class:`ASyncIterator` wrapping the :class:`AsyncIterator` returned from the wrapped function call.
|
|
263
|
+
"""
|
|
209
264
|
if self.__weakself__ is None:
|
|
210
265
|
return ASyncIterator(self.__wrapped__(*args, **kwargs))
|
|
211
266
|
return ASyncIterator(self.__wrapped__(self.__self__, *args, **kwargs))
|
|
@@ -257,7 +312,7 @@ class _ASyncView(ASyncIterator[T]):
|
|
|
257
312
|
iterable: AnyIterable[T],
|
|
258
313
|
) -> None:
|
|
259
314
|
"""
|
|
260
|
-
Initializes the
|
|
315
|
+
Initializes the {cls} with a function and an iterable.
|
|
261
316
|
|
|
262
317
|
Args:
|
|
263
318
|
function: A function to apply to the items in the iterable.
|
a_sync/utils/iterators.py
CHANGED
|
@@ -13,10 +13,9 @@ logger = logging.getLogger(__name__)
|
|
|
13
13
|
|
|
14
14
|
async def exhaust_iterator(iterator: AsyncIterator[T], *, queue: Optional[asyncio.Queue] = None) -> None:
|
|
15
15
|
"""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
This function is a utility to exhaust an async iterator, with an option to forward the iterated items to a provided asyncio.Queue. It's particularly useful when dealing with asynchronous operations that produce items to be consumed by other parts of an application, enabling a producer-consumer pattern.
|
|
16
|
+
Asynchronously iterates over items from the given async iterator and optionally places them into a queue.
|
|
17
|
+
|
|
18
|
+
This function is a utility to exhaust an async iterator, with an option to forward the iterated items to a provided asyncio.Queue. It's particularly useful when dealing with asynchronous operations that produce items to be consumed by other parts of an application, enabling a producer-consumer pattern.
|
|
20
19
|
|
|
21
20
|
Args:
|
|
22
21
|
iterator (AsyncIterator[T]): The async iterator to exhaust.
|
|
@@ -33,10 +32,9 @@ async def exhaust_iterator(iterator: AsyncIterator[T], *, queue: Optional[asynci
|
|
|
33
32
|
|
|
34
33
|
async def exhaust_iterators(iterators, *, queue: Optional[asyncio.Queue] = None, join: bool = False) -> None:
|
|
35
34
|
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
This function leverages asyncio.gather to concurrently exhaust multiple async iterators. It's useful in scenarios where items from multiple async sources need to be processed or collected together, supporting concurrent operations and efficient multitasking.
|
|
35
|
+
Asynchronously iterates over multiple async iterators concurrently and optionally places their items into a queue.
|
|
36
|
+
|
|
37
|
+
This function leverages asyncio.gather to concurrently exhaust multiple async iterators. It's useful in scenarios where items from multiple async sources need to be processed or collected together, supporting concurrent operations and efficient multitasking.
|
|
40
38
|
|
|
41
39
|
Args:
|
|
42
40
|
iterators: A sequence of async iterators to be exhausted concurrently.
|
|
@@ -93,12 +91,11 @@ def as_yielded(iterator0: AsyncIterator[T0], iterator1: AsyncIterator[T1]) -> As
|
|
|
93
91
|
def as_yielded(iterator0: AsyncIterator[T0], iterator1: AsyncIterator[T1], iterator2: AsyncIterator[T2], *iterators: AsyncIterator[T]) -> AsyncIterator[Union[T0, T1, T2, T]]:...
|
|
94
92
|
async def as_yielded(*iterators: AsyncIterator[T]) -> AsyncIterator[T]: # type: ignore [misc]
|
|
95
93
|
"""
|
|
96
|
-
|
|
97
|
-
Merges multiple async iterators into a single async iterator that yields items as they become available from any of the source iterators.
|
|
94
|
+
Merges multiple async iterators into a single async iterator that yields items as they become available from any of the source iterators.
|
|
98
95
|
|
|
99
|
-
|
|
96
|
+
This function is designed to streamline the handling of multiple asynchronous data streams by consolidating them into a single asynchronous iteration context. It enables concurrent fetching and processing of items from multiple sources, improving efficiency and simplifying code structure when dealing with asynchronous operations.
|
|
100
97
|
|
|
101
|
-
|
|
98
|
+
The merging process is facilitated by internally managing a queue where items from the source iterators are placed as they are fetched. This mechanism ensures that the merged stream of items is delivered in an order determined by the availability of items from the source iterators, rather than their original sequence.
|
|
102
99
|
|
|
103
100
|
Args:
|
|
104
101
|
*iterators: Variable length list of AsyncIterator objects to be merged.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
a_sync/ENVIRONMENT_VARIABLES.py,sha256=mbOTOeyDyc90OA0CcTNzaOHKm3YT3myanQvVcefdtBU,462
|
|
2
2
|
a_sync/__init__.py,sha256=iPrNPP5i2H02HmX050hz-XqAYwAwrlyh3hkXRegdy7E,2204
|
|
3
3
|
a_sync/_smart.py,sha256=mZ7zD8usbRG3dEjddwnz46gwFxcDjPri6na7vCPX9hw,6989
|
|
4
|
-
a_sync/_typing.py,sha256=
|
|
4
|
+
a_sync/_typing.py,sha256=GTCqBBgeCGoB_wLb0WoizBrrYf2a-2GXgK82CZQKP2E,5368
|
|
5
5
|
a_sync/aliases.py,sha256=kkv7JGdlJeyy2x8JauCy3D6spbYBCTMgNtC_QrT118s,213
|
|
6
6
|
a_sync/exceptions.py,sha256=0VHUEBgTVmaF8LIuFINCv1YCuC_GfCJgmwnPP3I9HRI,6597
|
|
7
7
|
a_sync/executor.py,sha256=cAlmCeKAw7dIOxeZLozWg69aWyyOvyXmYkraQyK-qDE,12984
|
|
8
8
|
a_sync/future.py,sha256=zQy3Gv1UvX399Yx5-W-ygxYZSS_C3aEhQlEz8gyoB90,26093
|
|
9
|
-
a_sync/iter.py,sha256=
|
|
9
|
+
a_sync/iter.py,sha256=qc0MobUDCxVvI0Q9C2JELDNK2XO5aOpG7YhOGzuCPEQ,20597
|
|
10
10
|
a_sync/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
a_sync/task.py,sha256=FEf788GSKzBCOqjtljlqKlisT5ZyK_kCa-d_-KTSuOc,28213
|
|
12
12
|
a_sync/a_sync/__init__.py,sha256=V93WFLhKbDR9oSegknq6ub-M85HT983eIt_Tov0Reos,1092
|
|
13
|
-
a_sync/a_sync/_descriptor.py,sha256=
|
|
13
|
+
a_sync/a_sync/_descriptor.py,sha256=jhcPnzJ3PJ4o7l_wf5DbmH-sKQxS14Yd1uh_riYq_rU,7851
|
|
14
14
|
a_sync/a_sync/_flags.py,sha256=2-97KHE-Hjb5RPnx4AU2h5TJ2nR7tBdnzqHWvkLgOs8,1669
|
|
15
15
|
a_sync/a_sync/_helpers.py,sha256=z6TRvqlXUdLKRyw0ZCZyzY6FvkNyoGt8_XgEGjV-UaU,1837
|
|
16
16
|
a_sync/a_sync/_kwargs.py,sha256=szblXLK1LF2S71LsLGQTCFM4v9E0xJP-rdkL6O2xKJo,1378
|
|
@@ -20,8 +20,8 @@ a_sync/a_sync/base.py,sha256=qE7p2nXmpwpMulCnZcBV1I5sXiWGtcmtAEZVrqAt0rc,7363
|
|
|
20
20
|
a_sync/a_sync/config.py,sha256=b9YDs3cjoyxiwxIEld78dyVWsv1rGZMLutJVQauT29Y,2764
|
|
21
21
|
a_sync/a_sync/decorator.py,sha256=s_KqDzIki3NvsXnjd9dlUnHgmOlM8HwcjOjl9rlzOK0,8424
|
|
22
22
|
a_sync/a_sync/function.py,sha256=94qtv62rgJmIOwwYLdaTth53HJ3a_VSR4dDnwqpg-PU,28643
|
|
23
|
-
a_sync/a_sync/method.py,sha256=
|
|
24
|
-
a_sync/a_sync/property.py,sha256=
|
|
23
|
+
a_sync/a_sync/method.py,sha256=Iq1FaklAzBavNHIR9FHwRVik1dAGlAPhOhsjMrWZtWU,23291
|
|
24
|
+
a_sync/a_sync/property.py,sha256=mIcYmcIpUM-RuYPlIa6_r3UXbplChf2GhwoOV8sTgb4,18366
|
|
25
25
|
a_sync/a_sync/singleton.py,sha256=dHFwuSkOYP58Dn_I6zciMpJmeG1ENMOjJ1j8lOFQrl0,1459
|
|
26
26
|
a_sync/a_sync/modifiers/__init__.py,sha256=0kOpApvcDIBr37645vY50aG6lIdccNG_IupZZsAawBM,1052
|
|
27
27
|
a_sync/a_sync/modifiers/limiter.py,sha256=WtMh-F_4O6kxAYGiCKTnTYu2RrPQNov3dDYB4OTigjk,1763
|
|
@@ -46,7 +46,7 @@ a_sync/primitives/locks/semaphore.py,sha256=oIFoIOj2KyBPWtWUJKcq0Las7nLpuu53BwoU
|
|
|
46
46
|
a_sync/sphinx/__init__.py,sha256=VcgVF_ea4HAVNxb8KXX-_fcLviBQGnN9OIRWaUjPhy4,50
|
|
47
47
|
a_sync/sphinx/ext.py,sha256=UjPf7s57mAOpzOSWyxv58pel022XADxUrnL-tRjZIvw,6586
|
|
48
48
|
a_sync/utils/__init__.py,sha256=MP2jX5G8-3WQSF3VxRNFQvbPFdlPPKBrd6rlcLqT9oM,3048
|
|
49
|
-
a_sync/utils/iterators.py,sha256=
|
|
49
|
+
a_sync/utils/iterators.py,sha256=5GGWSFrO_bAcCK3JHLOVlfMQCkWJpe_Qt01ru2olRm0,8769
|
|
50
50
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
51
|
tests/conftest.py,sha256=Q7w6vrh3acUxttLU7Qx35KQS8jeV4ENQ7wzerK0OfLU,57
|
|
52
52
|
tests/executor.py,sha256=quJtFDPFLkhPXrYVWYM1F4NJ1DCeG4XxMz9MLcyx5zg,239
|
|
@@ -67,8 +67,8 @@ tests/test_modified.py,sha256=H_Z98JNvy1Ze2Qae6Jgyo1gPqOGycVkwmGutrSmnQmk,247
|
|
|
67
67
|
tests/test_semaphore.py,sha256=pncCO3Y_xus9f85nCPY6Pr4WbUbHpNZNT5tBgwUAbZA,1628
|
|
68
68
|
tests/test_singleton.py,sha256=KGLLWr4eM3PHh_MBDubseTxAaS0r7Bddal2wY-qY4oA,539
|
|
69
69
|
tests/test_task.py,sha256=BpODWsy6I2LAZ4VZ4SGa4R6rly1U10gz0JjIPoW6GrI,7389
|
|
70
|
-
ez_a_sync-0.22.
|
|
71
|
-
ez_a_sync-0.22.
|
|
72
|
-
ez_a_sync-0.22.
|
|
73
|
-
ez_a_sync-0.22.
|
|
74
|
-
ez_a_sync-0.22.
|
|
70
|
+
ez_a_sync-0.22.7.dist-info/LICENSE.txt,sha256=1on6-17OUMlja6vSPTcmlmeT_DwujCZJijYxaplBvZk,1075
|
|
71
|
+
ez_a_sync-0.22.7.dist-info/METADATA,sha256=IR_xj3u9zGDn-DR4t58vqSwv_MNw69GOzaRTApocdTY,532
|
|
72
|
+
ez_a_sync-0.22.7.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
|
73
|
+
ez_a_sync-0.22.7.dist-info/top_level.txt,sha256=GVK_7kp7dgBLeHp84iIQdsJmiXnrXd-5sIf2x0Q-VKc,13
|
|
74
|
+
ez_a_sync-0.22.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|