python-iterutils 0.3.0__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 +1 -1
- iterutils/dynamic.py +14 -47
- iterutils/gen_step.py +35 -2
- iterutils/misc.py +30 -78
- {python_iterutils-0.3.0.dist-info → python_iterutils-0.3.1.dist-info}/METADATA +3 -2
- python_iterutils-0.3.1.dist-info/RECORD +9 -0
- python_iterutils-0.3.0.dist-info/RECORD +0 -9
- {python_iterutils-0.3.0.dist-info → python_iterutils-0.3.1.dist-info}/WHEEL +0 -0
- {python_iterutils-0.3.0.dist-info → python_iterutils-0.3.1.dist-info}/licenses/LICENSE +0 -0
iterutils/__init__.py
CHANGED
iterutils/dynamic.py
CHANGED
|
@@ -3,58 +3,25 @@
|
|
|
3
3
|
|
|
4
4
|
__all__ = ["dynamic_async", "dynamic_async_iter"]
|
|
5
5
|
|
|
6
|
-
from asyncio import
|
|
7
|
-
from collections.abc import
|
|
8
|
-
AsyncIterable, AsyncIterator, Awaitable, Callable, Iterable, Iterator,
|
|
9
|
-
)
|
|
6
|
+
from asyncio import AbstractEventLoop
|
|
7
|
+
from collections.abc import AsyncIterable, Callable, Iterable
|
|
10
8
|
from inspect import isawaitable
|
|
11
9
|
|
|
12
10
|
from argtools import has_keyword_arg
|
|
13
|
-
from asynctools import
|
|
11
|
+
from asynctools import (
|
|
12
|
+
ensure_async, in_async, iter_async, run_async, to_coroutine,
|
|
13
|
+
to_aiter,
|
|
14
|
+
)
|
|
14
15
|
from decotools import optional
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
async def _as_async[T](v: T, /) -> T:
|
|
18
|
-
return v
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
async def _as_async_iter[T](
|
|
22
|
-
it: Iterable[T],
|
|
23
|
-
/,
|
|
24
|
-
threaded: bool = False,
|
|
25
|
-
) -> AsyncIterator[T]:
|
|
26
|
-
if threaded:
|
|
27
|
-
call = iter(it).__next__
|
|
28
|
-
try:
|
|
29
|
-
while True:
|
|
30
|
-
yield await to_thread(call)
|
|
31
|
-
except StopIteration:
|
|
32
|
-
pass
|
|
33
|
-
else:
|
|
34
|
-
for e in it:
|
|
35
|
-
yield e
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _as_iter[T](
|
|
39
|
-
it: AsyncIterable[T],
|
|
40
|
-
/,
|
|
41
|
-
run: Callable = asyncio_run,
|
|
42
|
-
) -> Iterator[T]:
|
|
43
|
-
try:
|
|
44
|
-
call = aiter(it).__anext__
|
|
45
|
-
while True:
|
|
46
|
-
yield run(call())
|
|
47
|
-
except StopAsyncIteration:
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
|
-
|
|
51
18
|
@optional
|
|
52
|
-
def dynamic_async
|
|
19
|
+
def dynamic_async(
|
|
53
20
|
func: Callable,
|
|
54
21
|
/,
|
|
55
|
-
run: Callable = asyncio_run,
|
|
56
22
|
threaded: bool = False,
|
|
57
23
|
async_: None | bool = None,
|
|
24
|
+
loop: None | AbstractEventLoop = None,
|
|
58
25
|
):
|
|
59
26
|
has_async_arg = has_keyword_arg(func, "async_")
|
|
60
27
|
def wrapper(*args, async_: None | bool = async_, **kwds):
|
|
@@ -68,22 +35,22 @@ def dynamic_async[T](
|
|
|
68
35
|
else:
|
|
69
36
|
r = func(*args, **kwds)
|
|
70
37
|
if not isawaitable(r):
|
|
71
|
-
r =
|
|
38
|
+
r = to_coroutine(r)
|
|
72
39
|
else:
|
|
73
40
|
r = func(*args, **kwds)
|
|
74
41
|
if isawaitable(r):
|
|
75
|
-
r =
|
|
42
|
+
r = run_async(r, loop)
|
|
76
43
|
return r
|
|
77
44
|
return wrapper
|
|
78
45
|
|
|
79
46
|
|
|
80
47
|
@optional
|
|
81
|
-
def dynamic_async_iter
|
|
48
|
+
def dynamic_async_iter(
|
|
82
49
|
func: Callable[..., Iterable] | Callable[..., AsyncIterable],
|
|
83
50
|
/,
|
|
84
|
-
run: Callable = asyncio_run,
|
|
85
51
|
threaded: bool = False,
|
|
86
52
|
async_: None | bool = None,
|
|
53
|
+
loop: None | AbstractEventLoop = None,
|
|
87
54
|
):
|
|
88
55
|
has_async_arg = has_keyword_arg(func, "async_")
|
|
89
56
|
def wrapper(*args, async_: None | bool = async_, **kwds):
|
|
@@ -94,9 +61,9 @@ def dynamic_async_iter[T](
|
|
|
94
61
|
it = func(*args, **kwds)
|
|
95
62
|
if async_:
|
|
96
63
|
if not isinstance(it, AsyncIterable):
|
|
97
|
-
it =
|
|
64
|
+
it = to_aiter(it, threaded=threaded)
|
|
98
65
|
elif isinstance(it, AsyncIterable):
|
|
99
|
-
it =
|
|
66
|
+
it = iter_async(it, loop)
|
|
100
67
|
return it
|
|
101
68
|
return wrapper
|
|
102
69
|
|
iterutils/gen_step.py
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
5
5
|
"iter_gen_step", "run_gen_step", "run_gen_step_iter",
|
|
6
|
-
"as_gen_step", "with_iter_next", "
|
|
6
|
+
"as_gen_step", "with_iter_next", "with_lock", "split_cm",
|
|
7
|
+
"Yield", "YieldFrom",
|
|
7
8
|
]
|
|
8
9
|
|
|
9
10
|
from asyncio import CancelledError as AsyncCancelledError
|
|
@@ -171,7 +172,7 @@ def run_gen_step[T](
|
|
|
171
172
|
/,
|
|
172
173
|
async_: Literal[True],
|
|
173
174
|
running: SupportsBool = True,
|
|
174
|
-
) ->
|
|
175
|
+
) -> Coroutine[Any, Any, T]:
|
|
175
176
|
...
|
|
176
177
|
def run_gen_step(
|
|
177
178
|
gen,
|
|
@@ -358,6 +359,38 @@ def with_iter_next[T](
|
|
|
358
359
|
pass
|
|
359
360
|
|
|
360
361
|
|
|
362
|
+
@contextmanager
|
|
363
|
+
def with_lock[T](lock, /):
|
|
364
|
+
"""包装锁,以供 `run_gen_step` 和 `run_gen_step_iter` 使用
|
|
365
|
+
|
|
366
|
+
.. code:: python
|
|
367
|
+
|
|
368
|
+
if async_:
|
|
369
|
+
async def process():
|
|
370
|
+
async with lock:
|
|
371
|
+
...
|
|
372
|
+
return process()
|
|
373
|
+
else:
|
|
374
|
+
with lock:
|
|
375
|
+
...
|
|
376
|
+
|
|
377
|
+
大概相当于
|
|
378
|
+
|
|
379
|
+
.. code:: python
|
|
380
|
+
|
|
381
|
+
def gen_step():
|
|
382
|
+
with with_lock(lock) as r:
|
|
383
|
+
yield r
|
|
384
|
+
...
|
|
385
|
+
|
|
386
|
+
run_gen_step(gen_step, async_)
|
|
387
|
+
"""
|
|
388
|
+
try:
|
|
389
|
+
yield lock.acquire()
|
|
390
|
+
finally:
|
|
391
|
+
lock.release()
|
|
392
|
+
|
|
393
|
+
|
|
361
394
|
@overload
|
|
362
395
|
def split_cm[T](
|
|
363
396
|
cm: AbstractContextManager[T],
|
iterutils/misc.py
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
5
|
-
"iterable", "
|
|
6
|
-
"chain", "chain_from_iterable", "chunked", "foreach", "
|
|
7
|
-
"
|
|
8
|
-
"async_collect", "group_collect", "async_group_collect", "iter_unique",
|
|
5
|
+
"iterable", "map", "filter", "reduce", "zip",
|
|
6
|
+
"chain", "chain_from_iterable", "chunked", "foreach", "through",
|
|
7
|
+
"flatten", "collect", "async_group_collect", "iter_unique",
|
|
9
8
|
"async_iter_unique", "wrap_iter", "wrap_aiter", "peek_iter", "peek_aiter",
|
|
10
9
|
"acc_step", "cut_iter", "context", "backgroud_loop", "gen_startup",
|
|
11
10
|
"async_gen_startup", "do_iter", "do_aiter", "bfs_iter", "bfs_gen",
|
|
@@ -24,7 +23,7 @@ from contextlib import asynccontextmanager, contextmanager, ExitStack, AsyncExit
|
|
|
24
23
|
from copy import copy
|
|
25
24
|
from functools import update_wrapper
|
|
26
25
|
from itertools import batched, chain as _chain, pairwise
|
|
27
|
-
from inspect import iscoroutinefunction
|
|
26
|
+
from inspect import isawaitable, iscoroutinefunction
|
|
28
27
|
from sys import _getframe
|
|
29
28
|
from _thread import start_new_thread
|
|
30
29
|
from time import sleep, time
|
|
@@ -35,17 +34,13 @@ from typing import (
|
|
|
35
34
|
|
|
36
35
|
from asynctools import (
|
|
37
36
|
async_filter, async_map, async_reduce, async_zip, async_batched,
|
|
38
|
-
ensure_async, ensure_aiter, async_chain,
|
|
37
|
+
ensure_async, ensure_aiter, async_chain, async_chain_from_iterable,
|
|
38
|
+
async_collect, async_foreach, async_through,
|
|
39
39
|
)
|
|
40
40
|
from texttools import format_time
|
|
41
41
|
from undefined import undefined
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
iterable = Iterable.__instancecheck__
|
|
45
|
-
async_iterable = AsyncIterable.__instancecheck__
|
|
46
|
-
isawaitable = Awaitable.__instancecheck__
|
|
47
|
-
|
|
48
|
-
|
|
49
44
|
def _coalesce(vals, default=None):
|
|
50
45
|
for val in vals:
|
|
51
46
|
if val is not None:
|
|
@@ -232,11 +227,8 @@ def chain_from_iterable[T](
|
|
|
232
227
|
*,
|
|
233
228
|
async_: Literal[False, True] = False,
|
|
234
229
|
) -> Iterator[T] | AsyncIterator[T]:
|
|
235
|
-
if async_ or
|
|
236
|
-
|
|
237
|
-
return async_chain.from_iterable(iterables, threaded=threaded)
|
|
238
|
-
else:
|
|
239
|
-
return async_chain.from_iterable(iterables, threaded=threaded)
|
|
230
|
+
if async_ or threaded:
|
|
231
|
+
return async_chain_from_iterable(iterables, threaded=threaded)
|
|
240
232
|
return _chain.from_iterable(iterables) # type: ignore
|
|
241
233
|
|
|
242
234
|
setattr(chain, "from_iterable", chain_from_iterable)
|
|
@@ -291,85 +283,45 @@ def chunked[T](
|
|
|
291
283
|
|
|
292
284
|
|
|
293
285
|
def foreach(
|
|
294
|
-
|
|
286
|
+
function: Callable,
|
|
295
287
|
iterable: Iterable | AsyncIterable,
|
|
296
288
|
/,
|
|
297
289
|
*iterables: Iterable | AsyncIterable,
|
|
290
|
+
default = None,
|
|
298
291
|
threaded: bool = False,
|
|
299
292
|
):
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
isinstance(iterable, Iterable) and
|
|
304
|
-
all(isinstance(it, Iterable) for it in iterables)
|
|
293
|
+
if (threaded or
|
|
294
|
+
isinstance(iterable, AsyncIterable) or
|
|
295
|
+
any(isinstance(it, AsyncIterable) for it in iterables)
|
|
305
296
|
):
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
async def async_foreach(
|
|
317
|
-
value: Callable,
|
|
318
|
-
iterable: Iterable | AsyncIterable,
|
|
319
|
-
/,
|
|
320
|
-
*iterables: Iterable | AsyncIterable,
|
|
321
|
-
threaded: bool = False,
|
|
322
|
-
):
|
|
323
|
-
"""
|
|
324
|
-
"""
|
|
325
|
-
value = ensure_async(value, threaded=threaded)
|
|
297
|
+
return async_foreach(
|
|
298
|
+
function,
|
|
299
|
+
iterable,
|
|
300
|
+
*iterables,
|
|
301
|
+
default=default,
|
|
302
|
+
threaded=threaded,
|
|
303
|
+
)
|
|
304
|
+
r = default
|
|
326
305
|
if iterables:
|
|
327
|
-
|
|
328
|
-
|
|
306
|
+
for args in _zip(iterable, *iterables):
|
|
307
|
+
r = function(*args)
|
|
329
308
|
else:
|
|
330
|
-
|
|
331
|
-
|
|
309
|
+
for arg in iterable:
|
|
310
|
+
r = function(arg)
|
|
311
|
+
return r
|
|
332
312
|
|
|
333
313
|
|
|
334
314
|
def through(
|
|
335
315
|
iterable: Iterable | AsyncIterable,
|
|
336
316
|
/,
|
|
337
|
-
take_while: None | Callable = None,
|
|
338
317
|
threaded: bool = False,
|
|
339
318
|
):
|
|
340
319
|
"""
|
|
341
320
|
"""
|
|
342
|
-
if threaded or
|
|
343
|
-
return async_through(iterable,
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
pass
|
|
347
|
-
else:
|
|
348
|
-
for v in _map(take_while, iterable):
|
|
349
|
-
if not v:
|
|
350
|
-
break
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
async def async_through(
|
|
354
|
-
iterable: Iterable | AsyncIterable,
|
|
355
|
-
/,
|
|
356
|
-
take_while: None | Callable = None,
|
|
357
|
-
threaded: bool = False,
|
|
358
|
-
):
|
|
359
|
-
"""
|
|
360
|
-
"""
|
|
361
|
-
iterable = ensure_aiter(iterable, threaded=threaded)
|
|
362
|
-
if take_while is None:
|
|
363
|
-
async for _ in iterable:
|
|
364
|
-
pass
|
|
365
|
-
elif take_while is bool:
|
|
366
|
-
async for v in iterable:
|
|
367
|
-
if not v:
|
|
368
|
-
break
|
|
369
|
-
else:
|
|
370
|
-
async for v in async_map(take_while, iterable):
|
|
371
|
-
if not v:
|
|
372
|
-
break
|
|
321
|
+
if threaded or isinstance(iterable, AsyncIterable):
|
|
322
|
+
return async_through(iterable, threaded=threaded)
|
|
323
|
+
for _ in iterable:
|
|
324
|
+
pass
|
|
373
325
|
|
|
374
326
|
|
|
375
327
|
@overload
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-iterutils
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Python another itertools.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -21,7 +21,8 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
21
21
|
Classifier: Topic :: Software Development
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Dist: python-
|
|
24
|
+
Requires-Dist: python-argtools (>=0.0.4)
|
|
25
|
+
Requires-Dist: python-asynctools (>=0.2.1)
|
|
25
26
|
Requires-Dist: python-texttools (>=0.0.6)
|
|
26
27
|
Requires-Dist: python-undefined (>=0.0.4)
|
|
27
28
|
Project-URL: Homepage, https://github.com/ChenyangGao/python-modules/tree/main/python-iterutils
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
iterutils/__init__.py,sha256=e3TnEvFCdzg6jotU3JB95qHwcA2DrkRJjrTMLF1rYWs,193
|
|
2
|
+
iterutils/dynamic.py,sha256=AxvY1H61BUxMWkTLK6lQDzfKeFQXmRbPadQSf3LJ3gs,1946
|
|
3
|
+
iterutils/gen_step.py,sha256=66QInXz4VxANWHNgmSQ3x6U5I6_pUfCtTRgjftdgeQE,11078
|
|
4
|
+
iterutils/misc.py,sha256=43ViCCJLc2MJGiisTCTbVhOHH5Akfc3ZW7kQlI7pm5c,27823
|
|
5
|
+
iterutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
python_iterutils-0.3.1.dist-info/METADATA,sha256=0cMSV_WHhomz5qnES44vCKzPYQWApzE_oVw_4zDkat8,1521
|
|
7
|
+
python_iterutils-0.3.1.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
|
|
8
|
+
python_iterutils-0.3.1.dist-info/licenses/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
|
9
|
+
python_iterutils-0.3.1.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
iterutils/__init__.py,sha256=Dxp6LiS0vgtgwo1QZJa1Q4Krxa50dFOai3SJK67tXnY,193
|
|
2
|
-
iterutils/dynamic.py,sha256=qYDPlg5JaF637kxo8e2V3OWtzAn3JKLrMGXjH5z4fvw,2555
|
|
3
|
-
iterutils/gen_step.py,sha256=Bi5KQO1FkcpTJ9gf1m5AZzsPoHUVQ0pLUiqnFdmKgBQ,10430
|
|
4
|
-
iterutils/misc.py,sha256=TTVOs6qSNBN5sQHpCzfmv3LaY8k5H7PFp6RdcsXRdtM,29222
|
|
5
|
-
iterutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
python_iterutils-0.3.0.dist-info/METADATA,sha256=NnIt3TLSSAM4ss3bwEx3EU8Ss87Va3TIAI4GU4yWcrc,1480
|
|
7
|
-
python_iterutils-0.3.0.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
|
|
8
|
-
python_iterutils-0.3.0.dist-info/licenses/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
|
9
|
-
python_iterutils-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|