python-iterutils 0.0.1__tar.gz → 0.0.2.2__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.0.1 → python_iterutils-0.0.2.2}/PKG-INFO +2 -1
- python_iterutils-0.0.2.2/iterutils/__init__.py +126 -0
- {python_iterutils-0.0.1 → python_iterutils-0.0.2.2}/pyproject.toml +2 -1
- python_iterutils-0.0.1/iterutils/__init__.py +0 -109
- {python_iterutils-0.0.1 → python_iterutils-0.0.2.2}/LICENSE +0 -0
- {python_iterutils-0.0.1 → python_iterutils-0.0.2.2}/iterutils/py.typed +0 -0
- {python_iterutils-0.0.1 → python_iterutils-0.0.2.2}/readme.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-iterutils
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2.2
|
|
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
|
|
@@ -21,6 +21,7 @@ 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-asynctools
|
|
24
25
|
Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-iterutils
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
26
27
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
5
|
+
__version__ = (0, 0, 2)
|
|
6
|
+
__all__ = [
|
|
7
|
+
"iterable", "async_iterable", "foreach", "async_foreach", "through", "async_through",
|
|
8
|
+
"wrap_iter", "wrap_aiter", "acc_step", "cut_iter",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
from collections.abc import AsyncIterable, AsyncIterator, Callable, Iterable, Iterator
|
|
12
|
+
from typing import Any, TypeVar
|
|
13
|
+
|
|
14
|
+
from asynctools import async_zip, ensure_async, ensure_aiter
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
T = TypeVar("T")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def iterable(it, /) -> bool:
|
|
21
|
+
try:
|
|
22
|
+
return isinstance(iter(it), Iterable)
|
|
23
|
+
except TypeError:
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def async_iterable(it, /) -> bool:
|
|
28
|
+
try:
|
|
29
|
+
return isinstance(iter(it), AsyncIterable)
|
|
30
|
+
except TypeError:
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def foreach(func: Callable, iterable, /, *iterables):
|
|
35
|
+
if iterables:
|
|
36
|
+
for args in zip(iterable, *iterables):
|
|
37
|
+
func(*args)
|
|
38
|
+
else:
|
|
39
|
+
for arg in iterable:
|
|
40
|
+
func(arg)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def async_foreach(func: Callable, iterable, /, *iterables, threaded: bool = True):
|
|
44
|
+
func = ensure_async(func, threaded=threaded)
|
|
45
|
+
if iterables:
|
|
46
|
+
async for args in async_zip(iterable, *iterables, threaded=threaded):
|
|
47
|
+
await func(*args)
|
|
48
|
+
else:
|
|
49
|
+
async for arg in ensure_aiter(iterable, threaded=threaded):
|
|
50
|
+
await func(arg)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def through(it: Iterable, /):
|
|
54
|
+
for _ in it:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def async_through(
|
|
59
|
+
it: Iterable | AsyncIterable,
|
|
60
|
+
/,
|
|
61
|
+
threaded: bool = True,
|
|
62
|
+
):
|
|
63
|
+
async for _ in ensure_aiter(it, threaded=threaded):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def wrap_iter(
|
|
68
|
+
it: Iterable[T],
|
|
69
|
+
/,
|
|
70
|
+
callprev: None | Callable[[T], Any] = None,
|
|
71
|
+
callnext: None | Callable[[T], Any] = None,
|
|
72
|
+
) -> Iterator[T]:
|
|
73
|
+
if not callable(callprev):
|
|
74
|
+
callprev = None
|
|
75
|
+
if not callable(callnext):
|
|
76
|
+
callnext = None
|
|
77
|
+
for e in it:
|
|
78
|
+
if callprev:
|
|
79
|
+
callprev(e)
|
|
80
|
+
yield e
|
|
81
|
+
if callnext:
|
|
82
|
+
callnext(e)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def wrap_aiter(
|
|
86
|
+
it: Iterable[T] | AsyncIterable[T],
|
|
87
|
+
/,
|
|
88
|
+
callprev: None | Callable[[T], Any] = None,
|
|
89
|
+
callnext: None | Callable[[T], Any] = None,
|
|
90
|
+
threaded: bool = True,
|
|
91
|
+
) -> AsyncIterator[T]:
|
|
92
|
+
callprev = ensure_async(callprev) if callable(callprev) else None
|
|
93
|
+
callnext = ensure_async(callnext) if callable(callnext) else None
|
|
94
|
+
async for e in ensure_aiter(it, threaded=threaded):
|
|
95
|
+
if callprev:
|
|
96
|
+
await callprev(e)
|
|
97
|
+
yield e
|
|
98
|
+
if callnext:
|
|
99
|
+
await callnext(e)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def acc_step(
|
|
103
|
+
start: int,
|
|
104
|
+
stop: None | int = None,
|
|
105
|
+
step: int = 1,
|
|
106
|
+
) -> Iterator[tuple[int, int, int]]:
|
|
107
|
+
if stop is None:
|
|
108
|
+
start, stop = 0, start
|
|
109
|
+
for i in range(start + step, stop, step):
|
|
110
|
+
yield start, (start := i), step
|
|
111
|
+
if start != stop:
|
|
112
|
+
yield start, stop, stop - start
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def cut_iter(
|
|
116
|
+
start: int,
|
|
117
|
+
stop: None | int = None,
|
|
118
|
+
step: int = 1,
|
|
119
|
+
) -> Iterator[tuple[int, int]]:
|
|
120
|
+
if stop is None:
|
|
121
|
+
start, stop = 0, start
|
|
122
|
+
for start in range(start + step, stop, step):
|
|
123
|
+
yield start, step
|
|
124
|
+
if start != stop:
|
|
125
|
+
yield stop, stop - start
|
|
126
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-iterutils"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.2.2"
|
|
4
4
|
description = "Python another itertools."
|
|
5
5
|
authors = ["ChenyangGao <wosiwujm@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -27,6 +27,7 @@ include = [
|
|
|
27
27
|
|
|
28
28
|
[tool.poetry.dependencies]
|
|
29
29
|
python = "^3.10"
|
|
30
|
+
python-asynctools = "*"
|
|
30
31
|
|
|
31
32
|
[build-system]
|
|
32
33
|
requires = ["poetry-core"]
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# encoding: utf-8
|
|
3
|
-
|
|
4
|
-
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
5
|
-
__version__ = (0, 0, 1)
|
|
6
|
-
__all__ = ["iterable", "async_iterable", "acc_step", "cut_iter", "asyncify_iter"]
|
|
7
|
-
|
|
8
|
-
from asyncio import to_thread
|
|
9
|
-
from collections.abc import AsyncGenerator, AsyncIterable, Generator, Iterable, Iterator
|
|
10
|
-
from typing import overload, Any, Optional, TypeVar
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
TI = TypeVar("TI")
|
|
14
|
-
TO = TypeVar("TO")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def iterable(it, /) -> bool:
|
|
18
|
-
try:
|
|
19
|
-
return isinstance(iter(it), Iterable)
|
|
20
|
-
except TypeError:
|
|
21
|
-
return False
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def async_iterable(it, /) -> bool:
|
|
25
|
-
try:
|
|
26
|
-
return isinstance(iter(it), AsyncIterable)
|
|
27
|
-
except TypeError:
|
|
28
|
-
return False
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def acc_step(
|
|
32
|
-
start: int,
|
|
33
|
-
stop: Optional[int] = None,
|
|
34
|
-
step: int = 1,
|
|
35
|
-
) -> Iterator[tuple[int, int, int]]:
|
|
36
|
-
if stop is None:
|
|
37
|
-
start, stop = 0, start
|
|
38
|
-
for i in range(start + step, stop, step):
|
|
39
|
-
yield start, (start := i), step
|
|
40
|
-
if start != stop:
|
|
41
|
-
yield start, stop, stop - start
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def cut_iter(
|
|
45
|
-
start: int,
|
|
46
|
-
stop: Optional[int] = None,
|
|
47
|
-
step: int = 1,
|
|
48
|
-
) -> Iterator[tuple[int, int]]:
|
|
49
|
-
if stop is None:
|
|
50
|
-
start, stop = 0, start
|
|
51
|
-
for start in range(start + step, stop, step):
|
|
52
|
-
yield start, step
|
|
53
|
-
if start != stop:
|
|
54
|
-
yield stop, stop - start
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@overload
|
|
58
|
-
async def _asyncify_iter(it: Generator[TI, TO, Any], /, wait_for_thread: bool) -> AsyncGenerator[TI, TO]: ...
|
|
59
|
-
@overload
|
|
60
|
-
async def _asyncify_iter(it: Iterable[TO], /, wait_for_thread: bool) -> AsyncGenerator[Any, TO]: ...
|
|
61
|
-
async def _asyncify_iter(it, /, wait_for_thread: bool = False):
|
|
62
|
-
if wait_for_thread:
|
|
63
|
-
if isinstance(it, Generator):
|
|
64
|
-
send = it.send
|
|
65
|
-
def nextval(val):
|
|
66
|
-
try:
|
|
67
|
-
return send(val), None
|
|
68
|
-
except BaseException as e:
|
|
69
|
-
return None, e
|
|
70
|
-
else:
|
|
71
|
-
getnext = iter(it).__next__
|
|
72
|
-
def nextval(val):
|
|
73
|
-
try:
|
|
74
|
-
return getnext(), None
|
|
75
|
-
except BaseException as e:
|
|
76
|
-
return None, e
|
|
77
|
-
val = None
|
|
78
|
-
while True:
|
|
79
|
-
yield_val, exc = await to_thread(nextval, val)
|
|
80
|
-
if exc is None:
|
|
81
|
-
yield yield_val
|
|
82
|
-
elif isinstance(exc, StopIteration):
|
|
83
|
-
break
|
|
84
|
-
else:
|
|
85
|
-
raise exc
|
|
86
|
-
elif isinstance(it, Generator):
|
|
87
|
-
send = it.send
|
|
88
|
-
val = None
|
|
89
|
-
try:
|
|
90
|
-
while True:
|
|
91
|
-
val = yield send(val)
|
|
92
|
-
except StopIteration:
|
|
93
|
-
pass
|
|
94
|
-
else:
|
|
95
|
-
for val in it:
|
|
96
|
-
yield val
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
@overload
|
|
100
|
-
def asyncify_iter(it: AsyncIterable[TO], /, wait_for_thread: bool) -> AsyncIterable[TO]: ...
|
|
101
|
-
@overload
|
|
102
|
-
def asyncify_iter(it: Generator[TI, TO, Any], /, wait_for_thread: bool) -> AsyncGenerator[TI, TO]: ...
|
|
103
|
-
@overload
|
|
104
|
-
def asyncify_iter(it: Iterable[TO], /, wait_for_thread: bool) -> AsyncGenerator[Any, TO]: ...
|
|
105
|
-
def asyncify_iter(it, /, wait_for_thread: bool = False):
|
|
106
|
-
if isinstance(it, AsyncIterable):
|
|
107
|
-
return it
|
|
108
|
-
return _asyncify_iter(it, wait_for_thread=wait_for_thread)
|
|
109
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|