python-iterutils 0.0.4.5__tar.gz → 0.0.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-iterutils
3
- Version: 0.0.4.5
3
+ Version: 0.0.6
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
@@ -2,18 +2,20 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 0, 4)
5
+ __version__ = (0, 0, 6)
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",
8
+ "wrap_iter", "wrap_aiter", "acc_step", "cut_iter", "run_gen_step", "run_gen_step_iter",
9
+ "Yield", "YieldFrom",
9
10
  ]
10
11
 
12
+ from abc import ABC, abstractmethod
11
13
  from asyncio import to_thread
12
14
  from collections.abc import (
13
15
  AsyncIterable, AsyncIterator, Awaitable, Callable, Generator, Iterable, Iterator,
14
16
  )
15
17
  from inspect import isawaitable
16
- from typing import Any, TypeVar
18
+ from typing import overload, Any, Literal, NamedTuple, TypeVar
17
19
 
18
20
  from asynctools import async_zip, ensure_async, ensure_aiter
19
21
 
@@ -21,6 +23,25 @@ from asynctools import async_zip, ensure_async, ensure_aiter
21
23
  T = TypeVar("T")
22
24
 
23
25
 
26
+ class YieldBase(ABC, Iterable):
27
+ __slots__ = "value", "identity"
28
+ @property
29
+ @abstractmethod
30
+ def yield_type(self, /) -> int:
31
+ ...
32
+
33
+
34
+ @YieldBase.register
35
+ class Yield(NamedTuple):
36
+ value: Any
37
+ identity: bool = False
38
+ yield_type = 1 # type: ignore
39
+
40
+
41
+ class YieldFrom(Yield):
42
+ yield_type = 2
43
+
44
+
24
45
  def iterable(it, /) -> bool:
25
46
  try:
26
47
  return isinstance(iter(it), Iterable)
@@ -35,23 +56,23 @@ def async_iterable(it, /) -> bool:
35
56
  return False
36
57
 
37
58
 
38
- def foreach(func: Callable, iterable, /, *iterables):
59
+ def foreach(ret: Callable, iterable, /, *iterables):
39
60
  if iterables:
40
61
  for args in zip(iterable, *iterables):
41
- func(*args)
62
+ ret(*args)
42
63
  else:
43
64
  for arg in iterable:
44
- func(arg)
65
+ ret(arg)
45
66
 
46
67
 
47
- async def async_foreach(func: Callable, iterable, /, *iterables, threaded: bool = True):
48
- func = ensure_async(func, threaded=threaded)
68
+ async def async_foreach(ret: Callable, iterable, /, *iterables, threaded: bool = True):
69
+ ret = ensure_async(ret, threaded=threaded)
49
70
  if iterables:
50
71
  async for args in async_zip(iterable, *iterables, threaded=threaded):
51
- await func(*args)
72
+ await ret(*args)
52
73
  else:
53
74
  async for arg in ensure_aiter(iterable, threaded=threaded):
54
- await func(arg)
75
+ await ret(arg)
55
76
 
56
77
 
57
78
  def through(it: Iterable, /):
@@ -186,29 +207,27 @@ def run_gen_step(
186
207
  async def process():
187
208
  try:
188
209
  if threaded:
189
- func = await to_thread(send, None)
210
+ ret = await to_thread(send, None)
190
211
  else:
191
- func = send(None)
212
+ ret = send(None)
192
213
  while True:
193
214
  try:
194
- if isawaitable(func):
195
- ret = await func
196
- elif callable(func):
197
- ret = func()
215
+ if isawaitable(ret):
216
+ ret = await ret
217
+ elif callable(ret):
218
+ ret = ret()
198
219
  if isawaitable(ret):
199
220
  ret = await ret
200
- else:
201
- ret = func
202
221
  except BaseException as e:
203
222
  if threaded:
204
- func = await to_thread(throw, e)
223
+ ret = await to_thread(throw, e)
205
224
  else:
206
- func = throw(e)
225
+ ret = throw(e)
207
226
  else:
208
227
  if threaded:
209
- func = await to_thread(send, ret)
228
+ ret = await to_thread(send, ret)
210
229
  else:
211
- func = send(ret)
230
+ ret = send(ret)
212
231
  except StopIteration as e:
213
232
  return e.value
214
233
  finally:
@@ -235,14 +254,15 @@ def run_gen_step(
235
254
  return result
236
255
  else:
237
256
  try:
238
- func = send(None)
257
+ ret = send(None)
239
258
  while True:
240
259
  try:
241
- ret = func() if callable(func) else ret
260
+ if callable(ret):
261
+ ret = ret()
242
262
  except BaseException as e:
243
- func = throw(e)
263
+ ret = throw(e)
244
264
  else:
245
- func = send(ret)
265
+ ret = send(ret)
246
266
  except StopIteration as e:
247
267
  result = e.value
248
268
  if as_iter:
@@ -252,3 +272,112 @@ def run_gen_step(
252
272
  if close is not None:
253
273
  close()
254
274
 
275
+
276
+ @overload
277
+ def run_gen_step_iter(
278
+ gen_step: Generator | Callable[[], Generator],
279
+ threaded: bool = False,
280
+ *,
281
+ async_: Literal[False] = False,
282
+ ) -> Iterator:
283
+ ...
284
+ @overload
285
+ def run_gen_step_iter(
286
+ gen_step: Generator | Callable[[], Generator],
287
+ threaded: bool = False,
288
+ *,
289
+ async_: Literal[True],
290
+ ) -> AsyncIterator:
291
+ ...
292
+ def run_gen_step_iter(
293
+ gen_step: Generator | Callable[[], Generator],
294
+ threaded: bool = False,
295
+ *,
296
+ async_: bool = False,
297
+ ) -> Iterator | AsyncIterator:
298
+ if callable(gen_step):
299
+ gen = gen_step()
300
+ close = gen.close
301
+ else:
302
+ gen = gen_step
303
+ close = None
304
+ send = gen.send
305
+ throw = gen.throw
306
+ if async_:
307
+ async def process():
308
+ try:
309
+ if threaded:
310
+ ret = await to_thread(send, None)
311
+ else:
312
+ ret = send(None)
313
+ while True:
314
+ yield_type = 0
315
+ identity = False
316
+ if isinstance(ret, YieldBase):
317
+ yield_type = ret.yield_type
318
+ ret, identity = ret
319
+ try:
320
+ if not identity:
321
+ if isawaitable(ret):
322
+ ret = await ret
323
+ elif callable(ret):
324
+ ret = ret()
325
+ if isawaitable(ret):
326
+ ret = await ret
327
+ else:
328
+ ret = ret
329
+ except BaseException as e:
330
+ if threaded:
331
+ ret = await to_thread(throw, e)
332
+ else:
333
+ ret = throw(e)
334
+ else:
335
+ match yield_type:
336
+ case 1:
337
+ yield ret
338
+ case 2:
339
+ async for val in ensure_aiter(ret, threaded=threaded):
340
+ yield val
341
+ if threaded:
342
+ ret = await to_thread(send, ret)
343
+ else:
344
+ ret = send(ret)
345
+ except (StopIteration, GeneratorExit):
346
+ pass
347
+ finally:
348
+ if close is not None:
349
+ if threaded:
350
+ await to_thread(close)
351
+ else:
352
+ close()
353
+ else:
354
+ def process():
355
+ try:
356
+ ret = send(None)
357
+ while True:
358
+ yield_type = 0
359
+ identity = False
360
+ if isinstance(ret, YieldBase):
361
+ yield_type = ret.yield_type
362
+ ret, identity = ret
363
+ try:
364
+ if not identity:
365
+ ret = ret() if callable(ret) else ret
366
+ except BaseException as e:
367
+ ret = throw(e)
368
+ else:
369
+ match yield_type:
370
+ case 1:
371
+ yield ret
372
+ case 2:
373
+ yield from ret
374
+ ret = send(ret)
375
+ except StopIteration as e:
376
+ return e.value
377
+ except GeneratorExit:
378
+ pass
379
+ finally:
380
+ if close is not None:
381
+ close()
382
+ return process()
383
+
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-iterutils"
3
- version = "0.0.4.5"
3
+ version = "0.0.6"
4
4
  description = "Python another itertools."
5
5
  authors = ["ChenyangGao <wosiwujm@gmail.com>"]
6
6
  license = "MIT"