python-iterutils 0.2.10.2__py3-none-any.whl → 0.3.1__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.
- iterutils/__init__.py +4 -1495
- iterutils/dynamic.py +69 -0
- iterutils/gen_step.py +447 -0
- iterutils/misc.py +1014 -0
- {python_iterutils-0.2.10.2.dist-info → python_iterutils-0.3.1.dist-info}/METADATA +5 -4
- python_iterutils-0.3.1.dist-info/RECORD +9 -0
- {python_iterutils-0.2.10.2.dist-info → python_iterutils-0.3.1.dist-info}/WHEEL +1 -1
- python_iterutils-0.2.10.2.dist-info/RECORD +0 -6
- {python_iterutils-0.2.10.2.dist-info → python_iterutils-0.3.1.dist-info}/licenses/LICENSE +0 -0
iterutils/__init__.py
CHANGED
|
@@ -2,1499 +2,8 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
5
|
-
__version__ = (0,
|
|
6
|
-
__all__ = [
|
|
7
|
-
"Yield", "YieldFrom", "GenStep", "GenStepIter", "iterable",
|
|
8
|
-
"async_iterable", "run_gen_step", "run_gen_step_iter",
|
|
9
|
-
"as_gen_step", "as_gen_step_iter", "split_cm", "with_iter_next",
|
|
10
|
-
"map", "filter", "reduce", "zip", "chain", "chain_from_iterable",
|
|
11
|
-
"chunked", "foreach", "async_foreach", "through", "async_through",
|
|
12
|
-
"flatten", "async_flatten", "collect", "async_collect",
|
|
13
|
-
"group_collect", "async_group_collect", "iter_unique",
|
|
14
|
-
"async_iter_unique", "wrap_iter", "wrap_aiter", "peek_iter", "peek_aiter",
|
|
15
|
-
"acc_step", "cut_iter", "context", "backgroud_loop", "gen_startup",
|
|
16
|
-
"async_gen_startup", "do_iter", "do_aiter", "bfs_iter", "bfs_gen",
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
from asyncio import create_task, sleep as async_sleep
|
|
20
|
-
from builtins import map as _map, filter as _filter, zip as _zip
|
|
21
|
-
from collections import defaultdict, deque
|
|
22
|
-
from collections.abc import (
|
|
23
|
-
AsyncGenerator, AsyncIterable, AsyncIterator, Awaitable, Buffer,
|
|
24
|
-
Callable, Collection, Container, Coroutine, Generator, Iterable,
|
|
25
|
-
Iterator, Mapping, MutableMapping, MutableSet, MutableSequence,
|
|
26
|
-
Sequence, ValuesView,
|
|
27
|
-
)
|
|
28
|
-
from contextlib import (
|
|
29
|
-
asynccontextmanager, contextmanager, ExitStack, AsyncExitStack,
|
|
30
|
-
AbstractContextManager, AbstractAsyncContextManager,
|
|
31
|
-
)
|
|
32
|
-
from copy import copy
|
|
33
|
-
from dataclasses import dataclass
|
|
34
|
-
from functools import update_wrapper
|
|
35
|
-
from itertools import batched, chain as _chain, pairwise
|
|
36
|
-
from inspect import iscoroutinefunction, signature
|
|
37
|
-
from sys import _getframe, exc_info
|
|
38
|
-
from _thread import start_new_thread
|
|
39
|
-
from time import sleep, time
|
|
40
|
-
from types import FrameType
|
|
41
|
-
from typing import (
|
|
42
|
-
cast, overload, Any, AsyncContextManager, ContextManager, Literal,
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
from asynctools import (
|
|
46
|
-
async_filter, async_map, async_reduce, async_zip, async_batched,
|
|
47
|
-
ensure_async, ensure_aiter, async_chain, collect as async_collect,
|
|
48
|
-
)
|
|
49
|
-
from texttools import format_time
|
|
50
|
-
from undefined import undefined
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@dataclass(slots=True, frozen=True, unsafe_hash=True)
|
|
54
|
-
class Yield:
|
|
55
|
-
"""专供 `run_gen_step_iter`,说明值需要 yield 给用户
|
|
56
|
-
"""
|
|
57
|
-
value: Any
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@dataclass(slots=True, frozen=True, unsafe_hash=True)
|
|
61
|
-
class YieldFrom:
|
|
62
|
-
"""专供 `run_gen_step_iter`,说明值需要解包后逐个 yield 给用户
|
|
63
|
-
"""
|
|
64
|
-
value: Any
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@dataclass(slots=True, frozen=True, unsafe_hash=True)
|
|
68
|
-
class GenStep:
|
|
69
|
-
"""专供 `run_gen_step` 和 `run_gen_step_iter`,说明值需要进一步提取
|
|
70
|
-
"""
|
|
71
|
-
value: Generator
|
|
72
|
-
max_depth: int = 0
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
@dataclass(slots=True, frozen=True, unsafe_hash=True)
|
|
76
|
-
class GenStepIter:
|
|
77
|
-
"""专供 `run_gen_step_iter`,说明值需要进一步提取
|
|
78
|
-
"""
|
|
79
|
-
value: Generator
|
|
80
|
-
max_depth: int = 0
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
iterable = Iterable.__instancecheck__
|
|
84
|
-
async_iterable = AsyncIterable.__instancecheck__
|
|
85
|
-
isawaitable = Awaitable.__instancecheck__
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def _coalesce(vals, default=None):
|
|
89
|
-
for val in vals:
|
|
90
|
-
if val is not None:
|
|
91
|
-
return val
|
|
92
|
-
return default
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@overload
|
|
96
|
-
def _get_async(back: int = 2, /, *, default: Literal[False] = False) -> bool:
|
|
97
|
-
...
|
|
98
|
-
@overload
|
|
99
|
-
def _get_async[T](back: int = 2, /, *, default: T) -> bool | T:
|
|
100
|
-
...
|
|
101
|
-
def _get_async[T](back: int = 2, /, *, default: Literal[False] | T = False) -> bool | T:
|
|
102
|
-
"""往上查找,从最近的调用栈的命名空间中获取 `async_` 的值
|
|
103
|
-
"""
|
|
104
|
-
def iter_frams(f: None | FrameType = _getframe(back)):
|
|
105
|
-
while f:
|
|
106
|
-
yield f.f_locals.get("async_")
|
|
107
|
-
f = f.f_back
|
|
108
|
-
return _coalesce(iter_frams(), default)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def _run_gen_step(
|
|
112
|
-
gen: Generator,
|
|
113
|
-
/,
|
|
114
|
-
drive_generator: int = 0,
|
|
115
|
-
):
|
|
116
|
-
send = gen.send
|
|
117
|
-
throw = gen.throw
|
|
118
|
-
dgen = drive_generator if drive_generator < 0 else drive_generator - 1
|
|
119
|
-
try:
|
|
120
|
-
value: Any = send(None)
|
|
121
|
-
while True:
|
|
122
|
-
try:
|
|
123
|
-
if isinstance(value, GenStep):
|
|
124
|
-
value = _run_gen_step(value.value, value.max_depth)
|
|
125
|
-
elif drive_generator and isinstance(value, Generator):
|
|
126
|
-
value = _run_gen_step(value, dgen)
|
|
127
|
-
except BaseException as e:
|
|
128
|
-
value = throw(e)
|
|
129
|
-
else:
|
|
130
|
-
value = send(value)
|
|
131
|
-
except StopIteration as e:
|
|
132
|
-
value = e.value
|
|
133
|
-
if isinstance(value, GenStep):
|
|
134
|
-
value = _run_gen_step(value.value, value.max_depth)
|
|
135
|
-
elif drive_generator and isinstance(value, Generator):
|
|
136
|
-
value = _run_gen_step(value, dgen)
|
|
137
|
-
return value
|
|
138
|
-
finally:
|
|
139
|
-
gen.close()
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
async def _run_gen_step_async(
|
|
143
|
-
gen: Generator,
|
|
144
|
-
/,
|
|
145
|
-
drive_generator: int = 0,
|
|
146
|
-
):
|
|
147
|
-
send = gen.send
|
|
148
|
-
throw = gen.throw
|
|
149
|
-
dgen = drive_generator if drive_generator < 0 else drive_generator - 1
|
|
150
|
-
try:
|
|
151
|
-
value: Any = send(None)
|
|
152
|
-
while True:
|
|
153
|
-
try:
|
|
154
|
-
if isawaitable(value):
|
|
155
|
-
value = await value
|
|
156
|
-
elif isinstance(value, GenStep):
|
|
157
|
-
value = await _run_gen_step_async(value.value, value.max_depth)
|
|
158
|
-
elif drive_generator and isinstance(value, Generator):
|
|
159
|
-
value = await _run_gen_step_async(value, dgen)
|
|
160
|
-
except BaseException as e:
|
|
161
|
-
value = throw(e)
|
|
162
|
-
else:
|
|
163
|
-
value = send(value)
|
|
164
|
-
except StopIteration as e:
|
|
165
|
-
value = e.value
|
|
166
|
-
if isawaitable(value):
|
|
167
|
-
value = await value
|
|
168
|
-
elif isinstance(value, GenStep):
|
|
169
|
-
value = await _run_gen_step_async(value.value, value.max_depth)
|
|
170
|
-
elif drive_generator and isinstance(value, Generator):
|
|
171
|
-
value = await _run_gen_step_async(value, dgen)
|
|
172
|
-
return value
|
|
173
|
-
finally:
|
|
174
|
-
gen.close()
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def run_gen_step[**Args](
|
|
178
|
-
gen_step: Generator | Callable[Args, Generator],
|
|
179
|
-
async_: None | Literal[False, True] = None,
|
|
180
|
-
/,
|
|
181
|
-
*args: Args.args,
|
|
182
|
-
**kwds: Args.kwargs,
|
|
183
|
-
):
|
|
184
|
-
"""驱动生成器运行,并返回其结果
|
|
185
|
-
"""
|
|
186
|
-
if async_ is None:
|
|
187
|
-
async_ = _get_async()
|
|
188
|
-
if not isinstance(gen_step, Generator):
|
|
189
|
-
params = signature(gen_step).parameters
|
|
190
|
-
if ((param := params.get("async_")) and
|
|
191
|
-
(param.kind in (param.POSITIONAL_OR_KEYWORD, param.KEYWORD_ONLY))
|
|
192
|
-
):
|
|
193
|
-
kwds.setdefault("async_", async_)
|
|
194
|
-
gen_step = gen_step(*args, **kwds)
|
|
195
|
-
if async_:
|
|
196
|
-
return _run_gen_step_async(gen_step)
|
|
197
|
-
else:
|
|
198
|
-
return _run_gen_step(gen_step)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def _run_gen_step_iter(
|
|
202
|
-
gen: Generator,
|
|
203
|
-
/,
|
|
204
|
-
drive_generator: int = 0,
|
|
205
|
-
) -> Iterator:
|
|
206
|
-
send = gen.send
|
|
207
|
-
throw = gen.throw
|
|
208
|
-
dgen = drive_generator if drive_generator < 0 else drive_generator - 1
|
|
209
|
-
try:
|
|
210
|
-
value: Any = send(None)
|
|
211
|
-
while True:
|
|
212
|
-
try:
|
|
213
|
-
val_type = type(value)
|
|
214
|
-
if issubclass(val_type, (Yield, YieldFrom)):
|
|
215
|
-
value = value.value
|
|
216
|
-
if isinstance(value, GenStepIter):
|
|
217
|
-
yield from _run_gen_step_iter(value.value, value.max_depth)
|
|
218
|
-
else:
|
|
219
|
-
if isinstance(value, GenStep):
|
|
220
|
-
value = _run_gen_step(value.value, value.max_depth)
|
|
221
|
-
elif drive_generator and isinstance(value, Generator):
|
|
222
|
-
value = _run_gen_step(value, dgen)
|
|
223
|
-
if val_type is Yield:
|
|
224
|
-
yield value
|
|
225
|
-
elif val_type is YieldFrom:
|
|
226
|
-
yield from value
|
|
227
|
-
except BaseException as e:
|
|
228
|
-
value = throw(e)
|
|
229
|
-
else:
|
|
230
|
-
value = send(value)
|
|
231
|
-
except StopIteration as e:
|
|
232
|
-
value = e.value
|
|
233
|
-
val_type = type(value)
|
|
234
|
-
if issubclass(val_type, (Yield, YieldFrom)):
|
|
235
|
-
value = value.value
|
|
236
|
-
elif isinstance(value, GenStepIter):
|
|
237
|
-
yield from _run_gen_step_iter(value.value, value.max_depth)
|
|
238
|
-
elif isinstance(value, GenStep):
|
|
239
|
-
value = _run_gen_step(value.value, value.max_depth)
|
|
240
|
-
elif drive_generator and isinstance(value, Generator):
|
|
241
|
-
value = _run_gen_step(value, dgen)
|
|
242
|
-
if val_type is Yield:
|
|
243
|
-
yield value
|
|
244
|
-
elif val_type is YieldFrom:
|
|
245
|
-
yield from value
|
|
246
|
-
finally:
|
|
247
|
-
gen.close()
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
async def _run_gen_step_async_iter(
|
|
251
|
-
gen: Generator,
|
|
252
|
-
/,
|
|
253
|
-
drive_generator: int = 0,
|
|
254
|
-
) -> AsyncIterator:
|
|
255
|
-
send = gen.send
|
|
256
|
-
throw = gen.throw
|
|
257
|
-
dgen = drive_generator if drive_generator < 0 else drive_generator - 1
|
|
258
|
-
try:
|
|
259
|
-
value: Any = send(None)
|
|
260
|
-
while True:
|
|
261
|
-
try:
|
|
262
|
-
val_type = type(value)
|
|
263
|
-
if issubclass(val_type, (Yield, YieldFrom)):
|
|
264
|
-
value = value.value
|
|
265
|
-
if isawaitable(value):
|
|
266
|
-
value = await value
|
|
267
|
-
elif isinstance(value, GenStepIter):
|
|
268
|
-
async for el in _run_gen_step_async_iter(value.value, value.max_depth):
|
|
269
|
-
yield el
|
|
270
|
-
elif isinstance(value, GenStep):
|
|
271
|
-
value = await _run_gen_step_async(value.value, value.max_depth)
|
|
272
|
-
elif drive_generator and isinstance(value, Generator):
|
|
273
|
-
value = await _run_gen_step_async(value, dgen)
|
|
274
|
-
if val_type is Yield:
|
|
275
|
-
yield value
|
|
276
|
-
elif val_type is YieldFrom:
|
|
277
|
-
if isinstance(value, AsyncIterable):
|
|
278
|
-
async for el in value:
|
|
279
|
-
yield el
|
|
280
|
-
else:
|
|
281
|
-
for el in value:
|
|
282
|
-
yield el
|
|
283
|
-
except BaseException as e:
|
|
284
|
-
value = throw(e)
|
|
285
|
-
else:
|
|
286
|
-
value = send(value)
|
|
287
|
-
except StopIteration as e:
|
|
288
|
-
value = e.value
|
|
289
|
-
val_type = type(value)
|
|
290
|
-
if issubclass(val_type, (Yield, YieldFrom)):
|
|
291
|
-
value = value.value
|
|
292
|
-
if isawaitable(value):
|
|
293
|
-
value = await value
|
|
294
|
-
if isinstance(value, GenStepIter):
|
|
295
|
-
async for el in _run_gen_step_async_iter(value.value, value.max_depth):
|
|
296
|
-
yield el
|
|
297
|
-
else:
|
|
298
|
-
if isinstance(value, GenStep):
|
|
299
|
-
value = await _run_gen_step_async(value.value, value.max_depth)
|
|
300
|
-
elif drive_generator and isinstance(value, Generator):
|
|
301
|
-
value = await _run_gen_step_async(value, dgen)
|
|
302
|
-
if val_type is Yield:
|
|
303
|
-
yield value
|
|
304
|
-
elif val_type is YieldFrom:
|
|
305
|
-
if isinstance(value, AsyncIterable):
|
|
306
|
-
async for el in value:
|
|
307
|
-
yield el
|
|
308
|
-
else:
|
|
309
|
-
for el in value:
|
|
310
|
-
yield el
|
|
311
|
-
finally:
|
|
312
|
-
gen.close()
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
@overload
|
|
316
|
-
def run_gen_step_iter[**Args](
|
|
317
|
-
gen_step: Generator | Callable[Args, Generator],
|
|
318
|
-
async_: None = None,
|
|
319
|
-
/,
|
|
320
|
-
*args: Args.args,
|
|
321
|
-
**kwds: Args.kwargs,
|
|
322
|
-
) -> Iterator | AsyncIterator:
|
|
323
|
-
...
|
|
324
|
-
@overload
|
|
325
|
-
def run_gen_step_iter[**Args](
|
|
326
|
-
gen_step: Generator | Callable[Args, Generator],
|
|
327
|
-
async_: Literal[False] = False,
|
|
328
|
-
/,
|
|
329
|
-
*args: Args.args,
|
|
330
|
-
**kwds: Args.kwargs,
|
|
331
|
-
) -> Iterator:
|
|
332
|
-
...
|
|
333
|
-
@overload
|
|
334
|
-
def run_gen_step_iter[**Args](
|
|
335
|
-
gen_step: Generator | Callable[Args, Generator],
|
|
336
|
-
async_: Literal[True],
|
|
337
|
-
/,
|
|
338
|
-
*args: Args.args,
|
|
339
|
-
**kwds: Args.kwargs,
|
|
340
|
-
) -> AsyncIterator:
|
|
341
|
-
...
|
|
342
|
-
def run_gen_step_iter[**Args](
|
|
343
|
-
gen_step: Generator | Callable[Args, Generator],
|
|
344
|
-
async_: None | Literal[False, True] = None,
|
|
345
|
-
/,
|
|
346
|
-
*args: Args.args,
|
|
347
|
-
**kwds: Args.kwargs,
|
|
348
|
-
) -> Iterator | AsyncIterator:
|
|
349
|
-
"""驱动生成器运行,并从中返回可迭代而出的值
|
|
350
|
-
"""
|
|
351
|
-
if async_ is None:
|
|
352
|
-
async_ = _get_async()
|
|
353
|
-
if not isinstance(gen_step, Generator):
|
|
354
|
-
params = signature(gen_step).parameters
|
|
355
|
-
if ((param := params.get("async_")) and
|
|
356
|
-
(param.kind in (param.POSITIONAL_OR_KEYWORD, param.KEYWORD_ONLY))
|
|
357
|
-
):
|
|
358
|
-
kwds.setdefault("async_", async_)
|
|
359
|
-
gen_step = gen_step(*args, **kwds)
|
|
360
|
-
if async_:
|
|
361
|
-
return _run_gen_step_async_iter(gen_step)
|
|
362
|
-
else:
|
|
363
|
-
return _run_gen_step_iter(gen_step)
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
def as_gen_step[**Args](
|
|
367
|
-
gen_step: Callable[Args, Generator],
|
|
368
|
-
/,
|
|
369
|
-
) -> Callable[Args, Any]:
|
|
370
|
-
default_async = _get_async(default=None)
|
|
371
|
-
def wrapper(*args: Args.args, **kwds: Args.kwargs):
|
|
372
|
-
return run_gen_step(
|
|
373
|
-
gen_step,
|
|
374
|
-
_coalesce((
|
|
375
|
-
kwds.pop("async_", None),
|
|
376
|
-
_get_async(default=default_async),
|
|
377
|
-
)),
|
|
378
|
-
*args,
|
|
379
|
-
**kwds,
|
|
380
|
-
)
|
|
381
|
-
return wrapper
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
def as_gen_step_iter[**Args](
|
|
385
|
-
gen_step: Callable[Args, Generator],
|
|
386
|
-
/,
|
|
387
|
-
) -> Callable[Args, Iterable | AsyncIterable]:
|
|
388
|
-
default_async = _get_async(default=None)
|
|
389
|
-
def wrapper(*args: Args.args, **kwds: Args.kwargs):
|
|
390
|
-
return run_gen_step_iter(
|
|
391
|
-
gen_step,
|
|
392
|
-
_coalesce((
|
|
393
|
-
kwds.pop("async_", None),
|
|
394
|
-
_get_async(default=default_async),
|
|
395
|
-
)),
|
|
396
|
-
*args,
|
|
397
|
-
**kwds,
|
|
398
|
-
)
|
|
399
|
-
return wrapper
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
@overload
|
|
403
|
-
def split_cm[T](
|
|
404
|
-
cm: AbstractContextManager[T],
|
|
405
|
-
/,
|
|
406
|
-
) -> tuple[Callable[[], T], Callable[[], Any]]:
|
|
407
|
-
...
|
|
408
|
-
@overload
|
|
409
|
-
def split_cm[T](
|
|
410
|
-
cm: AbstractAsyncContextManager[T],
|
|
411
|
-
/,
|
|
412
|
-
) -> tuple[Callable[[], Coroutine[Any, Any, T]], Callable[[], Coroutine]]:
|
|
413
|
-
...
|
|
414
|
-
def split_cm[T](
|
|
415
|
-
cm: AbstractContextManager[T] | AbstractAsyncContextManager[T],
|
|
416
|
-
/,
|
|
417
|
-
) -> (
|
|
418
|
-
tuple[Callable[[], T], Callable[[], Any]] |
|
|
419
|
-
tuple[Callable[[], Coroutine[Any, Any, T]], Callable[[], Coroutine]]
|
|
420
|
-
):
|
|
421
|
-
"""拆分上下文管理器,以供 `run_gen_step` 和 `run_gen_step_iter` 使用
|
|
422
|
-
|
|
423
|
-
.. code:: python
|
|
424
|
-
|
|
425
|
-
if async_:
|
|
426
|
-
async def process():
|
|
427
|
-
async with cm as obj:
|
|
428
|
-
do_what_you_want()
|
|
429
|
-
return process()
|
|
430
|
-
else:
|
|
431
|
-
with cm as obj:
|
|
432
|
-
do_what_you_want()
|
|
433
|
-
|
|
434
|
-
大概相当于
|
|
435
|
-
|
|
436
|
-
.. code:: python
|
|
437
|
-
|
|
438
|
-
def gen_step():
|
|
439
|
-
enter, exit = split_cm(cm)
|
|
440
|
-
obj = yield enter()
|
|
441
|
-
try:
|
|
442
|
-
do_what_you_want()
|
|
443
|
-
finally:
|
|
444
|
-
yield exit()
|
|
445
|
-
|
|
446
|
-
run_gen_step(gen_step, async_)
|
|
447
|
-
"""
|
|
448
|
-
if isinstance(cm, AbstractAsyncContextManager):
|
|
449
|
-
enter: Callable = cm.__aenter__
|
|
450
|
-
exit: Callable = cm.__aexit__
|
|
451
|
-
else:
|
|
452
|
-
enter = cm.__enter__
|
|
453
|
-
exit = cm.__exit__
|
|
454
|
-
return enter, lambda: exit(*exc_info())
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
@overload
|
|
458
|
-
def with_iter_next[T](
|
|
459
|
-
iterable: Iterable[T],
|
|
460
|
-
/,
|
|
461
|
-
) -> ContextManager[Callable[[], T]]:
|
|
462
|
-
...
|
|
463
|
-
@overload
|
|
464
|
-
def with_iter_next[T](
|
|
465
|
-
iterable: AsyncIterable[T],
|
|
466
|
-
/,
|
|
467
|
-
) -> ContextManager[Callable[[], Awaitable[T]]]:
|
|
468
|
-
...
|
|
469
|
-
@contextmanager
|
|
470
|
-
def with_iter_next[T](
|
|
471
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
472
|
-
/,
|
|
473
|
-
):
|
|
474
|
-
"""包装迭代器,以供 `run_gen_step` 和 `run_gen_step_iter` 使用
|
|
475
|
-
|
|
476
|
-
.. code:: python
|
|
477
|
-
|
|
478
|
-
if async_:
|
|
479
|
-
async def process():
|
|
480
|
-
async for e in iterable:
|
|
481
|
-
do_what_you_want()
|
|
482
|
-
return process()
|
|
483
|
-
else:
|
|
484
|
-
for e in iterable:
|
|
485
|
-
do_what_you_want()
|
|
486
|
-
|
|
487
|
-
大概相当于
|
|
488
|
-
|
|
489
|
-
.. code:: python
|
|
490
|
-
|
|
491
|
-
def gen_step():
|
|
492
|
-
with with_iter_next(iterable) as do_next:
|
|
493
|
-
while True:
|
|
494
|
-
e = yield do_next()
|
|
495
|
-
do_what_you_want()
|
|
496
|
-
|
|
497
|
-
run_gen_step(gen_step, async_)
|
|
498
|
-
"""
|
|
499
|
-
if isinstance(iterable, AsyncIterable):
|
|
500
|
-
try:
|
|
501
|
-
yield aiter(iterable).__anext__
|
|
502
|
-
except StopAsyncIteration:
|
|
503
|
-
pass
|
|
504
|
-
else:
|
|
505
|
-
try:
|
|
506
|
-
yield iter(iterable).__next__
|
|
507
|
-
except StopIteration:
|
|
508
|
-
pass
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
def map(
|
|
512
|
-
function: None | Callable,
|
|
513
|
-
iterable: Iterable | AsyncIterable,
|
|
514
|
-
/,
|
|
515
|
-
*iterables: Iterable | AsyncIterable,
|
|
516
|
-
threaded: bool = False,
|
|
517
|
-
):
|
|
518
|
-
"""
|
|
519
|
-
"""
|
|
520
|
-
if (
|
|
521
|
-
threaded or
|
|
522
|
-
iscoroutinefunction(function) or
|
|
523
|
-
isinstance(iterable, AsyncIterable) or
|
|
524
|
-
any(isinstance(i, AsyncIterable) for i in iterables)
|
|
525
|
-
):
|
|
526
|
-
if function is None:
|
|
527
|
-
if iterables:
|
|
528
|
-
return async_zip(iterable, *iterables, threaded=threaded)
|
|
529
|
-
elif threaded:
|
|
530
|
-
return ensure_aiter(iterable, threaded=threaded)
|
|
531
|
-
else:
|
|
532
|
-
return iterable
|
|
533
|
-
return async_map(function, iterable, *iterables)
|
|
534
|
-
if function is None:
|
|
535
|
-
if iterables:
|
|
536
|
-
return _zip(iterable, *iterables)
|
|
537
|
-
else:
|
|
538
|
-
return iterable
|
|
539
|
-
return _map(function, iterable, *iterables)
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
def filter(
|
|
543
|
-
function: None | Callable,
|
|
544
|
-
iterable: Iterable | AsyncIterable,
|
|
545
|
-
/,
|
|
546
|
-
threaded: bool = False,
|
|
547
|
-
):
|
|
548
|
-
"""
|
|
549
|
-
"""
|
|
550
|
-
if threaded or iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
|
|
551
|
-
return async_filter(function, iterable, threaded=threaded)
|
|
552
|
-
return _filter(function, iterable)
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
def reduce(
|
|
556
|
-
function: Callable,
|
|
557
|
-
iterable: Iterable | AsyncIterable,
|
|
558
|
-
initial: Any = undefined,
|
|
559
|
-
/,
|
|
560
|
-
threaded: bool = False,
|
|
561
|
-
):
|
|
562
|
-
"""
|
|
563
|
-
"""
|
|
564
|
-
if threaded or iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
|
|
565
|
-
return async_reduce(function, iterable, initial, threaded=threaded)
|
|
566
|
-
from functools import reduce
|
|
567
|
-
if initial is undefined:
|
|
568
|
-
return reduce(function, iterable)
|
|
569
|
-
return reduce(function, iterable, initial)
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
def zip(
|
|
573
|
-
iterable: Iterable | AsyncIterable,
|
|
574
|
-
/,
|
|
575
|
-
*iterables: Iterable | AsyncIterable,
|
|
576
|
-
threaded: bool = False,
|
|
577
|
-
):
|
|
578
|
-
"""
|
|
579
|
-
"""
|
|
580
|
-
if (not threaded and
|
|
581
|
-
isinstance(iterable, Iterable) and
|
|
582
|
-
all(isinstance(it, Iterable) for it in iterables)
|
|
583
|
-
):
|
|
584
|
-
return _zip(iterable, *iterables)
|
|
585
|
-
return async_zip(iterable, *iterables, threaded=threaded)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
@overload
|
|
589
|
-
def chain[T](
|
|
590
|
-
iterable: Iterable[T],
|
|
591
|
-
/,
|
|
592
|
-
*iterables: Iterable[T],
|
|
593
|
-
threaded: Literal[False] = False,
|
|
594
|
-
) -> Iterator[T]:
|
|
595
|
-
...
|
|
596
|
-
@overload
|
|
597
|
-
def chain[T](
|
|
598
|
-
iterable: Iterable[T],
|
|
599
|
-
/,
|
|
600
|
-
*iterables: Iterable[T] | AsyncIterable[T],
|
|
601
|
-
threaded: Literal[True],
|
|
602
|
-
) -> AsyncIterator[T]:
|
|
603
|
-
...
|
|
604
|
-
@overload
|
|
605
|
-
def chain[T](
|
|
606
|
-
iterable: AsyncIterable[T],
|
|
607
|
-
/,
|
|
608
|
-
*iterables: Iterable[T] | AsyncIterable[T],
|
|
609
|
-
threaded: Literal[False, True] = False,
|
|
610
|
-
) -> AsyncIterator[T]:
|
|
611
|
-
...
|
|
612
|
-
def chain[T](
|
|
613
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
614
|
-
/,
|
|
615
|
-
*iterables: Iterable[T] | AsyncIterable[T],
|
|
616
|
-
threaded: Literal[False, True] = False,
|
|
617
|
-
) -> Iterator[T] | AsyncIterator[T]:
|
|
618
|
-
if (not threaded and
|
|
619
|
-
isinstance(iterable, Iterable) and
|
|
620
|
-
all(isinstance(it, Iterable) for it in iterables)
|
|
621
|
-
):
|
|
622
|
-
return _chain(iterable, *iterables) # type: ignore
|
|
623
|
-
return async_chain(iterable, *iterables, threaded=threaded)
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
@overload
|
|
627
|
-
def chain_from_iterable[T](
|
|
628
|
-
iterables: Iterable[Iterable[T]],
|
|
629
|
-
threaded: bool = False,
|
|
630
|
-
*,
|
|
631
|
-
async_: Literal[False] = False,
|
|
632
|
-
) -> Iterator[T]:
|
|
633
|
-
...
|
|
634
|
-
@overload
|
|
635
|
-
def chain_from_iterable[T](
|
|
636
|
-
iterables: (
|
|
637
|
-
AsyncIterable[Iterable[T]] |
|
|
638
|
-
AsyncIterable[AsyncIterable[T]] |
|
|
639
|
-
AsyncIterable[Iterable[T] | AsyncIterable[T]]
|
|
640
|
-
),
|
|
641
|
-
threaded: bool = False,
|
|
642
|
-
*,
|
|
643
|
-
async_: bool = False,
|
|
644
|
-
) -> AsyncIterator[T]:
|
|
645
|
-
...
|
|
646
|
-
@overload
|
|
647
|
-
def chain_from_iterable[T](
|
|
648
|
-
iterables: (
|
|
649
|
-
Iterable[Iterable[T]] |
|
|
650
|
-
Iterable[AsyncIterable[T]] |
|
|
651
|
-
Iterable[Iterable[T] | AsyncIterable[T]] |
|
|
652
|
-
AsyncIterable[Iterable[T]] |
|
|
653
|
-
AsyncIterable[AsyncIterable[T]] |
|
|
654
|
-
AsyncIterable[Iterable[T] | AsyncIterable[T]]
|
|
655
|
-
),
|
|
656
|
-
threaded: bool = False,
|
|
657
|
-
*,
|
|
658
|
-
async_: Literal[True],
|
|
659
|
-
) -> AsyncIterator[T]:
|
|
660
|
-
...
|
|
661
|
-
def chain_from_iterable[T](
|
|
662
|
-
iterables: (
|
|
663
|
-
Iterable[Iterable[T]] |
|
|
664
|
-
Iterable[AsyncIterable[T]] |
|
|
665
|
-
Iterable[Iterable[T] | AsyncIterable[T]] |
|
|
666
|
-
AsyncIterable[Iterable[T]] |
|
|
667
|
-
AsyncIterable[AsyncIterable[T]] |
|
|
668
|
-
AsyncIterable[Iterable[T] | AsyncIterable[T]]
|
|
669
|
-
),
|
|
670
|
-
threaded: bool = False,
|
|
671
|
-
*,
|
|
672
|
-
async_: Literal[False, True] = False,
|
|
673
|
-
) -> Iterator[T] | AsyncIterator[T]:
|
|
674
|
-
if async_ or not isinstance(iterables, Iterable):
|
|
675
|
-
if isinstance(iterables, Iterable):
|
|
676
|
-
return async_chain.from_iterable(iterables, threaded=threaded)
|
|
677
|
-
else:
|
|
678
|
-
return async_chain.from_iterable(iterables, threaded=threaded)
|
|
679
|
-
return _chain.from_iterable(iterables) # type: ignore
|
|
680
|
-
|
|
681
|
-
setattr(chain, "from_iterable", chain_from_iterable)
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
@overload
|
|
685
|
-
def chunked[T](
|
|
686
|
-
iterable: Iterable[T],
|
|
687
|
-
n: int = 1,
|
|
688
|
-
/,
|
|
689
|
-
*,
|
|
690
|
-
threaded: Literal[False] = False,
|
|
691
|
-
) -> Iterator[Sequence[T]]:
|
|
692
|
-
...
|
|
693
|
-
@overload
|
|
694
|
-
def chunked[T](
|
|
695
|
-
iterable: Iterable[T],
|
|
696
|
-
n: int = 1,
|
|
697
|
-
/,
|
|
698
|
-
*,
|
|
699
|
-
threaded: Literal[True],
|
|
700
|
-
) -> Iterator[Sequence[T]]:
|
|
701
|
-
...
|
|
702
|
-
@overload
|
|
703
|
-
def chunked[T](
|
|
704
|
-
iterable: AsyncIterable[T],
|
|
705
|
-
n: int = 1,
|
|
706
|
-
/,
|
|
707
|
-
*,
|
|
708
|
-
threaded: Literal[False, True] = False,
|
|
709
|
-
) -> AsyncIterator[Sequence[T]]:
|
|
710
|
-
...
|
|
711
|
-
def chunked[T](
|
|
712
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
713
|
-
n: int = 1,
|
|
714
|
-
/,
|
|
715
|
-
*,
|
|
716
|
-
threaded: Literal[False, True] = False,
|
|
717
|
-
) -> Iterator[Sequence[T]] | AsyncIterator[Sequence[T]]:
|
|
718
|
-
"""
|
|
719
|
-
"""
|
|
720
|
-
if n < 0:
|
|
721
|
-
n = 1
|
|
722
|
-
if isinstance(iterable, Sequence):
|
|
723
|
-
if n == 1:
|
|
724
|
-
return ((e,) for e in iterable)
|
|
725
|
-
return (iterable[i:j] for i, j in pairwise(range(0, len(iterable)+n, n)))
|
|
726
|
-
elif not threaded and isinstance(iterable, Iterable):
|
|
727
|
-
return batched(iterable, n)
|
|
728
|
-
else:
|
|
729
|
-
return async_batched(iterable, n, threaded=threaded)
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
def foreach(
|
|
733
|
-
value: Callable,
|
|
734
|
-
iterable: Iterable | AsyncIterable,
|
|
735
|
-
/,
|
|
736
|
-
*iterables: Iterable | AsyncIterable,
|
|
737
|
-
threaded: bool = False,
|
|
738
|
-
):
|
|
739
|
-
"""
|
|
740
|
-
"""
|
|
741
|
-
if (not threaded and
|
|
742
|
-
isinstance(iterable, Iterable) and
|
|
743
|
-
all(isinstance(it, Iterable) for it in iterables)
|
|
744
|
-
):
|
|
745
|
-
if iterables:
|
|
746
|
-
for args in _zip(iterable, *iterables):
|
|
747
|
-
value(*args)
|
|
748
|
-
else:
|
|
749
|
-
for arg in iterable:
|
|
750
|
-
value(arg)
|
|
751
|
-
else:
|
|
752
|
-
return async_foreach(value, iterable, *iterables, threaded=threaded)
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
async def async_foreach(
|
|
756
|
-
value: Callable,
|
|
757
|
-
iterable: Iterable | AsyncIterable,
|
|
758
|
-
/,
|
|
759
|
-
*iterables: Iterable | AsyncIterable,
|
|
760
|
-
threaded: bool = False,
|
|
761
|
-
):
|
|
762
|
-
"""
|
|
763
|
-
"""
|
|
764
|
-
value = ensure_async(value, threaded=threaded)
|
|
765
|
-
if iterables:
|
|
766
|
-
async for args in async_zip(iterable, *iterables, threaded=threaded):
|
|
767
|
-
await value(*args)
|
|
768
|
-
else:
|
|
769
|
-
async for arg in ensure_aiter(iterable, threaded=threaded):
|
|
770
|
-
await value(arg)
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
def through(
|
|
774
|
-
iterable: Iterable | AsyncIterable,
|
|
775
|
-
/,
|
|
776
|
-
take_while: None | Callable = None,
|
|
777
|
-
threaded: bool = False,
|
|
778
|
-
):
|
|
779
|
-
"""
|
|
780
|
-
"""
|
|
781
|
-
if threaded or not isinstance(iterable, Iterable):
|
|
782
|
-
return async_through(iterable, take_while, threaded=threaded)
|
|
783
|
-
elif take_while is None:
|
|
784
|
-
for _ in iterable:
|
|
785
|
-
pass
|
|
786
|
-
else:
|
|
787
|
-
for v in _map(take_while, iterable):
|
|
788
|
-
if not v:
|
|
789
|
-
break
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
async def async_through(
|
|
793
|
-
iterable: Iterable | AsyncIterable,
|
|
794
|
-
/,
|
|
795
|
-
take_while: None | Callable = None,
|
|
796
|
-
threaded: bool = False,
|
|
797
|
-
):
|
|
798
|
-
"""
|
|
799
|
-
"""
|
|
800
|
-
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
801
|
-
if take_while is None:
|
|
802
|
-
async for _ in iterable:
|
|
803
|
-
pass
|
|
804
|
-
elif take_while is bool:
|
|
805
|
-
async for v in iterable:
|
|
806
|
-
if not v:
|
|
807
|
-
break
|
|
808
|
-
else:
|
|
809
|
-
async for v in async_map(take_while, iterable):
|
|
810
|
-
if not v:
|
|
811
|
-
break
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
@overload
|
|
815
|
-
def flatten(
|
|
816
|
-
iterable: Iterable,
|
|
817
|
-
/,
|
|
818
|
-
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
819
|
-
*,
|
|
820
|
-
threaded: Literal[False] = False,
|
|
821
|
-
) -> Iterator:
|
|
822
|
-
...
|
|
823
|
-
@overload
|
|
824
|
-
def flatten(
|
|
825
|
-
iterable: Iterable,
|
|
826
|
-
/,
|
|
827
|
-
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
828
|
-
*,
|
|
829
|
-
threaded: Literal[True],
|
|
830
|
-
) -> Iterator:
|
|
831
|
-
...
|
|
832
|
-
@overload
|
|
833
|
-
def flatten(
|
|
834
|
-
iterable: AsyncIterable,
|
|
835
|
-
/,
|
|
836
|
-
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
837
|
-
*,
|
|
838
|
-
threaded: Literal[False, True] = False,
|
|
839
|
-
) -> AsyncIterator:
|
|
840
|
-
...
|
|
841
|
-
def flatten(
|
|
842
|
-
iterable: Iterable | AsyncIterable,
|
|
843
|
-
/,
|
|
844
|
-
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
845
|
-
threaded: Literal[False, True] = False,
|
|
846
|
-
) -> Iterator | AsyncIterator:
|
|
847
|
-
"""
|
|
848
|
-
"""
|
|
849
|
-
if threaded or not isinstance(iterable, Iterable):
|
|
850
|
-
return async_flatten(iterable, exclude_types, threaded=threaded)
|
|
851
|
-
def gen(iterable):
|
|
852
|
-
for e in iterable:
|
|
853
|
-
if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
|
|
854
|
-
yield from gen(e)
|
|
855
|
-
else:
|
|
856
|
-
yield e
|
|
857
|
-
return gen(iterable)
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
async def async_flatten(
|
|
861
|
-
iterable: Iterable | AsyncIterable,
|
|
862
|
-
/,
|
|
863
|
-
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
864
|
-
threaded: bool = False,
|
|
865
|
-
) -> AsyncIterator:
|
|
866
|
-
"""
|
|
867
|
-
"""
|
|
868
|
-
async for e in ensure_aiter(iterable, threaded=threaded):
|
|
869
|
-
if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
|
|
870
|
-
async for e in async_flatten(e, exclude_types, threaded=threaded):
|
|
871
|
-
yield e
|
|
872
|
-
else:
|
|
873
|
-
yield e
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
@overload
|
|
877
|
-
def collect[K, V](
|
|
878
|
-
iterable: Iterable[tuple[K, V]] | Mapping[K, V],
|
|
879
|
-
/,
|
|
880
|
-
rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
|
|
881
|
-
*,
|
|
882
|
-
threaded: Literal[False] = False,
|
|
883
|
-
) -> MutableMapping[K, V]:
|
|
884
|
-
...
|
|
885
|
-
@overload
|
|
886
|
-
def collect[T](
|
|
887
|
-
iterable: Iterable[T],
|
|
888
|
-
/,
|
|
889
|
-
rettype: Callable[[Iterable[T]], Collection[T]] = list,
|
|
890
|
-
*,
|
|
891
|
-
threaded: Literal[False] = False,
|
|
892
|
-
) -> Collection[T]:
|
|
893
|
-
...
|
|
894
|
-
@overload
|
|
895
|
-
def collect[K, V](
|
|
896
|
-
iterable: Iterable[tuple[K, V]] | Mapping[K, V],
|
|
897
|
-
/,
|
|
898
|
-
rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
|
|
899
|
-
*,
|
|
900
|
-
threaded: Literal[True],
|
|
901
|
-
) -> Coroutine[Any, Any, MutableMapping[K, V]]:
|
|
902
|
-
...
|
|
903
|
-
@overload
|
|
904
|
-
def collect[T](
|
|
905
|
-
iterable: Iterable[T],
|
|
906
|
-
/,
|
|
907
|
-
rettype: Callable[[Iterable[T]], Collection[T]] = list,
|
|
908
|
-
*,
|
|
909
|
-
threaded: Literal[True],
|
|
910
|
-
) -> Coroutine[Any, Any, Collection[T]]:
|
|
911
|
-
...
|
|
912
|
-
@overload
|
|
913
|
-
def collect[K, V](
|
|
914
|
-
iterable: AsyncIterable[tuple[K, V]],
|
|
915
|
-
/,
|
|
916
|
-
rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
|
|
917
|
-
*,
|
|
918
|
-
threaded: Literal[False, True] = False,
|
|
919
|
-
) -> Coroutine[Any, Any, MutableMapping[K, V]]:
|
|
920
|
-
...
|
|
921
|
-
@overload
|
|
922
|
-
def collect[T](
|
|
923
|
-
iterable: AsyncIterable[T],
|
|
924
|
-
/,
|
|
925
|
-
rettype: Callable[[Iterable[T]], Collection[T]] = list,
|
|
926
|
-
*,
|
|
927
|
-
threaded: Literal[False, True] = False,
|
|
928
|
-
) -> Coroutine[Any, Any, Collection[T]]:
|
|
929
|
-
...
|
|
930
|
-
def collect(
|
|
931
|
-
iterable: Iterable | AsyncIterable | Mapping,
|
|
932
|
-
/,
|
|
933
|
-
rettype: Callable[[Iterable], Collection] = list,
|
|
934
|
-
*,
|
|
935
|
-
threaded: Literal[False, True] = False,
|
|
936
|
-
) -> Collection | Coroutine[Any, Any, Collection]:
|
|
937
|
-
"""
|
|
938
|
-
"""
|
|
939
|
-
if threaded or not isinstance(iterable, Iterable):
|
|
940
|
-
return async_collect(iterable, rettype, threaded=threaded)
|
|
941
|
-
return rettype(iterable)
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
@overload
|
|
945
|
-
def group_collect[K, V, C: Container](
|
|
946
|
-
iterable: Iterable[tuple[K, V]],
|
|
947
|
-
mapping: None = None,
|
|
948
|
-
factory: None | C | Callable[[], C] = None,
|
|
949
|
-
threaded: bool = False,
|
|
950
|
-
) -> dict[K, C]:
|
|
951
|
-
...
|
|
952
|
-
@overload
|
|
953
|
-
def group_collect[K, V, C: Container, M: MutableMapping](
|
|
954
|
-
iterable: Iterable[tuple[K, V]],
|
|
955
|
-
mapping: M,
|
|
956
|
-
factory: None | C | Callable[[], C] = None,
|
|
957
|
-
threaded: bool = False,
|
|
958
|
-
) -> M:
|
|
959
|
-
...
|
|
960
|
-
@overload
|
|
961
|
-
def group_collect[K, V, C: Container](
|
|
962
|
-
iterable: AsyncIterable[tuple[K, V]],
|
|
963
|
-
mapping: None = None,
|
|
964
|
-
factory: None | C | Callable[[], C] = None,
|
|
965
|
-
threaded: bool = False,
|
|
966
|
-
) -> Coroutine[Any, Any, dict[K, C]]:
|
|
967
|
-
...
|
|
968
|
-
@overload
|
|
969
|
-
def group_collect[K, V, C: Container, M: MutableMapping](
|
|
970
|
-
iterable: AsyncIterable[tuple[K, V]],
|
|
971
|
-
mapping: M,
|
|
972
|
-
factory: None | C | Callable[[], C] = None,
|
|
973
|
-
threaded: bool = False,
|
|
974
|
-
) -> Coroutine[Any, Any, M]:
|
|
975
|
-
...
|
|
976
|
-
def group_collect[K, V, C: Container, M: MutableMapping](
|
|
977
|
-
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
978
|
-
mapping: None | M = None,
|
|
979
|
-
factory: None | C | Callable[[], C] = None,
|
|
980
|
-
threaded: bool = False,
|
|
981
|
-
) -> dict[K, C] | M | Coroutine[Any, Any, dict[K, C]] | Coroutine[Any, Any, M]:
|
|
982
|
-
"""
|
|
983
|
-
"""
|
|
984
|
-
if threaded or not isinstance(iterable, Iterable):
|
|
985
|
-
return async_group_collect(iterable, mapping, factory, threaded=threaded)
|
|
986
|
-
if factory is None:
|
|
987
|
-
if isinstance(mapping, defaultdict):
|
|
988
|
-
factory = mapping.default_factory
|
|
989
|
-
elif mapping:
|
|
990
|
-
factory = type(next(iter(ValuesView(mapping))))
|
|
991
|
-
else:
|
|
992
|
-
factory = cast(type[C], list)
|
|
993
|
-
elif callable(factory):
|
|
994
|
-
pass
|
|
995
|
-
elif isinstance(factory, Container):
|
|
996
|
-
factory = cast(Callable[[], C], lambda _obj=factory: copy(_obj))
|
|
997
|
-
else:
|
|
998
|
-
raise ValueError("can't determine factory")
|
|
999
|
-
factory = cast(Callable[[], C], factory)
|
|
1000
|
-
if isinstance(factory, type):
|
|
1001
|
-
factory_type = factory
|
|
1002
|
-
else:
|
|
1003
|
-
factory_type = type(factory())
|
|
1004
|
-
if issubclass(factory_type, MutableSequence):
|
|
1005
|
-
add = getattr(factory_type, "append")
|
|
1006
|
-
else:
|
|
1007
|
-
add = getattr(factory_type, "add")
|
|
1008
|
-
if mapping is None:
|
|
1009
|
-
mapping = cast(M, {})
|
|
1010
|
-
for k, v in iterable:
|
|
1011
|
-
try:
|
|
1012
|
-
c = mapping[k]
|
|
1013
|
-
except LookupError:
|
|
1014
|
-
c = mapping[k] = factory()
|
|
1015
|
-
add(c, v)
|
|
1016
|
-
return mapping
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
@overload
|
|
1020
|
-
async def async_group_collect[K, V, C: Container](
|
|
1021
|
-
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
1022
|
-
mapping: None = None,
|
|
1023
|
-
factory: None | C | Callable[[], C] = None,
|
|
1024
|
-
threaded: bool = False,
|
|
1025
|
-
) -> dict[K, C]:
|
|
1026
|
-
...
|
|
1027
|
-
@overload
|
|
1028
|
-
async def async_group_collect[K, V, C: Container, M: MutableMapping](
|
|
1029
|
-
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
1030
|
-
mapping: M,
|
|
1031
|
-
factory: None | C | Callable[[], C] = None,
|
|
1032
|
-
threaded: bool = False,
|
|
1033
|
-
) -> M:
|
|
1034
|
-
...
|
|
1035
|
-
async def async_group_collect[K, V, C: Container, M: MutableMapping](
|
|
1036
|
-
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
1037
|
-
mapping: None | M = None,
|
|
1038
|
-
factory: None | C | Callable[[], C] = None,
|
|
1039
|
-
threaded: bool = False,
|
|
1040
|
-
) -> dict[K, C] | M:
|
|
1041
|
-
"""
|
|
1042
|
-
"""
|
|
1043
|
-
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
1044
|
-
if factory is None:
|
|
1045
|
-
if isinstance(mapping, defaultdict):
|
|
1046
|
-
factory = mapping.default_factory
|
|
1047
|
-
elif mapping:
|
|
1048
|
-
factory = type(next(iter(ValuesView(mapping))))
|
|
1049
|
-
else:
|
|
1050
|
-
factory = cast(type[C], list)
|
|
1051
|
-
elif callable(factory):
|
|
1052
|
-
pass
|
|
1053
|
-
elif isinstance(factory, Container):
|
|
1054
|
-
factory = cast(Callable[[], C], lambda _obj=factory: copy(_obj))
|
|
1055
|
-
else:
|
|
1056
|
-
raise ValueError("can't determine factory")
|
|
1057
|
-
factory = cast(Callable[[], C], factory)
|
|
1058
|
-
if isinstance(factory, type):
|
|
1059
|
-
factory_type = factory
|
|
1060
|
-
else:
|
|
1061
|
-
factory_type = type(factory())
|
|
1062
|
-
if issubclass(factory_type, MutableSequence):
|
|
1063
|
-
add = getattr(factory_type, "append")
|
|
1064
|
-
else:
|
|
1065
|
-
add = getattr(factory_type, "add")
|
|
1066
|
-
if mapping is None:
|
|
1067
|
-
mapping = cast(M, {})
|
|
1068
|
-
async for k, v in iterable:
|
|
1069
|
-
try:
|
|
1070
|
-
c = mapping[k]
|
|
1071
|
-
except LookupError:
|
|
1072
|
-
c = mapping[k] = factory()
|
|
1073
|
-
add(c, v)
|
|
1074
|
-
return mapping
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
@overload
|
|
1078
|
-
def iter_unique[T](
|
|
1079
|
-
iterable: Iterable[T],
|
|
1080
|
-
/,
|
|
1081
|
-
seen: None | MutableSet = None,
|
|
1082
|
-
*,
|
|
1083
|
-
threaded: Literal[False] = False,
|
|
1084
|
-
) -> Iterator[T]:
|
|
1085
|
-
...
|
|
1086
|
-
@overload
|
|
1087
|
-
def iter_unique[T](
|
|
1088
|
-
iterable: Iterable[T],
|
|
1089
|
-
/,
|
|
1090
|
-
seen: None | MutableSet = None,
|
|
1091
|
-
*,
|
|
1092
|
-
threaded: Literal[True],
|
|
1093
|
-
) -> AsyncIterator[T]:
|
|
1094
|
-
...
|
|
1095
|
-
@overload
|
|
1096
|
-
def iter_unique[T](
|
|
1097
|
-
iterable: AsyncIterable[T],
|
|
1098
|
-
/,
|
|
1099
|
-
seen: None | MutableSet = None,
|
|
1100
|
-
*,
|
|
1101
|
-
threaded: Literal[False, True] = False,
|
|
1102
|
-
) -> AsyncIterator[T]:
|
|
1103
|
-
...
|
|
1104
|
-
def iter_unique[T](
|
|
1105
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
1106
|
-
/,
|
|
1107
|
-
seen: None | MutableSet = None,
|
|
1108
|
-
threaded: Literal[False, True] = False,
|
|
1109
|
-
) -> Iterator[T] | AsyncIterator[T]:
|
|
1110
|
-
"""
|
|
1111
|
-
"""
|
|
1112
|
-
if threaded or not isinstance(iterable, Iterable):
|
|
1113
|
-
return async_iter_unique(iterable, seen, threaded=threaded)
|
|
1114
|
-
if seen is None:
|
|
1115
|
-
seen = set()
|
|
1116
|
-
def gen(iterable):
|
|
1117
|
-
add = seen.add
|
|
1118
|
-
for e in iterable:
|
|
1119
|
-
if e not in seen:
|
|
1120
|
-
yield e
|
|
1121
|
-
add(e)
|
|
1122
|
-
return gen(iterable)
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
async def async_iter_unique[T](
|
|
1126
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
1127
|
-
/,
|
|
1128
|
-
seen: None | MutableSet = None,
|
|
1129
|
-
threaded: bool = False,
|
|
1130
|
-
) -> AsyncIterator[T]:
|
|
1131
|
-
"""
|
|
1132
|
-
"""
|
|
1133
|
-
if seen is None:
|
|
1134
|
-
seen = set()
|
|
1135
|
-
add = seen.add
|
|
1136
|
-
async for e in ensure_aiter(iterable, threaded=threaded):
|
|
1137
|
-
if e not in seen:
|
|
1138
|
-
yield e
|
|
1139
|
-
add(e)
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
@overload
|
|
1143
|
-
def wrap_iter[T](
|
|
1144
|
-
iterable: Iterable[T],
|
|
1145
|
-
/,
|
|
1146
|
-
callprev: None | Callable[[T], Any] = None,
|
|
1147
|
-
callnext: None | Callable[[T], Any] = None,
|
|
1148
|
-
*,
|
|
1149
|
-
threaded: Literal[False] = False,
|
|
1150
|
-
) -> Iterator[T]:
|
|
1151
|
-
...
|
|
1152
|
-
@overload
|
|
1153
|
-
def wrap_iter[T](
|
|
1154
|
-
iterable: Iterable[T],
|
|
1155
|
-
/,
|
|
1156
|
-
callprev: None | Callable[[T], Any] = None,
|
|
1157
|
-
callnext: None | Callable[[T], Any] = None,
|
|
1158
|
-
*,
|
|
1159
|
-
threaded: Literal[True],
|
|
1160
|
-
) -> AsyncIterator[T]:
|
|
1161
|
-
...
|
|
1162
|
-
@overload
|
|
1163
|
-
def wrap_iter[T](
|
|
1164
|
-
iterable: AsyncIterable[T],
|
|
1165
|
-
/,
|
|
1166
|
-
callprev: None | Callable[[T], Any] = None,
|
|
1167
|
-
callnext: None | Callable[[T], Any] = None,
|
|
1168
|
-
threaded: Literal[False, True] = False,
|
|
1169
|
-
) -> AsyncIterator[T]:
|
|
1170
|
-
...
|
|
1171
|
-
def wrap_iter[T](
|
|
1172
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
1173
|
-
/,
|
|
1174
|
-
callprev: None | Callable[[T], Any] = None,
|
|
1175
|
-
callnext: None | Callable[[T], Any] = None,
|
|
1176
|
-
threaded: bool = False,
|
|
1177
|
-
) -> Iterator[T] | AsyncIterator[T]:
|
|
1178
|
-
"""
|
|
1179
|
-
"""
|
|
1180
|
-
if threaded or not isinstance(iterable, Iterable):
|
|
1181
|
-
return wrap_aiter(
|
|
1182
|
-
iterable,
|
|
1183
|
-
callprev=callprev,
|
|
1184
|
-
callnext=callnext,
|
|
1185
|
-
threaded=threaded,
|
|
1186
|
-
)
|
|
1187
|
-
if not callable(callprev):
|
|
1188
|
-
callprev = None
|
|
1189
|
-
if not callable(callnext):
|
|
1190
|
-
callnext = None
|
|
1191
|
-
def gen():
|
|
1192
|
-
for e in iterable:
|
|
1193
|
-
callprev and callprev(e)
|
|
1194
|
-
yield e
|
|
1195
|
-
callnext and callnext(e)
|
|
1196
|
-
return gen()
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
async def wrap_aiter[T](
|
|
1200
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
1201
|
-
/,
|
|
1202
|
-
callprev: None | Callable[[T], Any] = None,
|
|
1203
|
-
callnext: None | Callable[[T], Any] = None,
|
|
1204
|
-
threaded: bool = False,
|
|
1205
|
-
) -> AsyncIterator[T]:
|
|
1206
|
-
"""
|
|
1207
|
-
"""
|
|
1208
|
-
callprev = ensure_async(callprev, threaded=threaded) if callable(callprev) else None
|
|
1209
|
-
callnext = ensure_async(callnext, threaded=threaded) if callable(callnext) else None
|
|
1210
|
-
async for e in ensure_aiter(iterable, threaded=threaded):
|
|
1211
|
-
callprev and await callprev(e)
|
|
1212
|
-
yield e
|
|
1213
|
-
callnext and await callnext(e)
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
@overload
|
|
1217
|
-
def peek_iter[T](
|
|
1218
|
-
iterable: Iterable[T],
|
|
1219
|
-
/,
|
|
1220
|
-
threaded: Literal[False] = False,
|
|
1221
|
-
) -> None | Iterator[T]:
|
|
1222
|
-
...
|
|
1223
|
-
@overload
|
|
1224
|
-
def peek_iter[T](
|
|
1225
|
-
iterable: Iterable[T],
|
|
1226
|
-
/,
|
|
1227
|
-
threaded: Literal[True],
|
|
1228
|
-
) -> Coroutine[Any, Any, None | AsyncIterator[T]]:
|
|
1229
|
-
...
|
|
1230
|
-
@overload
|
|
1231
|
-
def peek_iter[T](
|
|
1232
|
-
iterable: AsyncIterable[T],
|
|
1233
|
-
/,
|
|
1234
|
-
threaded: Literal[False, True] = False,
|
|
1235
|
-
) -> Coroutine[Any, Any, None | AsyncIterator[T]]:
|
|
1236
|
-
...
|
|
1237
|
-
def peek_iter[T](
|
|
1238
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
1239
|
-
/,
|
|
1240
|
-
threaded: Literal[False, True] = False,
|
|
1241
|
-
) -> None | Iterator[T] | Coroutine[Any, Any, None | AsyncIterator[T]]:
|
|
1242
|
-
if threaded or isinstance(iterable, AsyncIterable):
|
|
1243
|
-
return peek_aiter(iterable, threaded=threaded)
|
|
1244
|
-
try:
|
|
1245
|
-
it = iter(iterable)
|
|
1246
|
-
first = next(it)
|
|
1247
|
-
return chain((first,), it)
|
|
1248
|
-
except StopIteration:
|
|
1249
|
-
return None
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
async def peek_aiter[T](
|
|
1253
|
-
iterable: Iterable[T] | AsyncIterable[T],
|
|
1254
|
-
/,
|
|
1255
|
-
threaded: Literal[False, True] = False,
|
|
1256
|
-
) -> None | AsyncIterator[T]:
|
|
1257
|
-
try:
|
|
1258
|
-
it = ensure_aiter(iterable, threaded=threaded)
|
|
1259
|
-
first = await anext(it)
|
|
1260
|
-
return async_chain((first,), it)
|
|
1261
|
-
except StopAsyncIteration:
|
|
1262
|
-
return None
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
def acc_step(
|
|
1266
|
-
start: int,
|
|
1267
|
-
stop: None | int = None,
|
|
1268
|
-
step: int = 1,
|
|
1269
|
-
) -> Iterator[tuple[int, int, int]]:
|
|
1270
|
-
"""
|
|
1271
|
-
"""
|
|
1272
|
-
if stop is None:
|
|
1273
|
-
start, stop = 0, start
|
|
1274
|
-
for i in range(start + step, stop, step):
|
|
1275
|
-
yield start, (start := i), step
|
|
1276
|
-
if start != stop:
|
|
1277
|
-
yield start, stop, stop - start
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
def cut_iter(
|
|
1281
|
-
start: int,
|
|
1282
|
-
stop: None | int = None,
|
|
1283
|
-
step: int = 1,
|
|
1284
|
-
) -> Iterator[tuple[int, int]]:
|
|
1285
|
-
"""
|
|
1286
|
-
"""
|
|
1287
|
-
if stop is None:
|
|
1288
|
-
start, stop = 0, start
|
|
1289
|
-
for start in range(start + step, stop, step):
|
|
1290
|
-
yield start, step
|
|
1291
|
-
if start != stop:
|
|
1292
|
-
yield stop, stop - start
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
@overload
|
|
1296
|
-
def context[T](
|
|
1297
|
-
func: Callable[..., T],
|
|
1298
|
-
*ctxs: ContextManager,
|
|
1299
|
-
async_: Literal[False],
|
|
1300
|
-
) -> T:
|
|
1301
|
-
...
|
|
1302
|
-
@overload
|
|
1303
|
-
def context[T](
|
|
1304
|
-
func: Callable[..., T] | Callable[..., Awaitable[T]],
|
|
1305
|
-
*ctxs: ContextManager | AsyncContextManager,
|
|
1306
|
-
async_: Literal[True],
|
|
1307
|
-
) -> Coroutine[Any, Any, T]:
|
|
1308
|
-
...
|
|
1309
|
-
@overload
|
|
1310
|
-
def context[T](
|
|
1311
|
-
func: Callable[..., T] | Callable[..., Awaitable[T]],
|
|
1312
|
-
*ctxs: ContextManager | AsyncContextManager,
|
|
1313
|
-
async_: None = None,
|
|
1314
|
-
) -> T | Coroutine[Any, Any, T]:
|
|
1315
|
-
...
|
|
1316
|
-
def context[T](
|
|
1317
|
-
func: Callable[..., T] | Callable[..., Awaitable[T]],
|
|
1318
|
-
*ctxs: ContextManager | AsyncContextManager,
|
|
1319
|
-
async_: None | Literal[False, True] = None,
|
|
1320
|
-
) -> T | Coroutine[Any, Any, T]:
|
|
1321
|
-
"""
|
|
1322
|
-
"""
|
|
1323
|
-
if async_ is None:
|
|
1324
|
-
if iscoroutinefunction(func):
|
|
1325
|
-
async_ = True
|
|
1326
|
-
else:
|
|
1327
|
-
async_ = _get_async()
|
|
1328
|
-
if async_:
|
|
1329
|
-
async def call():
|
|
1330
|
-
args: list = []
|
|
1331
|
-
add_arg = args.append
|
|
1332
|
-
with ExitStack() as stack:
|
|
1333
|
-
async with AsyncExitStack() as async_stack:
|
|
1334
|
-
enter = stack.enter_context
|
|
1335
|
-
async_enter = async_stack.enter_async_context
|
|
1336
|
-
for ctx in ctxs:
|
|
1337
|
-
if isinstance(ctx, AsyncContextManager):
|
|
1338
|
-
add_arg(await async_enter(ctx))
|
|
1339
|
-
else:
|
|
1340
|
-
add_arg(enter(ctx))
|
|
1341
|
-
ret = func(*args)
|
|
1342
|
-
if isawaitable(ret):
|
|
1343
|
-
ret = await cast(Awaitable, ret)
|
|
1344
|
-
return ret
|
|
1345
|
-
return call()
|
|
1346
|
-
else:
|
|
1347
|
-
with ExitStack() as stack:
|
|
1348
|
-
return func(*map(stack.enter_context, ctxs)) # type: ignore
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
@overload
|
|
1352
|
-
def backgroud_loop(
|
|
1353
|
-
call: None | Callable = None,
|
|
1354
|
-
/,
|
|
1355
|
-
interval: int | float = 0.05,
|
|
1356
|
-
*,
|
|
1357
|
-
async_: Literal[False],
|
|
1358
|
-
) -> ContextManager:
|
|
1359
|
-
...
|
|
1360
|
-
@overload
|
|
1361
|
-
def backgroud_loop(
|
|
1362
|
-
call: None | Callable = None,
|
|
1363
|
-
/,
|
|
1364
|
-
interval: int | float = 0.05,
|
|
1365
|
-
*,
|
|
1366
|
-
async_: Literal[True],
|
|
1367
|
-
) -> AsyncContextManager:
|
|
1368
|
-
...
|
|
1369
|
-
@overload
|
|
1370
|
-
def backgroud_loop(
|
|
1371
|
-
call: None | Callable = None,
|
|
1372
|
-
/,
|
|
1373
|
-
interval: int | float = 0.05,
|
|
1374
|
-
*,
|
|
1375
|
-
async_: None = None,
|
|
1376
|
-
) -> ContextManager | AsyncContextManager:
|
|
1377
|
-
...
|
|
1378
|
-
def backgroud_loop(
|
|
1379
|
-
call: None | Callable = None,
|
|
1380
|
-
/,
|
|
1381
|
-
interval: int | float = 0.05,
|
|
1382
|
-
*,
|
|
1383
|
-
async_: None | Literal[False, True] = None,
|
|
1384
|
-
) -> ContextManager | AsyncContextManager:
|
|
1385
|
-
"""
|
|
1386
|
-
"""
|
|
1387
|
-
if async_ is None:
|
|
1388
|
-
if iscoroutinefunction(call):
|
|
1389
|
-
async_ = True
|
|
1390
|
-
else:
|
|
1391
|
-
async_ = _get_async()
|
|
1392
|
-
use_default_call = not callable(call)
|
|
1393
|
-
if use_default_call:
|
|
1394
|
-
start = time()
|
|
1395
|
-
def call():
|
|
1396
|
-
print(f"\r\x1b[K{format_time(time() - start)}", end="")
|
|
1397
|
-
def run():
|
|
1398
|
-
while running:
|
|
1399
|
-
try:
|
|
1400
|
-
yield call
|
|
1401
|
-
except Exception:
|
|
1402
|
-
pass
|
|
1403
|
-
if interval > 0:
|
|
1404
|
-
if async_:
|
|
1405
|
-
yield async_sleep(interval)
|
|
1406
|
-
else:
|
|
1407
|
-
sleep(interval)
|
|
1408
|
-
running = True
|
|
1409
|
-
if async_:
|
|
1410
|
-
@asynccontextmanager
|
|
1411
|
-
async def actx():
|
|
1412
|
-
nonlocal running
|
|
1413
|
-
try:
|
|
1414
|
-
task = create_task(run())
|
|
1415
|
-
yield task
|
|
1416
|
-
finally:
|
|
1417
|
-
running = False
|
|
1418
|
-
task.cancel()
|
|
1419
|
-
if use_default_call:
|
|
1420
|
-
print("\r\x1b[K", end="")
|
|
1421
|
-
return actx()
|
|
1422
|
-
else:
|
|
1423
|
-
@contextmanager
|
|
1424
|
-
def ctx():
|
|
1425
|
-
nonlocal running
|
|
1426
|
-
try:
|
|
1427
|
-
yield start_new_thread(run, ())
|
|
1428
|
-
finally:
|
|
1429
|
-
running = False
|
|
1430
|
-
if use_default_call:
|
|
1431
|
-
print("\r\x1b[K", end="")
|
|
1432
|
-
return ctx()
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
def gen_startup[**Args, G: Generator](func: Callable[Args, G], /):
|
|
1436
|
-
def wrapper(*args: Args.args, **kwds: Args.kwargs) -> G:
|
|
1437
|
-
gen = func(*args, **kwds)
|
|
1438
|
-
next(gen)
|
|
1439
|
-
return gen
|
|
1440
|
-
return update_wrapper(wrapper, func)
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
def async_gen_startup[**Args, G: AsyncGenerator](func: Callable[Args, G], /):
|
|
1444
|
-
async def wrapper(*args: Args.args, **kwds: Args.kwargs) -> G:
|
|
1445
|
-
gen = func(*args, **kwds)
|
|
1446
|
-
await anext(gen)
|
|
1447
|
-
return gen
|
|
1448
|
-
return update_wrapper(wrapper, func)
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
def do_iter[T](
|
|
1452
|
-
func: Callable[[], T] | Iterable[T],
|
|
1453
|
-
/,
|
|
1454
|
-
sentinel=undefined,
|
|
1455
|
-
sentinel_excs: type[BaseException] | tuple[type[BaseException], ...] = (),
|
|
1456
|
-
) -> Iterator[T]:
|
|
1457
|
-
try:
|
|
1458
|
-
yield from iter(func if callable(func) else iter(func).__next__, sentinel)
|
|
1459
|
-
except sentinel_excs:
|
|
1460
|
-
pass
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
async def do_aiter[T](
|
|
1464
|
-
func: Callable[[], T] | Callable[[], Awaitable[T]] | Iterable[T] | AsyncIterable[T],
|
|
1465
|
-
/,
|
|
1466
|
-
sentinel=undefined,
|
|
1467
|
-
sentinel_excs: type[BaseException] | tuple[type[BaseException], ...] = (),
|
|
1468
|
-
) -> AsyncIterator[T]:
|
|
1469
|
-
if callable(func):
|
|
1470
|
-
func = ensure_async(func)
|
|
1471
|
-
else:
|
|
1472
|
-
func = ensure_aiter(func).__anext__
|
|
1473
|
-
try:
|
|
1474
|
-
while True:
|
|
1475
|
-
v = await func()
|
|
1476
|
-
if v is sentinel:
|
|
1477
|
-
break
|
|
1478
|
-
yield v
|
|
1479
|
-
except StopAsyncIteration:
|
|
1480
|
-
pass
|
|
1481
|
-
except sentinel_excs:
|
|
1482
|
-
pass
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
def bfs_iter[T](*initials: T) -> tuple[Iterator[T], Callable[[T], None]]:
|
|
1486
|
-
dq = deque(initials)
|
|
1487
|
-
return do_iter(dq.popleft, sentinel_excs=IndexError), dq.append
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
@gen_startup
|
|
1491
|
-
def bfs_gen[T](*initials) -> Generator[None | T, T | None, None]:
|
|
1492
|
-
dq = deque(initials)
|
|
1493
|
-
push, pop = dq.append, dq.popleft
|
|
1494
|
-
try:
|
|
1495
|
-
p = yield None
|
|
1496
|
-
while True:
|
|
1497
|
-
p = yield (pop() if p is None else push(p))
|
|
1498
|
-
except IndexError:
|
|
1499
|
-
pass
|
|
5
|
+
__version__ = (0, 3, 1)
|
|
1500
6
|
|
|
7
|
+
from .dynamic import *
|
|
8
|
+
from .gen_step import *
|
|
9
|
+
from .misc import *
|