python-iterutils 0.0.9__py3-none-any.whl → 0.1.0__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 CHANGED
@@ -2,26 +2,26 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 0, 9)
5
+ __version__ = (0, 1, 0)
6
6
  __all__ = [
7
7
  "iterable", "async_iterable", "foreach", "async_foreach", "through", "async_through",
8
- "wrap_iter", "wrap_aiter", "acc_step", "cut_iter", "run_gen_step", "run_gen_step_iter",
9
- "Return", "Yield", "YieldFrom",
8
+ "flatten", "async_flatten", "chunked", "wrap_iter", "wrap_aiter", "acc_step",
9
+ "cut_iter", "run_gen_step", "run_gen_step_iter", "Return", "Yield", "YieldFrom",
10
10
  ]
11
11
 
12
+
12
13
  from abc import ABC, abstractmethod
13
14
  from asyncio import to_thread
14
15
  from collections.abc import (
15
- AsyncIterable, AsyncIterator, Callable, Generator, Iterable, Iterator,
16
+ AsyncIterable, AsyncIterator, Buffer, Callable, Generator,
17
+ Iterable, Iterator, Sequence,
16
18
  )
17
19
  from dataclasses import dataclass
20
+ from itertools import batched, pairwise
18
21
  from inspect import isawaitable
19
- from typing import overload, Any, Literal, TypeVar
20
-
21
- from asynctools import async_map, async_zip, ensure_async, ensure_aiter
22
-
22
+ from typing import overload, Any, Literal
23
23
 
24
- T = TypeVar("T")
24
+ from asynctools import async_map, async_zip, async_batched, ensure_async, ensure_aiter
25
25
 
26
26
 
27
27
  @dataclass(slots=True, frozen=True)
@@ -48,21 +48,28 @@ class YieldFrom(YieldBase):
48
48
  yield_type = 2
49
49
 
50
50
 
51
- def iterable(it, /) -> bool:
51
+ def iterable(iterable, /) -> bool:
52
52
  try:
53
- return isinstance(iter(it), Iterable)
53
+ return isinstance(iter(iterable), Iterable)
54
54
  except TypeError:
55
55
  return False
56
56
 
57
57
 
58
- def async_iterable(it, /) -> bool:
58
+ def async_iterable(iterable, /) -> bool:
59
59
  try:
60
- return isinstance(iter(it), AsyncIterable)
60
+ return isinstance(iter(iterable), AsyncIterable)
61
61
  except TypeError:
62
62
  return False
63
63
 
64
64
 
65
- def foreach(value: Callable, iterable, /, *iterables):
65
+ def foreach(
66
+ value: Callable,
67
+ iterable: Iterable | AsyncIterable,
68
+ /,
69
+ *iterables: Iterable | AsyncIterable,
70
+ ):
71
+ if not (isinstance(iterable, Iterable) and all(isinstance(it, Iterable) for it in iterables)):
72
+ return async_foreach(value, iterable, *iterables)
66
73
  if iterables:
67
74
  for args in zip(iterable, *iterables):
68
75
  value(*args)
@@ -71,7 +78,13 @@ def foreach(value: Callable, iterable, /, *iterables):
71
78
  value(arg)
72
79
 
73
80
 
74
- async def async_foreach(value: Callable, iterable, /, *iterables, threaded: bool = True):
81
+ async def async_foreach(
82
+ value: Callable,
83
+ iterable: Iterable | AsyncIterable,
84
+ /,
85
+ *iterables: Iterable | AsyncIterable,
86
+ threaded: bool = True,
87
+ ):
75
88
  value = ensure_async(value, threaded=threaded)
76
89
  if iterables:
77
90
  async for args in async_zip(iterable, *iterables, threaded=threaded):
@@ -81,76 +94,188 @@ async def async_foreach(value: Callable, iterable, /, *iterables, threaded: bool
81
94
  await value(arg)
82
95
 
83
96
 
84
- def through(it: Iterable, /, take_while: None | Callable = None):
97
+ def through(
98
+ iterable: Iterable | AsyncIterable,
99
+ /,
100
+ take_while: None | Callable = None,
101
+ ):
102
+ if not isinstance(iterable, Iterable):
103
+ return async_through(iterable, take_while)
85
104
  if take_while is None:
86
- for _ in it:
105
+ for _ in iterable:
87
106
  pass
88
107
  else:
89
- for v in map(take_while, it):
108
+ for v in map(take_while, iterable):
90
109
  if not v:
91
110
  break
92
111
 
93
112
 
94
113
  async def async_through(
95
- it: Iterable | AsyncIterable,
114
+ iterable: Iterable | AsyncIterable,
96
115
  /,
97
116
  take_while: None | Callable = None,
98
117
  threaded: bool = True,
99
118
  ):
100
- it = ensure_aiter(it, threaded=threaded)
119
+ iterable = ensure_aiter(iterable, threaded=threaded)
101
120
  if take_while is None:
102
- async for _ in it:
121
+ async for _ in iterable:
103
122
  pass
104
123
  elif take_while is bool:
105
- async for v in it:
124
+ async for v in iterable:
106
125
  if not v:
107
126
  break
108
127
  else:
109
- async for v in async_map(take_while, it):
128
+ async for v in async_map(take_while, iterable):
110
129
  if not v:
111
130
  break
112
131
 
113
132
 
114
- def wrap_iter(
115
- it: Iterable[T],
133
+ @overload
134
+ def flatten(
135
+ iterable: Iterable,
136
+ /,
137
+ exclude_types: type | tuple[type, ...] = (Buffer, str),
138
+ ) -> Iterable:
139
+ ...
140
+ @overload
141
+ def flatten(
142
+ iterable: AsyncIterable,
143
+ /,
144
+ exclude_types: type | tuple[type, ...] = (Buffer, str),
145
+ ) -> AsyncIterable:
146
+ ...
147
+ def flatten(
148
+ iterable: Iterable | AsyncIterable,
149
+ /,
150
+ exclude_types: type | tuple[type, ...] = (Buffer, str),
151
+ ) -> Iterable | AsyncIterable:
152
+ if not isinstance(iterable, Iterable):
153
+ return async_flatten(iterable, exclude_types)
154
+ def gen(iterable):
155
+ for e in iterable:
156
+ if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
157
+ yield from gen(e)
158
+ else:
159
+ yield e
160
+ return gen(iterable)
161
+
162
+
163
+ async def async_flatten(
164
+ iterable: Iterable | AsyncIterable,
165
+ /,
166
+ exclude_types: type | tuple[type, ...] = (Buffer, str),
167
+ threaded: bool = True,
168
+ ) -> AsyncIterator:
169
+ async for e in ensure_aiter(iterable, threaded=threaded):
170
+ if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
171
+ async for e in async_flatten(e, exclude_types, threaded=threaded):
172
+ yield e
173
+ else:
174
+ yield e
175
+
176
+
177
+ @overload
178
+ def chunked[T](
179
+ iterable: Iterable[T],
180
+ n: int = 1,
181
+ /,
182
+ ) -> Iterator[Sequence[T]]:
183
+ ...
184
+ @overload
185
+ def chunked[T](
186
+ iterable: AsyncIterable[T],
187
+ n: int = 1,
188
+ /,
189
+ ) -> AsyncIterator[Sequence[T]]:
190
+ ...
191
+ def chunked[T](
192
+ iterable: Iterable[T] | AsyncIterable[T],
193
+ n: int = 1,
194
+ /,
195
+ ) -> Iterator[Sequence[T]] | AsyncIterator[Sequence[T]]:
196
+ if n < 0:
197
+ n = 1
198
+ if isinstance(iterable, Sequence):
199
+ if n == 1:
200
+ return ((e,) for e in iterable)
201
+ return (iterable[i:j] for i, j in pairwise(range(0, len(iterable)+n, n)))
202
+ elif isinstance(iterable, Iterable):
203
+ return batched(iterable, n)
204
+ else:
205
+ return async_batched(iterable, n)
206
+
207
+
208
+ @overload
209
+ def wrap_iter[T](
210
+ iterable: Iterable[T],
116
211
  /,
117
212
  callprev: None | Callable[[T], Any] = None,
118
213
  callnext: None | Callable[[T], Any] = None,
119
214
  callenter: None | Callable[[Iterable[T]], Any] = None,
120
215
  callexit: None | Callable[[Iterable[T], None | BaseException], Any] = None,
121
216
  ) -> Iterator[T]:
217
+ ...
218
+ @overload
219
+ def wrap_iter[T](
220
+ iterable: AsyncIterable[T],
221
+ /,
222
+ callprev: None | Callable[[T], Any] = None,
223
+ callnext: None | Callable[[T], Any] = None,
224
+ callenter: None | Callable[[Iterable[T] | AsyncIterable[T]], Any] = None,
225
+ callexit: None | Callable[[Iterable[T] | AsyncIterable[T], None | BaseException], Any] = None,
226
+ ) -> AsyncIterator[T]:
227
+ ...
228
+ def wrap_iter[T](
229
+ iterable: Iterable[T] | AsyncIterable[T],
230
+ /,
231
+ callprev: None | Callable[[T], Any] = None,
232
+ callnext: None | Callable[[T], Any] = None,
233
+ callenter: None | Callable[[Iterable[T]], Any] | Callable[[Iterable[T] | AsyncIterable[T]], Any] = None,
234
+ callexit: ( None | Callable[[Iterable[T], None | BaseException], Any] |
235
+ Callable[[Iterable[T] | AsyncIterable[T], None | BaseException], Any] ) = None,
236
+ ) -> Iterator[T] | AsyncIterator[T]:
237
+ if not isinstance(iterable, Iterable):
238
+ return wrap_aiter(
239
+ iterable,
240
+ callprev=callprev,
241
+ callnext=callnext,
242
+ callenter=callenter, # type: ignore
243
+ callexit=callexit, # type: ignore
244
+ )
122
245
  if not callable(callprev):
123
246
  callprev = None
124
247
  if not callable(callnext):
125
248
  callnext = None
126
- try:
127
- if callable(callenter):
128
- callenter(it)
129
- for e in it:
130
- if callprev:
131
- try:
132
- callprev(e)
133
- except (StopIteration, GeneratorExit):
134
- break
135
- yield e
136
- if callnext:
137
- try:
138
- callnext(e)
139
- except (StopIteration, GeneratorExit):
140
- break
141
- except BaseException as e:
142
- if callable(callexit):
143
- if not callexit(it, e):
249
+ def gen():
250
+ try:
251
+ if callable(callenter):
252
+ callenter(iterable)
253
+ for e in iterable:
254
+ if callprev:
255
+ try:
256
+ callprev(e)
257
+ except (StopIteration, GeneratorExit):
258
+ break
259
+ yield e
260
+ if callnext:
261
+ try:
262
+ callnext(e)
263
+ except (StopIteration, GeneratorExit):
264
+ break
265
+ except BaseException as e:
266
+ if callable(callexit):
267
+ if not callexit(iterable, e):
268
+ raise
269
+ else:
144
270
  raise
145
- else:
146
- raise
147
- finally:
148
- if callable(callexit):
149
- callexit(it, None)
271
+ finally:
272
+ if callable(callexit):
273
+ callexit(iterable, None)
274
+ return gen()
150
275
 
151
276
 
152
- async def wrap_aiter(
153
- it: Iterable[T] | AsyncIterable[T],
277
+ async def wrap_aiter[T](
278
+ iterable: Iterable[T] | AsyncIterable[T],
154
279
  /,
155
280
  callprev: None | Callable[[T], Any] = None,
156
281
  callnext: None | Callable[[T], Any] = None,
@@ -161,7 +286,7 @@ async def wrap_aiter(
161
286
  callprev = ensure_async(callprev, threaded=threaded) if callable(callprev) else None
162
287
  callnext = ensure_async(callnext, threaded=threaded) if callable(callnext) else None
163
288
  try:
164
- async for e in ensure_aiter(it, threaded=threaded):
289
+ async for e in ensure_aiter(iterable, threaded=threaded):
165
290
  if callprev:
166
291
  try:
167
292
  await callprev(e)
@@ -175,13 +300,13 @@ async def wrap_aiter(
175
300
  break
176
301
  except BaseException as e:
177
302
  if callable(callexit):
178
- if not await ensure_async(callexit, threaded=threaded)(it, e):
303
+ if not await ensure_async(callexit, threaded=threaded)(iterable, e):
179
304
  raise
180
305
  else:
181
306
  raise
182
307
  finally:
183
308
  if callable(callexit):
184
- await ensure_async(callexit, threaded=threaded)(it, None)
309
+ await ensure_async(callexit, threaded=threaded)(iterable, None)
185
310
 
186
311
 
187
312
  def acc_step(
@@ -210,7 +335,7 @@ def cut_iter(
210
335
  yield stop, stop - start
211
336
 
212
337
 
213
- def run_gen_step(
338
+ def run_gen_step[T](
214
339
  gen_step: Generator[Any, Any, T] | Callable[[], Generator[Any, Any, T]],
215
340
  *,
216
341
  async_: bool = False,
@@ -272,16 +397,16 @@ def run_gen_step(
272
397
  result = process()
273
398
  if as_iter:
274
399
  async def wrap(result):
275
- it = await result
400
+ iterable = await result
276
401
  try:
277
- it = aiter(it)
402
+ iterable = aiter(iterable)
278
403
  except TypeError:
279
- for val in iter(it):
404
+ for val in iter(iterable):
280
405
  if isawaitable(val):
281
406
  val = await val
282
407
  yield val
283
408
  else:
284
- async for val in it:
409
+ async for val in iterable:
285
410
  yield val
286
411
  result = wrap(result)
287
412
  return result
@@ -1,28 +1,26 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-iterutils
3
- Version: 0.0.9
3
+ Version: 0.1.0
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
7
7
  Keywords: iterable,iterutils
8
8
  Author: ChenyangGao
9
9
  Author-email: wosiwujm@gmail.com
10
- Requires-Python: >=3.10,<4.0
10
+ Requires-Python: >=3.12,<4.0
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
17
  Classifier: Programming Language :: Python :: 3.12
20
18
  Classifier: Programming Language :: Python :: 3.13
21
19
  Classifier: Programming Language :: Python :: 3 :: Only
22
20
  Classifier: Topic :: Software Development
23
21
  Classifier: Topic :: Software Development :: Libraries
24
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
- Requires-Dist: python-asynctools (>=0.0.8.2)
23
+ Requires-Dist: python-asynctools (>=0.0.9)
26
24
  Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-iterutils
27
25
  Description-Content-Type: text/markdown
28
26
 
@@ -0,0 +1,7 @@
1
+ LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
+ iterutils/__init__.py,sha256=m6CldG12romSrteHnbHufKlmbRjzd6LfnsxqrqCETwM,17487
3
+ iterutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ python_iterutils-0.1.0.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
5
+ python_iterutils-0.1.0.dist-info/METADATA,sha256=a1p4ibqdGfFKWEhsNSv80GJwd3PiNr7JNCmVOBEAb2U,1341
6
+ python_iterutils-0.1.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
7
+ python_iterutils-0.1.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
- iterutils/__init__.py,sha256=1rn-CbwE-giO8p78etuppB6oUN4-g1vMRcAl3hrsPP8,13520
3
- iterutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- python_iterutils-0.0.9.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
5
- python_iterutils-0.0.9.dist-info/METADATA,sha256=N2GQcGvPH0jn7dvUbL08QnHb9ECe4q0KnDk7kIghAO0,1445
6
- python_iterutils-0.0.9.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
7
- python_iterutils-0.0.9.dist-info/RECORD,,