python-iterutils 0.1.6.1__tar.gz → 0.1.8__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.6.1 → python_iterutils-0.1.8}/PKG-INFO +3 -3
- {python_iterutils-0.1.6.1 → python_iterutils-0.1.8}/iterutils/__init__.py +215 -17
- {python_iterutils-0.1.6.1 → python_iterutils-0.1.8}/pyproject.toml +3 -3
- {python_iterutils-0.1.6.1 → python_iterutils-0.1.8}/LICENSE +0 -0
- {python_iterutils-0.1.6.1 → python_iterutils-0.1.8}/iterutils/py.typed +0 -0
- {python_iterutils-0.1.6.1 → python_iterutils-0.1.8}/readme.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-iterutils
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: Python another itertools.
|
|
5
5
|
Home-page: https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-iterutils
|
|
6
6
|
License: MIT
|
|
@@ -20,8 +20,8 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
20
20
|
Classifier: Topic :: Software Development
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
-
Requires-Dist: python-asynctools (>=0.0.10)
|
|
24
|
-
Requires-Dist: python-decotools (>=0.0.
|
|
23
|
+
Requires-Dist: python-asynctools (>=0.0.10.1)
|
|
24
|
+
Requires-Dist: python-decotools (>=0.0.2)
|
|
25
25
|
Requires-Dist: python-texttools (>=0.0.3)
|
|
26
26
|
Requires-Dist: python-undefined (>=0.0.3)
|
|
27
27
|
Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-iterutils
|
|
@@ -2,33 +2,38 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
5
|
-
__version__ = (0, 1,
|
|
5
|
+
__version__ = (0, 1, 8)
|
|
6
6
|
__all__ = [
|
|
7
7
|
"Return", "Yield", "YieldFrom", "iterable", "async_iterable", "foreach", "async_foreach",
|
|
8
|
-
"through", "async_through", "flatten", "async_flatten", "
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"backgroud_loop",
|
|
8
|
+
"through", "async_through", "flatten", "async_flatten", "collect", "async_collect",
|
|
9
|
+
"group_collect", "async_group_collect", "map", "filter", "reduce", "zip", "chunked",
|
|
10
|
+
"iter_unique", "async_iter_unique", "wrap_iter", "wrap_aiter", "acc_step", "cut_iter",
|
|
11
|
+
"run_gen_step", "run_gen_step_iter", "as_gen_step", "bfs_gen", "with_iter_next", "backgroud_loop",
|
|
12
12
|
]
|
|
13
13
|
|
|
14
14
|
from abc import ABC, abstractmethod
|
|
15
15
|
from asyncio import create_task, sleep as async_sleep, to_thread
|
|
16
16
|
from builtins import map as _map, filter as _filter, zip as _zip
|
|
17
|
-
from collections import deque
|
|
17
|
+
from collections import defaultdict, deque
|
|
18
18
|
from collections.abc import (
|
|
19
|
-
AsyncIterable, AsyncIterator, Awaitable, Buffer, Callable,
|
|
20
|
-
Iterable, Iterator,
|
|
19
|
+
AsyncIterable, AsyncIterator, Awaitable, Buffer, Callable, Collection, Container,
|
|
20
|
+
Coroutine, Generator, Iterable, Iterator, Mapping, MutableMapping, MutableSet,
|
|
21
|
+
MutableSequence, Sequence, ValuesView,
|
|
21
22
|
)
|
|
22
23
|
from contextlib import asynccontextmanager, contextmanager, ExitStack, AsyncExitStack
|
|
24
|
+
from copy import copy
|
|
23
25
|
from dataclasses import dataclass
|
|
24
26
|
from itertools import batched, pairwise
|
|
25
27
|
from inspect import isawaitable, iscoroutinefunction
|
|
28
|
+
from sys import _getframe
|
|
26
29
|
from _thread import start_new_thread
|
|
27
30
|
from time import sleep, time
|
|
28
|
-
from
|
|
31
|
+
from types import FrameType
|
|
32
|
+
from typing import cast, overload, Any, AsyncContextManager, ContextManager, Literal
|
|
29
33
|
|
|
30
34
|
from asynctools import (
|
|
31
35
|
async_filter, async_map, async_reduce, async_zip, async_batched, ensure_async, ensure_aiter,
|
|
36
|
+
collect as async_collect,
|
|
32
37
|
)
|
|
33
38
|
from decotools import optional
|
|
34
39
|
from texttools import format_time
|
|
@@ -94,7 +99,7 @@ async def async_foreach(
|
|
|
94
99
|
iterable: Iterable | AsyncIterable,
|
|
95
100
|
/,
|
|
96
101
|
*iterables: Iterable | AsyncIterable,
|
|
97
|
-
threaded: bool =
|
|
102
|
+
threaded: bool = False,
|
|
98
103
|
):
|
|
99
104
|
value = ensure_async(value, threaded=threaded)
|
|
100
105
|
if iterables:
|
|
@@ -125,7 +130,7 @@ async def async_through(
|
|
|
125
130
|
iterable: Iterable | AsyncIterable,
|
|
126
131
|
/,
|
|
127
132
|
take_while: None | Callable = None,
|
|
128
|
-
threaded: bool =
|
|
133
|
+
threaded: bool = False,
|
|
129
134
|
):
|
|
130
135
|
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
131
136
|
if take_while is None:
|
|
@@ -175,7 +180,7 @@ async def async_flatten(
|
|
|
175
180
|
iterable: Iterable | AsyncIterable,
|
|
176
181
|
/,
|
|
177
182
|
exclude_types: type | tuple[type, ...] = (Buffer, str),
|
|
178
|
-
threaded: bool =
|
|
183
|
+
threaded: bool = False,
|
|
179
184
|
) -> AsyncIterator:
|
|
180
185
|
async for e in ensure_aiter(iterable, threaded=threaded):
|
|
181
186
|
if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
|
|
@@ -185,6 +190,168 @@ async def async_flatten(
|
|
|
185
190
|
yield e
|
|
186
191
|
|
|
187
192
|
|
|
193
|
+
@overload
|
|
194
|
+
def collect[K, V](
|
|
195
|
+
iterable: Iterable[tuple[K, V]] | Mapping[K, V],
|
|
196
|
+
/,
|
|
197
|
+
rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
|
|
198
|
+
) -> MutableMapping[K, V]:
|
|
199
|
+
...
|
|
200
|
+
@overload
|
|
201
|
+
def collect[T](
|
|
202
|
+
iterable: Iterable[T],
|
|
203
|
+
/,
|
|
204
|
+
rettype: Callable[[Iterable[T]], Collection[T]] = list,
|
|
205
|
+
) -> Collection[T]:
|
|
206
|
+
...
|
|
207
|
+
@overload
|
|
208
|
+
def collect[K, V](
|
|
209
|
+
iterable: AsyncIterable[tuple[K, V]],
|
|
210
|
+
/,
|
|
211
|
+
rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
|
|
212
|
+
) -> Coroutine[Any, Any, MutableMapping[K, V]]:
|
|
213
|
+
...
|
|
214
|
+
@overload
|
|
215
|
+
def collect[T](
|
|
216
|
+
iterable: AsyncIterable[T],
|
|
217
|
+
/,
|
|
218
|
+
rettype: Callable[[Iterable[T]], Collection[T]] = list,
|
|
219
|
+
) -> Coroutine[Any, Any, Collection[T]]:
|
|
220
|
+
...
|
|
221
|
+
def collect(
|
|
222
|
+
iterable: Iterable | AsyncIterable | Mapping,
|
|
223
|
+
/,
|
|
224
|
+
rettype: Callable[[Iterable], Collection] = list,
|
|
225
|
+
) -> Collection | Coroutine[Any, Any, Collection]:
|
|
226
|
+
if not isinstance(iterable, Iterable):
|
|
227
|
+
return async_collect(iterable, rettype)
|
|
228
|
+
return rettype(iterable)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@overload
|
|
232
|
+
def group_collect[K, V, C: Container](
|
|
233
|
+
iterable: Iterable[tuple[K, V]],
|
|
234
|
+
mapping: None = None,
|
|
235
|
+
factory: None | C | Callable[[], C] = None,
|
|
236
|
+
) -> dict[K, C]:
|
|
237
|
+
...
|
|
238
|
+
@overload
|
|
239
|
+
def group_collect[K, V, C: Container, M: MutableMapping](
|
|
240
|
+
iterable: Iterable[tuple[K, V]],
|
|
241
|
+
mapping: M,
|
|
242
|
+
factory: None | C | Callable[[], C] = None,
|
|
243
|
+
) -> M:
|
|
244
|
+
...
|
|
245
|
+
@overload
|
|
246
|
+
def group_collect[K, V, C: Container](
|
|
247
|
+
iterable: AsyncIterable[tuple[K, V]],
|
|
248
|
+
mapping: None = None,
|
|
249
|
+
factory: None | C | Callable[[], C] = None,
|
|
250
|
+
) -> Coroutine[Any, Any, dict[K, C]]:
|
|
251
|
+
...
|
|
252
|
+
@overload
|
|
253
|
+
def group_collect[K, V, C: Container, M: MutableMapping](
|
|
254
|
+
iterable: AsyncIterable[tuple[K, V]],
|
|
255
|
+
mapping: M,
|
|
256
|
+
factory: None | C | Callable[[], C] = None,
|
|
257
|
+
) -> Coroutine[Any, Any, M]:
|
|
258
|
+
...
|
|
259
|
+
def group_collect[K, V, C: Container, M: MutableMapping](
|
|
260
|
+
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
261
|
+
mapping: None | M = None,
|
|
262
|
+
factory: None | C | Callable[[], C] = None,
|
|
263
|
+
) -> dict[K, C] | M | Coroutine[Any, Any, dict[K, C]] | Coroutine[Any, Any, M]:
|
|
264
|
+
if not isinstance(iterable, Iterable):
|
|
265
|
+
return async_group_collect(iterable, mapping, factory)
|
|
266
|
+
if factory is None:
|
|
267
|
+
if isinstance(mapping, defaultdict):
|
|
268
|
+
factory = mapping.default_factory
|
|
269
|
+
elif mapping:
|
|
270
|
+
factory = type(next(iter(ValuesView(mapping))))
|
|
271
|
+
else:
|
|
272
|
+
factory = cast(type[C], list)
|
|
273
|
+
elif callable(factory):
|
|
274
|
+
pass
|
|
275
|
+
elif isinstance(factory, Container):
|
|
276
|
+
factory = cast(Callable[[], C], lambda _obj=factory: copy(_obj))
|
|
277
|
+
else:
|
|
278
|
+
raise ValueError("can't determine factory")
|
|
279
|
+
factory = cast(Callable[[], C], factory)
|
|
280
|
+
if isinstance(factory, type):
|
|
281
|
+
factory_type = factory
|
|
282
|
+
else:
|
|
283
|
+
factory_type = type(factory())
|
|
284
|
+
if issubclass(factory_type, MutableSequence):
|
|
285
|
+
add = getattr(factory_type, "append")
|
|
286
|
+
else:
|
|
287
|
+
add = getattr(factory_type, "add")
|
|
288
|
+
if mapping is None:
|
|
289
|
+
mapping = cast(M, {})
|
|
290
|
+
for k, v in iterable:
|
|
291
|
+
try:
|
|
292
|
+
c = mapping[k]
|
|
293
|
+
except LookupError:
|
|
294
|
+
c = mapping[k] = factory()
|
|
295
|
+
add(c, v)
|
|
296
|
+
return mapping
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
@overload
|
|
300
|
+
async def async_group_collect[K, V, C: Container](
|
|
301
|
+
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
302
|
+
mapping: None = None,
|
|
303
|
+
factory: None | C | Callable[[], C] = None,
|
|
304
|
+
threaded: bool = False,
|
|
305
|
+
) -> dict[K, C]:
|
|
306
|
+
...
|
|
307
|
+
@overload
|
|
308
|
+
async def async_group_collect[K, V, C: Container, M: MutableMapping](
|
|
309
|
+
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
310
|
+
mapping: M,
|
|
311
|
+
factory: None | C | Callable[[], C] = None,
|
|
312
|
+
threaded: bool = False,
|
|
313
|
+
) -> M:
|
|
314
|
+
...
|
|
315
|
+
async def async_group_collect[K, V, C: Container, M: MutableMapping](
|
|
316
|
+
iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
|
|
317
|
+
mapping: None | M = None,
|
|
318
|
+
factory: None | C | Callable[[], C] = None,
|
|
319
|
+
threaded: bool = False,
|
|
320
|
+
) -> dict[K, C] | M:
|
|
321
|
+
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
322
|
+
if factory is None:
|
|
323
|
+
if isinstance(mapping, defaultdict):
|
|
324
|
+
factory = mapping.default_factory
|
|
325
|
+
elif mapping:
|
|
326
|
+
factory = type(next(iter(ValuesView(mapping))))
|
|
327
|
+
else:
|
|
328
|
+
factory = cast(type[C], list)
|
|
329
|
+
elif callable(factory):
|
|
330
|
+
pass
|
|
331
|
+
elif isinstance(factory, Container):
|
|
332
|
+
factory = cast(Callable[[], C], lambda _obj=factory: copy(_obj))
|
|
333
|
+
else:
|
|
334
|
+
raise ValueError("can't determine factory")
|
|
335
|
+
factory = cast(Callable[[], C], factory)
|
|
336
|
+
if isinstance(factory, type):
|
|
337
|
+
factory_type = factory
|
|
338
|
+
else:
|
|
339
|
+
factory_type = type(factory())
|
|
340
|
+
if issubclass(factory_type, MutableSequence):
|
|
341
|
+
add = getattr(factory_type, "append")
|
|
342
|
+
else:
|
|
343
|
+
add = getattr(factory_type, "add")
|
|
344
|
+
if mapping is None:
|
|
345
|
+
mapping = cast(M, {})
|
|
346
|
+
async for k, v in iterable:
|
|
347
|
+
try:
|
|
348
|
+
c = mapping[k]
|
|
349
|
+
except LookupError:
|
|
350
|
+
c = mapping[k] = factory()
|
|
351
|
+
add(c, v)
|
|
352
|
+
return mapping
|
|
353
|
+
|
|
354
|
+
|
|
188
355
|
def map(
|
|
189
356
|
function: None | Callable,
|
|
190
357
|
iterable: Iterable | AsyncIterable,
|
|
@@ -398,7 +565,7 @@ async def wrap_aiter[T](
|
|
|
398
565
|
callnext: None | Callable[[T], Any] = None,
|
|
399
566
|
callenter: None | Callable[[Iterable[T] | AsyncIterable[T]], Any] = None,
|
|
400
567
|
callexit: None | Callable[[Iterable[T] | AsyncIterable[T], None | BaseException], Any] = None,
|
|
401
|
-
threaded: bool =
|
|
568
|
+
threaded: bool = False,
|
|
402
569
|
) -> AsyncIterator[T]:
|
|
403
570
|
callprev = ensure_async(callprev, threaded=threaded) if callable(callprev) else None
|
|
404
571
|
callnext = ensure_async(callnext, threaded=threaded) if callable(callnext) else None
|
|
@@ -452,13 +619,32 @@ def cut_iter(
|
|
|
452
619
|
yield stop, stop - start
|
|
453
620
|
|
|
454
621
|
|
|
622
|
+
def _get_async(back: int = 2) -> bool:
|
|
623
|
+
f: None | FrameType
|
|
624
|
+
f = _getframe(back)
|
|
625
|
+
f_globals = f.f_globals
|
|
626
|
+
f_locals = f.f_locals
|
|
627
|
+
if f_locals is f_globals:
|
|
628
|
+
return f_locals.get("async_") or False
|
|
629
|
+
while f_locals is not f_globals:
|
|
630
|
+
if "async_" in f_locals:
|
|
631
|
+
return f_locals["async_"] or False
|
|
632
|
+
f = f.f_back
|
|
633
|
+
if f is None:
|
|
634
|
+
break
|
|
635
|
+
f_locals = f.f_locals
|
|
636
|
+
return False
|
|
637
|
+
|
|
638
|
+
|
|
455
639
|
def run_gen_step[T](
|
|
456
640
|
gen_step: Generator[Any, Any, T] | Callable[[], Generator[Any, Any, T]],
|
|
457
641
|
*,
|
|
458
|
-
async_: bool =
|
|
642
|
+
async_: None | bool = None,
|
|
459
643
|
threaded: bool = False,
|
|
460
644
|
as_iter: bool = False,
|
|
461
645
|
) -> T:
|
|
646
|
+
if async_ is None:
|
|
647
|
+
async_ = _get_async()
|
|
462
648
|
if callable(gen_step):
|
|
463
649
|
gen = gen_step()
|
|
464
650
|
close = gen.close
|
|
@@ -561,7 +747,15 @@ def run_gen_step_iter(
|
|
|
561
747
|
gen_step: Generator | Callable[[], Generator],
|
|
562
748
|
threaded: bool = False,
|
|
563
749
|
*,
|
|
564
|
-
async_:
|
|
750
|
+
async_: None = None,
|
|
751
|
+
) -> Iterator | AsyncIterator:
|
|
752
|
+
...
|
|
753
|
+
@overload
|
|
754
|
+
def run_gen_step_iter(
|
|
755
|
+
gen_step: Generator | Callable[[], Generator],
|
|
756
|
+
threaded: bool = False,
|
|
757
|
+
*,
|
|
758
|
+
async_: Literal[False],
|
|
565
759
|
) -> Iterator:
|
|
566
760
|
...
|
|
567
761
|
@overload
|
|
@@ -576,8 +770,10 @@ def run_gen_step_iter(
|
|
|
576
770
|
gen_step: Generator | Callable[[], Generator],
|
|
577
771
|
threaded: bool = False,
|
|
578
772
|
*,
|
|
579
|
-
async_: bool =
|
|
773
|
+
async_: None | bool = None,
|
|
580
774
|
) -> Iterator | AsyncIterator:
|
|
775
|
+
if async_ is None:
|
|
776
|
+
async_ = _get_async()
|
|
581
777
|
if callable(gen_step):
|
|
582
778
|
gen = gen_step()
|
|
583
779
|
close = gen.close
|
|
@@ -687,9 +883,11 @@ def run_gen_step_iter(
|
|
|
687
883
|
def as_gen_step(
|
|
688
884
|
func: Callable,
|
|
689
885
|
/,
|
|
690
|
-
async_: bool =
|
|
886
|
+
async_: None | bool = None,
|
|
691
887
|
iter: bool = False,
|
|
692
888
|
) -> Callable:
|
|
889
|
+
if async_ is None:
|
|
890
|
+
async_ = _get_async()
|
|
693
891
|
def wrapper(*args, **kwds):
|
|
694
892
|
if iter:
|
|
695
893
|
return run_gen_step_iter(func(*args, **kwds), async_=async_) # type: ignore
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-iterutils"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.8"
|
|
4
4
|
description = "Python another itertools."
|
|
5
5
|
authors = ["ChenyangGao <wosiwujm@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -27,8 +27,8 @@ include = [
|
|
|
27
27
|
|
|
28
28
|
[tool.poetry.dependencies]
|
|
29
29
|
python = "^3.12"
|
|
30
|
-
python-asynctools = ">=0.0.10"
|
|
31
|
-
python-decotools = ">=0.0.
|
|
30
|
+
python-asynctools = ">=0.0.10.1"
|
|
31
|
+
python-decotools = ">=0.0.2"
|
|
32
32
|
python-texttools = ">=0.0.3"
|
|
33
33
|
python-undefined = ">=0.0.3"
|
|
34
34
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|