python-iterutils 0.1.11__tar.gz → 0.2.1__tar.gz
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.
- {python_iterutils-0.1.11 → python_iterutils-0.2.1}/PKG-INFO +1 -1
- {python_iterutils-0.1.11 → python_iterutils-0.2.1}/iterutils/__init__.py +238 -167
- {python_iterutils-0.1.11 → python_iterutils-0.2.1}/pyproject.toml +1 -1
- {python_iterutils-0.1.11 → python_iterutils-0.2.1}/LICENSE +0 -0
- {python_iterutils-0.1.11 → python_iterutils-0.2.1}/iterutils/py.typed +0 -0
- {python_iterutils-0.1.11 → python_iterutils-0.2.1}/readme.md +0 -0
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
5
|
-
__version__ = (0,
|
|
5
|
+
__version__ = (0, 2, 1)
|
|
6
6
|
__all__ = [
|
|
7
|
-
"Return", "Yield", "YieldFrom", "iterable", "async_iterable",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
7
|
+
"Return", "Yield", "YieldFrom", "iterable", "async_iterable",
|
|
8
|
+
"foreach", "async_foreach", "through", "async_through", "flatten",
|
|
9
|
+
"async_flatten", "collect", "async_collect", "group_collect",
|
|
10
|
+
"async_group_collect", "map", "filter", "reduce", "zip", "chunked",
|
|
11
|
+
"iter_unique", "async_iter_unique", "wrap_iter", "wrap_aiter",
|
|
12
|
+
"acc_step", "cut_iter", "iter_gen_step", "iter_gen_step_async",
|
|
13
|
+
"run_gen_step", "run_gen_step_iter", "as_gen_step", "bfs_gen",
|
|
14
|
+
"with_iter_next", "backgroud_loop",
|
|
13
15
|
]
|
|
14
16
|
|
|
15
17
|
from abc import ABC, abstractmethod
|
|
@@ -17,11 +19,14 @@ from asyncio import create_task, sleep as async_sleep, to_thread
|
|
|
17
19
|
from builtins import map as _map, filter as _filter, zip as _zip
|
|
18
20
|
from collections import defaultdict, deque
|
|
19
21
|
from collections.abc import (
|
|
20
|
-
AsyncIterable, AsyncIterator, Awaitable, Buffer, Callable,
|
|
21
|
-
Coroutine, Generator, Iterable, Iterator,
|
|
22
|
-
MutableSequence, Sequence,
|
|
22
|
+
AsyncIterable, AsyncIterator, Awaitable, Buffer, Callable,
|
|
23
|
+
Collection, Container, Coroutine, Generator, Iterable, Iterator,
|
|
24
|
+
Mapping, MutableMapping, MutableSet, MutableSequence, Sequence,
|
|
25
|
+
ValuesView,
|
|
26
|
+
)
|
|
27
|
+
from contextlib import (
|
|
28
|
+
asynccontextmanager, contextmanager, ExitStack, AsyncExitStack,
|
|
23
29
|
)
|
|
24
|
-
from contextlib import asynccontextmanager, contextmanager, ExitStack, AsyncExitStack
|
|
25
30
|
from copy import copy
|
|
26
31
|
from dataclasses import dataclass
|
|
27
32
|
from itertools import batched, pairwise
|
|
@@ -30,26 +35,42 @@ from sys import _getframe
|
|
|
30
35
|
from _thread import start_new_thread
|
|
31
36
|
from time import sleep, time
|
|
32
37
|
from types import FrameType
|
|
33
|
-
from typing import
|
|
38
|
+
from typing import (
|
|
39
|
+
cast, overload, Any, AsyncContextManager, ContextManager, Literal,
|
|
40
|
+
Protocol,
|
|
41
|
+
)
|
|
34
42
|
|
|
35
43
|
from asynctools import (
|
|
36
|
-
async_filter, async_map, async_reduce, async_zip, async_batched,
|
|
37
|
-
collect as async_collect,
|
|
44
|
+
async_filter, async_map, async_reduce, async_zip, async_batched,
|
|
45
|
+
ensure_async, ensure_aiter, collect as async_collect,
|
|
38
46
|
)
|
|
39
47
|
from decotools import optional
|
|
40
48
|
from texttools import format_time
|
|
41
|
-
from undefined import undefined
|
|
49
|
+
from undefined import undefined
|
|
42
50
|
|
|
43
51
|
|
|
44
52
|
class SupportsBool(Protocol):
|
|
53
|
+
"""
|
|
54
|
+
"""
|
|
45
55
|
def __bool__(self, /) -> bool: ...
|
|
46
56
|
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
class Reraised(BaseException):
|
|
59
|
+
"""
|
|
60
|
+
"""
|
|
61
|
+
def __init__(self, exc: BaseException, /):
|
|
62
|
+
if isinstance(exc, Reraised):
|
|
63
|
+
exc = exc.exception
|
|
64
|
+
self.exception: BaseException = exc
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass(slots=True, frozen=True, unsafe_hash=True)
|
|
49
68
|
class YieldBase(ABC):
|
|
69
|
+
"""
|
|
70
|
+
"""
|
|
50
71
|
value: Any
|
|
51
|
-
|
|
52
|
-
|
|
72
|
+
may_await: None | bool | Literal[1] = False
|
|
73
|
+
may_call: None | bool | Literal[1] = None
|
|
53
74
|
|
|
54
75
|
@property
|
|
55
76
|
@abstractmethod
|
|
@@ -57,25 +78,30 @@ class YieldBase(ABC):
|
|
|
57
78
|
...
|
|
58
79
|
|
|
59
80
|
|
|
60
|
-
class Reraised(BaseException):
|
|
61
|
-
|
|
62
|
-
def __init__(self, exc: BaseException, /):
|
|
63
|
-
self.exception = exc
|
|
64
|
-
|
|
65
|
-
|
|
66
81
|
class Return(YieldBase):
|
|
82
|
+
"""
|
|
83
|
+
"""
|
|
84
|
+
__slots__ = ()
|
|
67
85
|
yield_type = 0
|
|
68
86
|
|
|
69
87
|
|
|
70
88
|
class Yield(YieldBase):
|
|
89
|
+
"""
|
|
90
|
+
"""
|
|
91
|
+
__slots__ = ()
|
|
71
92
|
yield_type = 1
|
|
72
93
|
|
|
73
94
|
|
|
74
95
|
class YieldFrom(YieldBase):
|
|
96
|
+
"""
|
|
97
|
+
"""
|
|
98
|
+
__slots__ = ()
|
|
75
99
|
yield_type = 2
|
|
76
100
|
|
|
77
101
|
|
|
78
102
|
def iterable(iterable, /) -> bool:
|
|
103
|
+
"""
|
|
104
|
+
"""
|
|
79
105
|
try:
|
|
80
106
|
return isinstance(iter(iterable), Iterable)
|
|
81
107
|
except TypeError:
|
|
@@ -83,6 +109,8 @@ def iterable(iterable, /) -> bool:
|
|
|
83
109
|
|
|
84
110
|
|
|
85
111
|
def async_iterable(iterable, /) -> bool:
|
|
112
|
+
"""
|
|
113
|
+
"""
|
|
86
114
|
try:
|
|
87
115
|
return isinstance(iter(iterable), AsyncIterable)
|
|
88
116
|
except TypeError:
|
|
@@ -95,6 +123,8 @@ def foreach(
|
|
|
95
123
|
/,
|
|
96
124
|
*iterables: Iterable | AsyncIterable,
|
|
97
125
|
):
|
|
126
|
+
"""
|
|
127
|
+
"""
|
|
98
128
|
if not (isinstance(iterable, Iterable) and all(isinstance(it, Iterable) for it in iterables)):
|
|
99
129
|
return async_foreach(value, iterable, *iterables)
|
|
100
130
|
if iterables:
|
|
@@ -112,6 +142,8 @@ async def async_foreach(
|
|
|
112
142
|
*iterables: Iterable | AsyncIterable,
|
|
113
143
|
threaded: bool = False,
|
|
114
144
|
):
|
|
145
|
+
"""
|
|
146
|
+
"""
|
|
115
147
|
value = ensure_async(value, threaded=threaded)
|
|
116
148
|
if iterables:
|
|
117
149
|
async for args in async_zip(iterable, *iterables, threaded=threaded):
|
|
@@ -126,6 +158,8 @@ def through(
|
|
|
126
158
|
/,
|
|
127
159
|
take_while: None | Callable = None,
|
|
128
160
|
):
|
|
161
|
+
"""
|
|
162
|
+
"""
|
|
129
163
|
if not isinstance(iterable, Iterable):
|
|
130
164
|
return async_through(iterable, take_while)
|
|
131
165
|
if take_while is None:
|
|
@@ -143,6 +177,8 @@ async def async_through(
|
|
|
143
177
|
take_while: None | Callable = None,
|
|
144
178
|
threaded: bool = False,
|
|
145
179
|
):
|
|
180
|
+
"""
|
|
181
|
+
"""
|
|
146
182
|
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
147
183
|
if take_while is None:
|
|
148
184
|
async for _ in iterable:
|
|
@@ -176,6 +212,8 @@ def flatten(
|
|
|
176
212
|
/,
|
|
177
213
|
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
178
214
|
) -> Iterator | AsyncIterator:
|
|
215
|
+
"""
|
|
216
|
+
"""
|
|
179
217
|
if not isinstance(iterable, Iterable):
|
|
180
218
|
return async_flatten(iterable, exclude_types)
|
|
181
219
|
def gen(iterable):
|
|
@@ -193,6 +231,8 @@ async def async_flatten(
|
|
|
193
231
|
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
194
232
|
threaded: bool = False,
|
|
195
233
|
) -> AsyncIterator:
|
|
234
|
+
"""
|
|
235
|
+
"""
|
|
196
236
|
async for e in ensure_aiter(iterable, threaded=threaded):
|
|
197
237
|
if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
|
|
198
238
|
async for e in async_flatten(e, exclude_types, threaded=threaded):
|
|
@@ -234,6 +274,8 @@ def collect(
|
|
|
234
274
|
/,
|
|
235
275
|
rettype: Callable[[Iterable], Collection] = list,
|
|
236
276
|
) -> Collection | Coroutine[Any, Any, Collection]:
|
|
277
|
+
"""
|
|
278
|
+
"""
|
|
237
279
|
if not isinstance(iterable, Iterable):
|
|
238
280
|
return async_collect(iterable, rettype)
|
|
239
281
|
return rettype(iterable)
|
|
@@ -272,6 +314,8 @@ def group_collect[K, V, C: Container, M: MutableMapping](
|
|
|
272
314
|
mapping: None | M = None,
|
|
273
315
|
factory: None | C | Callable[[], C] = None,
|
|
274
316
|
) -> dict[K, C] | M | Coroutine[Any, Any, dict[K, C]] | Coroutine[Any, Any, M]:
|
|
317
|
+
"""
|
|
318
|
+
"""
|
|
275
319
|
if not isinstance(iterable, Iterable):
|
|
276
320
|
return async_group_collect(iterable, mapping, factory)
|
|
277
321
|
if factory is None:
|
|
@@ -329,6 +373,8 @@ async def async_group_collect[K, V, C: Container, M: MutableMapping](
|
|
|
329
373
|
factory: None | C | Callable[[], C] = None,
|
|
330
374
|
threaded: bool = False,
|
|
331
375
|
) -> dict[K, C] | M:
|
|
376
|
+
"""
|
|
377
|
+
"""
|
|
332
378
|
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
333
379
|
if factory is None:
|
|
334
380
|
if isinstance(mapping, defaultdict):
|
|
@@ -368,7 +414,9 @@ def map(
|
|
|
368
414
|
iterable: Iterable | AsyncIterable,
|
|
369
415
|
/,
|
|
370
416
|
*iterables: Iterable | AsyncIterable,
|
|
371
|
-
):
|
|
417
|
+
):
|
|
418
|
+
"""
|
|
419
|
+
"""
|
|
372
420
|
if (
|
|
373
421
|
iscoroutinefunction(function) or
|
|
374
422
|
isinstance(iterable, AsyncIterable) or
|
|
@@ -393,6 +441,8 @@ def filter(
|
|
|
393
441
|
iterable: Iterable | AsyncIterable,
|
|
394
442
|
/,
|
|
395
443
|
):
|
|
444
|
+
"""
|
|
445
|
+
"""
|
|
396
446
|
if iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
|
|
397
447
|
return async_filter(function, iterable)
|
|
398
448
|
return _filter(function, iterable)
|
|
@@ -401,9 +451,11 @@ def filter(
|
|
|
401
451
|
def reduce(
|
|
402
452
|
function: Callable,
|
|
403
453
|
iterable: Iterable | AsyncIterable,
|
|
404
|
-
initial = undefined,
|
|
454
|
+
initial: Any = undefined,
|
|
405
455
|
/,
|
|
406
456
|
):
|
|
457
|
+
"""
|
|
458
|
+
"""
|
|
407
459
|
if iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
|
|
408
460
|
return async_reduce(function, iterable, initial)
|
|
409
461
|
from functools import reduce
|
|
@@ -417,6 +469,8 @@ def zip(
|
|
|
417
469
|
/,
|
|
418
470
|
*iterables: Iterable | AsyncIterable,
|
|
419
471
|
):
|
|
472
|
+
"""
|
|
473
|
+
"""
|
|
420
474
|
if isinstance(iterable, AsyncIterable) or any(isinstance(i, AsyncIterable) for i in iterables):
|
|
421
475
|
return async_zip(iterable, *iterables)
|
|
422
476
|
return _zip(iterable, *iterables)
|
|
@@ -441,6 +495,8 @@ def chunked[T](
|
|
|
441
495
|
n: int = 1,
|
|
442
496
|
/,
|
|
443
497
|
) -> Iterator[Sequence[T]] | AsyncIterator[Sequence[T]]:
|
|
498
|
+
"""
|
|
499
|
+
"""
|
|
444
500
|
if n < 0:
|
|
445
501
|
n = 1
|
|
446
502
|
if isinstance(iterable, Sequence):
|
|
@@ -472,6 +528,8 @@ def iter_unique[T](
|
|
|
472
528
|
/,
|
|
473
529
|
seen: None | MutableSet = None,
|
|
474
530
|
) -> Iterator[T] | AsyncIterator[T]:
|
|
531
|
+
"""
|
|
532
|
+
"""
|
|
475
533
|
if not isinstance(iterable, Iterable):
|
|
476
534
|
return async_iter_unique(iterable, seen)
|
|
477
535
|
if seen is None:
|
|
@@ -491,6 +549,8 @@ async def async_iter_unique[T](
|
|
|
491
549
|
seen: None | MutableSet = None,
|
|
492
550
|
threaded: bool = False,
|
|
493
551
|
) -> AsyncIterator[T]:
|
|
552
|
+
"""
|
|
553
|
+
"""
|
|
494
554
|
if seen is None:
|
|
495
555
|
seen = set()
|
|
496
556
|
add = seen.add
|
|
@@ -506,8 +566,6 @@ def wrap_iter[T](
|
|
|
506
566
|
/,
|
|
507
567
|
callprev: None | Callable[[T], Any] = None,
|
|
508
568
|
callnext: None | Callable[[T], Any] = None,
|
|
509
|
-
callenter: None | Callable[[Iterable[T]], Any] = None,
|
|
510
|
-
callexit: None | Callable[[Iterable[T], None | BaseException], Any] = None,
|
|
511
569
|
) -> Iterator[T]:
|
|
512
570
|
...
|
|
513
571
|
@overload
|
|
@@ -516,8 +574,6 @@ def wrap_iter[T](
|
|
|
516
574
|
/,
|
|
517
575
|
callprev: None | Callable[[T], Any] = None,
|
|
518
576
|
callnext: None | Callable[[T], Any] = None,
|
|
519
|
-
callenter: None | Callable[[Iterable[T] | AsyncIterable[T]], Any] = None,
|
|
520
|
-
callexit: None | Callable[[Iterable[T] | AsyncIterable[T], None | BaseException], Any] = None,
|
|
521
577
|
) -> AsyncIterator[T]:
|
|
522
578
|
...
|
|
523
579
|
def wrap_iter[T](
|
|
@@ -525,47 +581,24 @@ def wrap_iter[T](
|
|
|
525
581
|
/,
|
|
526
582
|
callprev: None | Callable[[T], Any] = None,
|
|
527
583
|
callnext: None | Callable[[T], Any] = None,
|
|
528
|
-
callenter: None | Callable[[Iterable[T]], Any] | Callable[[Iterable[T] | AsyncIterable[T]], Any] = None,
|
|
529
|
-
callexit: ( None | Callable[[Iterable[T], None | BaseException], Any] |
|
|
530
|
-
Callable[[Iterable[T] | AsyncIterable[T], None | BaseException], Any] ) = None,
|
|
531
584
|
) -> Iterator[T] | AsyncIterator[T]:
|
|
585
|
+
"""
|
|
586
|
+
"""
|
|
532
587
|
if not isinstance(iterable, Iterable):
|
|
533
588
|
return wrap_aiter(
|
|
534
589
|
iterable,
|
|
535
590
|
callprev=callprev,
|
|
536
591
|
callnext=callnext,
|
|
537
|
-
callenter=callenter, # type: ignore
|
|
538
|
-
callexit=callexit, # type: ignore
|
|
539
592
|
)
|
|
540
593
|
if not callable(callprev):
|
|
541
594
|
callprev = None
|
|
542
595
|
if not callable(callnext):
|
|
543
596
|
callnext = None
|
|
544
597
|
def gen():
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if callprev:
|
|
550
|
-
try:
|
|
551
|
-
callprev(e)
|
|
552
|
-
except (StopIteration, GeneratorExit):
|
|
553
|
-
break
|
|
554
|
-
yield e
|
|
555
|
-
if callnext:
|
|
556
|
-
try:
|
|
557
|
-
callnext(e)
|
|
558
|
-
except (StopIteration, GeneratorExit):
|
|
559
|
-
break
|
|
560
|
-
except BaseException as e:
|
|
561
|
-
if callable(callexit):
|
|
562
|
-
if not callexit(iterable, e):
|
|
563
|
-
raise
|
|
564
|
-
else:
|
|
565
|
-
raise
|
|
566
|
-
finally:
|
|
567
|
-
if callable(callexit):
|
|
568
|
-
callexit(iterable, None)
|
|
598
|
+
for e in iterable:
|
|
599
|
+
callprev and callprev(e)
|
|
600
|
+
yield e
|
|
601
|
+
callnext and callnext(e)
|
|
569
602
|
return gen()
|
|
570
603
|
|
|
571
604
|
|
|
@@ -574,34 +607,16 @@ async def wrap_aiter[T](
|
|
|
574
607
|
/,
|
|
575
608
|
callprev: None | Callable[[T], Any] = None,
|
|
576
609
|
callnext: None | Callable[[T], Any] = None,
|
|
577
|
-
callenter: None | Callable[[Iterable[T] | AsyncIterable[T]], Any] = None,
|
|
578
|
-
callexit: None | Callable[[Iterable[T] | AsyncIterable[T], None | BaseException], Any] = None,
|
|
579
610
|
threaded: bool = False,
|
|
580
611
|
) -> AsyncIterator[T]:
|
|
612
|
+
"""
|
|
613
|
+
"""
|
|
581
614
|
callprev = ensure_async(callprev, threaded=threaded) if callable(callprev) else None
|
|
582
615
|
callnext = ensure_async(callnext, threaded=threaded) if callable(callnext) else None
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
await callprev(e)
|
|
588
|
-
except (StopAsyncIteration, GeneratorExit):
|
|
589
|
-
break
|
|
590
|
-
yield e
|
|
591
|
-
if callnext:
|
|
592
|
-
try:
|
|
593
|
-
await callnext(e)
|
|
594
|
-
except (StopAsyncIteration, GeneratorExit):
|
|
595
|
-
break
|
|
596
|
-
except BaseException as e:
|
|
597
|
-
if callable(callexit):
|
|
598
|
-
if not await ensure_async(callexit, threaded=threaded)(iterable, e):
|
|
599
|
-
raise
|
|
600
|
-
else:
|
|
601
|
-
raise
|
|
602
|
-
finally:
|
|
603
|
-
if callable(callexit):
|
|
604
|
-
await ensure_async(callexit, threaded=threaded)(iterable, None)
|
|
616
|
+
async for e in ensure_aiter(iterable, threaded=threaded):
|
|
617
|
+
callprev and await callprev(e)
|
|
618
|
+
yield e
|
|
619
|
+
callnext and await callnext(e)
|
|
605
620
|
|
|
606
621
|
|
|
607
622
|
def acc_step(
|
|
@@ -609,6 +624,8 @@ def acc_step(
|
|
|
609
624
|
stop: None | int = None,
|
|
610
625
|
step: int = 1,
|
|
611
626
|
) -> Iterator[tuple[int, int, int]]:
|
|
627
|
+
"""
|
|
628
|
+
"""
|
|
612
629
|
if stop is None:
|
|
613
630
|
start, stop = 0, start
|
|
614
631
|
for i in range(start + step, stop, step):
|
|
@@ -622,6 +639,8 @@ def cut_iter(
|
|
|
622
639
|
stop: None | int = None,
|
|
623
640
|
step: int = 1,
|
|
624
641
|
) -> Iterator[tuple[int, int]]:
|
|
642
|
+
"""
|
|
643
|
+
"""
|
|
625
644
|
if stop is None:
|
|
626
645
|
start, stop = 0, start
|
|
627
646
|
for start in range(start + step, stop, step):
|
|
@@ -650,20 +669,25 @@ def _get_async(back: int = 2) -> bool:
|
|
|
650
669
|
@overload
|
|
651
670
|
def call_as_async[**Args, T: Coroutine](
|
|
652
671
|
func: Callable[Args, T], /,
|
|
672
|
+
may_await: bool | Literal[1] = False,
|
|
653
673
|
threaded: bool = False,
|
|
654
674
|
) -> Callable[Args, T]:
|
|
655
675
|
...
|
|
656
676
|
@overload
|
|
657
677
|
def call_as_async[**Args, T](
|
|
658
678
|
func: Callable[Args, T], /,
|
|
679
|
+
may_await: bool | Literal[1] = False,
|
|
659
680
|
threaded: bool = False,
|
|
660
681
|
) -> Callable[Args, Coroutine[Any, Any, T]]:
|
|
661
682
|
...
|
|
662
683
|
def call_as_async[**Args, T](
|
|
663
684
|
func: Callable[Args, T],
|
|
664
685
|
/,
|
|
686
|
+
may_await: bool | Literal[1] = False,
|
|
665
687
|
threaded: bool = False,
|
|
666
688
|
) -> Callable[Args, T] | Callable[Args, Coroutine[Any, Any, T]]:
|
|
689
|
+
"""
|
|
690
|
+
"""
|
|
667
691
|
if iscoroutinefunction(func):
|
|
668
692
|
return func
|
|
669
693
|
def wraps(*args, **kwds):
|
|
@@ -671,32 +695,35 @@ def call_as_async[**Args, T](
|
|
|
671
695
|
return func(*args, **kwds)
|
|
672
696
|
except (StopIteration, StopAsyncIteration) as e:
|
|
673
697
|
raise Reraised(e) from e
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
698
|
+
async def wrapper(*args, **kwds):
|
|
699
|
+
if threaded:
|
|
700
|
+
value = await to_thread(wraps, *args, **kwds)
|
|
701
|
+
else:
|
|
702
|
+
value = wraps(*args, **kwds)
|
|
703
|
+
if may_await is 1 or may_await and isawaitable(value):
|
|
704
|
+
value = await value
|
|
705
|
+
return value
|
|
680
706
|
return wrapper
|
|
681
707
|
|
|
682
708
|
|
|
683
709
|
def iter_gen_step(
|
|
684
710
|
gen_step: Generator | Callable[[], Generator],
|
|
711
|
+
may_call: bool | Literal[1] = True,
|
|
685
712
|
):
|
|
713
|
+
"""
|
|
714
|
+
"""
|
|
686
715
|
if callable(gen_step):
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
close = gen.close
|
|
716
|
+
gen_step = gen_step()
|
|
717
|
+
send = gen_step.send
|
|
718
|
+
throw = gen_step.throw
|
|
719
|
+
close = gen_step.close
|
|
720
|
+
value: Any = None
|
|
693
721
|
try:
|
|
694
|
-
value = send(None)
|
|
695
722
|
while True:
|
|
696
723
|
if isinstance(value, YieldBase):
|
|
697
724
|
raise StopIteration(value)
|
|
698
725
|
try:
|
|
699
|
-
if callable(value):
|
|
726
|
+
if may_call is 1 or may_call and callable(value):
|
|
700
727
|
value = value()
|
|
701
728
|
except BaseException as e:
|
|
702
729
|
value = throw(e)
|
|
@@ -705,11 +732,12 @@ def iter_gen_step(
|
|
|
705
732
|
yield value
|
|
706
733
|
except StopIteration as e:
|
|
707
734
|
value = e.value
|
|
708
|
-
try_call_me = True
|
|
709
735
|
if isinstance(value, YieldBase):
|
|
710
|
-
|
|
736
|
+
maybe_callable = value.may_call
|
|
737
|
+
if maybe_callable is not None:
|
|
738
|
+
may_call = maybe_callable
|
|
711
739
|
value = value.value
|
|
712
|
-
if callable(value)
|
|
740
|
+
if may_call is 1 or may_call and callable(value):
|
|
713
741
|
try:
|
|
714
742
|
value = value()
|
|
715
743
|
except BaseException as e:
|
|
@@ -718,32 +746,33 @@ def iter_gen_step(
|
|
|
718
746
|
except BaseException as e:
|
|
719
747
|
raise Reraised(e) from e
|
|
720
748
|
yield value
|
|
721
|
-
except BaseException as e:
|
|
722
|
-
raise Reraised(e) from e
|
|
723
749
|
finally:
|
|
724
750
|
close()
|
|
725
751
|
|
|
726
752
|
|
|
727
753
|
async def iter_gen_step_async(
|
|
728
754
|
gen_step: Generator | Callable[[], Generator],
|
|
755
|
+
may_await: bool | Literal[1] = True,
|
|
756
|
+
may_call: bool | Literal[1] = True,
|
|
729
757
|
threaded: bool = False,
|
|
730
758
|
):
|
|
759
|
+
"""
|
|
760
|
+
"""
|
|
731
761
|
if callable(gen_step):
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
close: Callable = call_as_async(gen.close, threaded=threaded)
|
|
762
|
+
gen_step = gen_step()
|
|
763
|
+
send: Callable = call_as_async(gen_step.send, threaded=threaded)
|
|
764
|
+
throw: Callable = call_as_async(gen_step.throw, threaded=threaded)
|
|
765
|
+
close: Callable = call_as_async(gen_step.close, threaded=threaded)
|
|
766
|
+
value: Any = None
|
|
738
767
|
try:
|
|
739
|
-
value = await send(None)
|
|
740
768
|
while True:
|
|
741
769
|
if isinstance(value, YieldBase):
|
|
742
770
|
raise StopIteration(value)
|
|
743
771
|
try:
|
|
744
|
-
if callable(value):
|
|
745
|
-
value = await call_as_async(
|
|
746
|
-
|
|
772
|
+
if may_call is 1 or may_call and callable(value):
|
|
773
|
+
value = await call_as_async(
|
|
774
|
+
value, may_await=may_await, threaded=threaded)()
|
|
775
|
+
elif may_await is 1 or may_await and isawaitable(value):
|
|
747
776
|
value = await value
|
|
748
777
|
except BaseException as e:
|
|
749
778
|
if isinstance(e, Reraised):
|
|
@@ -757,16 +786,19 @@ async def iter_gen_step_async(
|
|
|
757
786
|
e = e.exception
|
|
758
787
|
if isinstance(e, StopIteration):
|
|
759
788
|
value = e.value
|
|
760
|
-
identity = False
|
|
761
|
-
try_call_me = True
|
|
762
789
|
if isinstance(value, YieldBase):
|
|
763
|
-
|
|
764
|
-
|
|
790
|
+
maybe_awaitable = value.may_await
|
|
791
|
+
if maybe_awaitable is not None:
|
|
792
|
+
may_await = maybe_awaitable
|
|
793
|
+
maybe_callable = value.may_call
|
|
794
|
+
if maybe_callable is not None:
|
|
795
|
+
may_call = maybe_callable
|
|
765
796
|
value = value.value
|
|
766
797
|
try:
|
|
767
|
-
if callable(value)
|
|
768
|
-
value = await call_as_async(
|
|
769
|
-
|
|
798
|
+
if may_call is 1 or may_call and callable(value):
|
|
799
|
+
value = await call_as_async(
|
|
800
|
+
value, may_await=may_await, threaded=threaded)()
|
|
801
|
+
elif may_await is 1 or may_await and isawaitable(value):
|
|
770
802
|
value = await value
|
|
771
803
|
except BaseException as e:
|
|
772
804
|
try:
|
|
@@ -780,36 +812,44 @@ async def iter_gen_step_async(
|
|
|
780
812
|
await close()
|
|
781
813
|
|
|
782
814
|
|
|
783
|
-
def run_gen_step
|
|
815
|
+
def run_gen_step(
|
|
784
816
|
gen_step: Generator | Callable[[], Generator],
|
|
817
|
+
may_await: bool | Literal[1] = True,
|
|
818
|
+
may_call: bool | Literal[1] = True,
|
|
785
819
|
threaded: bool = False,
|
|
786
|
-
running_flag: None | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]]
|
|
820
|
+
running_flag: None | SupportsBool | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]] = None,
|
|
787
821
|
*,
|
|
788
822
|
async_: None | bool = None,
|
|
789
823
|
):
|
|
824
|
+
"""
|
|
825
|
+
"""
|
|
790
826
|
if async_ is None:
|
|
791
827
|
async_ = _get_async()
|
|
792
828
|
if async_:
|
|
793
829
|
async def process():
|
|
794
|
-
gen = iter_gen_step_async(
|
|
830
|
+
gen = iter_gen_step_async(
|
|
831
|
+
gen_step,
|
|
832
|
+
may_await=may_await,
|
|
833
|
+
may_call=may_call,
|
|
834
|
+
threaded=threaded,
|
|
835
|
+
)
|
|
795
836
|
try:
|
|
796
837
|
if running_flag is None:
|
|
797
838
|
async for value in gen:
|
|
798
839
|
pass
|
|
799
840
|
elif callable(running_flag):
|
|
800
|
-
pred = running_flag
|
|
801
|
-
if not
|
|
841
|
+
pred = call_as_async(running_flag, threaded=threaded)
|
|
842
|
+
if not await pred():
|
|
802
843
|
raise RuntimeError("stop before starting", gen) from StopIteration()
|
|
803
844
|
async for value in gen:
|
|
804
|
-
|
|
805
|
-
if not ((await pred) if isawaitable(pred) else pred):
|
|
845
|
+
if not await pred():
|
|
806
846
|
raise RuntimeError("stop midway", gen) from StopIteration(value)
|
|
807
|
-
|
|
847
|
+
else:
|
|
848
|
+
if not running_flag:
|
|
849
|
+
raise RuntimeError("stop before starting", gen) from StopIteration()
|
|
850
|
+
async for value in gen:
|
|
808
851
|
if not running_flag:
|
|
809
|
-
raise RuntimeError("stop
|
|
810
|
-
async for value in gen:
|
|
811
|
-
if not running_flag:
|
|
812
|
-
raise RuntimeError("stop midway", gen) from StopIteration(value)
|
|
852
|
+
raise RuntimeError("stop midway", gen) from StopIteration(value)
|
|
813
853
|
return value
|
|
814
854
|
except Reraised as e:
|
|
815
855
|
raise e.exception
|
|
@@ -819,7 +859,7 @@ def run_gen_step[T](
|
|
|
819
859
|
raise
|
|
820
860
|
return process()
|
|
821
861
|
else:
|
|
822
|
-
gen = iter_gen_step(gen_step)
|
|
862
|
+
gen = iter_gen_step(gen_step, may_call=may_call)
|
|
823
863
|
try:
|
|
824
864
|
if running_flag is None:
|
|
825
865
|
for value in gen:
|
|
@@ -844,6 +884,8 @@ def run_gen_step[T](
|
|
|
844
884
|
@overload
|
|
845
885
|
def run_gen_step_iter(
|
|
846
886
|
gen_step: Generator | Callable[[], Generator],
|
|
887
|
+
may_await: bool | Literal[1] = True,
|
|
888
|
+
may_call: bool | Literal[1] = True,
|
|
847
889
|
threaded: bool = False,
|
|
848
890
|
*,
|
|
849
891
|
async_: None = None,
|
|
@@ -852,6 +894,8 @@ def run_gen_step_iter(
|
|
|
852
894
|
@overload
|
|
853
895
|
def run_gen_step_iter(
|
|
854
896
|
gen_step: Generator | Callable[[], Generator],
|
|
897
|
+
may_await: bool | Literal[1] = True,
|
|
898
|
+
may_call: bool | Literal[1] = True,
|
|
855
899
|
threaded: bool = False,
|
|
856
900
|
*,
|
|
857
901
|
async_: Literal[False],
|
|
@@ -860,6 +904,8 @@ def run_gen_step_iter(
|
|
|
860
904
|
@overload
|
|
861
905
|
def run_gen_step_iter(
|
|
862
906
|
gen_step: Generator | Callable[[], Generator],
|
|
907
|
+
may_await: bool | Literal[1] = True,
|
|
908
|
+
may_call: bool | Literal[1] = True,
|
|
863
909
|
threaded: bool = False,
|
|
864
910
|
*,
|
|
865
911
|
async_: Literal[True],
|
|
@@ -867,44 +913,54 @@ def run_gen_step_iter(
|
|
|
867
913
|
...
|
|
868
914
|
def run_gen_step_iter(
|
|
869
915
|
gen_step: Generator | Callable[[], Generator],
|
|
916
|
+
may_await: bool | Literal[1] = True,
|
|
917
|
+
may_call: bool | Literal[1] = True,
|
|
870
918
|
threaded: bool = False,
|
|
871
919
|
*,
|
|
872
920
|
async_: None | bool = None,
|
|
873
921
|
) -> Iterator | AsyncIterator:
|
|
922
|
+
"""
|
|
923
|
+
"""
|
|
874
924
|
if async_ is None:
|
|
875
925
|
async_ = _get_async()
|
|
876
|
-
if callable(gen_step)
|
|
877
|
-
gen = gen_step()
|
|
878
|
-
else:
|
|
879
|
-
gen = gen_step
|
|
926
|
+
gen = gen_step() if callable(gen_step) else gen_step
|
|
880
927
|
send: Callable = gen.send
|
|
881
928
|
throw: Callable = gen.throw
|
|
882
929
|
close: Callable = gen.close
|
|
930
|
+
default_may_await = may_await
|
|
931
|
+
default_may_call = may_call
|
|
883
932
|
if async_:
|
|
884
933
|
send = call_as_async(send, threaded=threaded)
|
|
885
934
|
throw = call_as_async(throw, threaded=threaded)
|
|
886
935
|
close = call_as_async(close, threaded=threaded)
|
|
887
|
-
async def
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
if
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
936
|
+
async def aextract(value, /):
|
|
937
|
+
yield_type = -1
|
|
938
|
+
may_await = default_may_await
|
|
939
|
+
may_call = default_may_call
|
|
940
|
+
if isinstance(value, YieldBase):
|
|
941
|
+
yield_type = value.yield_type
|
|
942
|
+
maybe_awaitable = value.may_await
|
|
943
|
+
if maybe_awaitable is not None:
|
|
944
|
+
may_await = maybe_awaitable
|
|
945
|
+
maybe_callable = value.may_call
|
|
946
|
+
if maybe_callable is not None:
|
|
947
|
+
may_call = maybe_callable
|
|
948
|
+
value = value.value
|
|
949
|
+
if may_call is 1 or may_call and callable(value):
|
|
950
|
+
value = await call_as_async(
|
|
951
|
+
value, may_await=may_await, threaded=threaded)()
|
|
952
|
+
elif may_await is 1 or may_await and isawaitable(value):
|
|
953
|
+
value = await value
|
|
954
|
+
return yield_type, value
|
|
955
|
+
async def aprocess():
|
|
902
956
|
try:
|
|
903
957
|
value = await send(None)
|
|
904
958
|
while True:
|
|
905
959
|
try:
|
|
906
|
-
yield_type, value = await
|
|
960
|
+
yield_type, value = await aextract(value)
|
|
907
961
|
match yield_type:
|
|
962
|
+
case 0:
|
|
963
|
+
return
|
|
908
964
|
case 1:
|
|
909
965
|
yield value
|
|
910
966
|
case 2:
|
|
@@ -921,7 +977,7 @@ def run_gen_step_iter(
|
|
|
921
977
|
e = e.exception
|
|
922
978
|
if isinstance(e, StopIteration):
|
|
923
979
|
try:
|
|
924
|
-
yield_type, value = await
|
|
980
|
+
yield_type, value = await aextract(e.value)
|
|
925
981
|
match yield_type:
|
|
926
982
|
case 1:
|
|
927
983
|
yield value
|
|
@@ -936,18 +992,21 @@ def run_gen_step_iter(
|
|
|
936
992
|
raise
|
|
937
993
|
finally:
|
|
938
994
|
await close()
|
|
995
|
+
return aprocess()
|
|
939
996
|
else:
|
|
997
|
+
def extract(value, /):
|
|
998
|
+
yield_type = -1
|
|
999
|
+
may_call = default_may_call
|
|
1000
|
+
if isinstance(value, YieldBase):
|
|
1001
|
+
yield_type = value.yield_type
|
|
1002
|
+
maybe_callable = value.may_call
|
|
1003
|
+
if maybe_callable is not None:
|
|
1004
|
+
may_call = maybe_callable
|
|
1005
|
+
value = value.value
|
|
1006
|
+
if may_call is 1 or may_call and callable(value):
|
|
1007
|
+
value = value()
|
|
1008
|
+
return yield_type, value
|
|
940
1009
|
def process():
|
|
941
|
-
def extract(value, /):
|
|
942
|
-
try_call_me = True
|
|
943
|
-
yield_type = -1
|
|
944
|
-
if isinstance(value, YieldBase):
|
|
945
|
-
try_call_me = value.try_call_me
|
|
946
|
-
yield_type = value.yield_type
|
|
947
|
-
value = value.value
|
|
948
|
-
if try_call_me and callable(value):
|
|
949
|
-
value = value()
|
|
950
|
-
return yield_type, value
|
|
951
1010
|
try:
|
|
952
1011
|
value = send(None)
|
|
953
1012
|
while True:
|
|
@@ -978,7 +1037,7 @@ def run_gen_step_iter(
|
|
|
978
1037
|
throw(e)
|
|
979
1038
|
finally:
|
|
980
1039
|
close()
|
|
981
|
-
|
|
1040
|
+
return process()
|
|
982
1041
|
|
|
983
1042
|
|
|
984
1043
|
@optional
|
|
@@ -986,23 +1045,29 @@ def as_gen_step(
|
|
|
986
1045
|
func: Callable,
|
|
987
1046
|
/,
|
|
988
1047
|
iter: bool = False,
|
|
1048
|
+
may_await: bool | Literal[1] = True,
|
|
1049
|
+
may_call: bool | Literal[1] = True,
|
|
989
1050
|
threaded: bool = False,
|
|
990
|
-
running_flag: None | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]]
|
|
1051
|
+
running_flag: None | SupportsBool | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]] = None,
|
|
991
1052
|
*,
|
|
992
1053
|
async_: None | bool = None,
|
|
993
1054
|
) -> Callable:
|
|
994
|
-
|
|
995
|
-
|
|
1055
|
+
"""装饰器,构建一个 gen_step 函数
|
|
1056
|
+
"""
|
|
996
1057
|
def wrapper(*args, **kwds):
|
|
997
1058
|
if iter:
|
|
998
1059
|
return run_gen_step_iter(
|
|
999
1060
|
func(*args, **kwds),
|
|
1061
|
+
may_await=may_await,
|
|
1062
|
+
may_call=may_call,
|
|
1000
1063
|
threaded=threaded,
|
|
1001
1064
|
async_=async_, # type: ignore
|
|
1002
1065
|
)
|
|
1003
1066
|
else:
|
|
1004
1067
|
return run_gen_step(
|
|
1005
1068
|
func(*args, **kwds),
|
|
1069
|
+
may_await=may_await,
|
|
1070
|
+
may_call=may_call,
|
|
1006
1071
|
threaded=threaded,
|
|
1007
1072
|
running_flag=running_flag,
|
|
1008
1073
|
async_=async_,
|
|
@@ -1079,6 +1144,8 @@ def with_iter_next[T](
|
|
|
1079
1144
|
/,
|
|
1080
1145
|
async_: Literal[False, True] = False,
|
|
1081
1146
|
):
|
|
1147
|
+
"""
|
|
1148
|
+
"""
|
|
1082
1149
|
if async_:
|
|
1083
1150
|
get_next: Callable[[], T] | Callable[[], Awaitable[T]] = ensure_aiter(iterable).__anext__
|
|
1084
1151
|
elif isinstance(iterable, Iterable):
|
|
@@ -1117,6 +1184,8 @@ def context[T](
|
|
|
1117
1184
|
*ctxs: ContextManager | AsyncContextManager,
|
|
1118
1185
|
async_: Literal[False, True] = False,
|
|
1119
1186
|
) -> T | Coroutine[Any, Any, T]:
|
|
1187
|
+
"""
|
|
1188
|
+
"""
|
|
1120
1189
|
if async_:
|
|
1121
1190
|
async def call():
|
|
1122
1191
|
args: list = []
|
|
@@ -1165,6 +1234,8 @@ def backgroud_loop(
|
|
|
1165
1234
|
*,
|
|
1166
1235
|
async_: Literal[False, True] = False,
|
|
1167
1236
|
) -> ContextManager | AsyncContextManager:
|
|
1237
|
+
"""
|
|
1238
|
+
"""
|
|
1168
1239
|
use_default_call = not callable(call)
|
|
1169
1240
|
if use_default_call:
|
|
1170
1241
|
start = time()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|