python-iterutils 0.2.4.1__tar.gz → 0.2.5.1__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.2.4.1
3
+ Version: 0.2.5.1
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,7 +20,7 @@ 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.1.2)
23
+ Requires-Dist: python-asynctools (>=0.1.3.4)
24
24
  Requires-Dist: python-texttools (>=0.0.3)
25
25
  Requires-Dist: python-undefined (>=0.0.3)
26
26
  Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-iterutils
@@ -2,13 +2,14 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 2, 4)
5
+ __version__ = (0, 2, 5)
6
6
  __all__ = [
7
7
  "Yield", "YieldFrom", "iterable", "async_iterable",
8
8
  "run_gen_step", "run_gen_step_iter", "as_gen_step",
9
9
  "as_gen_step_iter", "split_cm, ""with_iter_next",
10
- "map", "filter", "reduce", "zip", "chunked",
11
- "foreach", "async_foreach", "through", "async_through",
10
+ "map", "filter", "reduce", "zip", "chain",
11
+ "chain_from_iterable", "chunked", "foreach",
12
+ "async_foreach", "through", "async_through",
12
13
  "flatten", "async_flatten", "collect", "async_collect",
13
14
  "group_collect", "async_group_collect", "iter_unique",
14
15
  "async_iter_unique", "wrap_iter", "wrap_aiter", "acc_step",
@@ -30,7 +31,7 @@ from contextlib import (
30
31
  )
31
32
  from copy import copy
32
33
  from dataclasses import dataclass
33
- from itertools import batched, pairwise
34
+ from itertools import batched, chain as _chain, pairwise
34
35
  from inspect import isawaitable, iscoroutinefunction, signature
35
36
  from sys import _getframe, exc_info
36
37
  from _thread import start_new_thread
@@ -42,7 +43,7 @@ from typing import (
42
43
 
43
44
  from asynctools import (
44
45
  async_filter, async_map, async_reduce, async_zip, async_batched,
45
- ensure_async, ensure_aiter, collect as async_collect,
46
+ ensure_async, ensure_aiter, async_chain, collect as async_collect,
46
47
  )
47
48
  from texttools import format_time
48
49
  from undefined import undefined
@@ -338,7 +339,7 @@ def split_cm[T](
338
339
  finally:
339
340
  yield exit()
340
341
 
341
- run_gen_step(gen_step, async_=async_)
342
+ run_gen_step(gen_step, async_)
342
343
  """
343
344
  if isinstance(cm, AbstractAsyncContextManager):
344
345
  enter: Callable = cm.__aenter__
@@ -389,7 +390,7 @@ def with_iter_next[T](
389
390
  e = yield do_next()
390
391
  do_what_you_want()
391
392
 
392
- run_gen_step(gen_step, async_=async_)
393
+ run_gen_step(gen_step, async_)
393
394
  """
394
395
  if isinstance(iterable, AsyncIterable):
395
396
  try:
@@ -408,17 +409,21 @@ def map(
408
409
  iterable: Iterable | AsyncIterable,
409
410
  /,
410
411
  *iterables: Iterable | AsyncIterable,
412
+ threaded: bool = False,
411
413
  ):
412
414
  """
413
415
  """
414
416
  if (
417
+ threaded or
415
418
  iscoroutinefunction(function) or
416
419
  isinstance(iterable, AsyncIterable) or
417
420
  any(isinstance(i, AsyncIterable) for i in iterables)
418
421
  ):
419
422
  if function is None:
420
423
  if iterables:
421
- return async_zip(iterable, *iterables)
424
+ return async_zip(iterable, *iterables, threaded=threaded)
425
+ elif threaded:
426
+ return ensure_aiter(iterable, threaded=threaded)
422
427
  else:
423
428
  return iterable
424
429
  return async_map(function, iterable, *iterables)
@@ -434,11 +439,12 @@ def filter(
434
439
  function: None | Callable,
435
440
  iterable: Iterable | AsyncIterable,
436
441
  /,
442
+ threaded: bool = False,
437
443
  ):
438
444
  """
439
445
  """
440
- if iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
441
- return async_filter(function, iterable)
446
+ if threaded or iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
447
+ return async_filter(function, iterable, threaded=threaded)
442
448
  return _filter(function, iterable)
443
449
 
444
450
 
@@ -447,11 +453,12 @@ def reduce(
447
453
  iterable: Iterable | AsyncIterable,
448
454
  initial: Any = undefined,
449
455
  /,
456
+ threaded: bool = False,
450
457
  ):
451
458
  """
452
459
  """
453
- if iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
454
- return async_reduce(function, iterable, initial)
460
+ if threaded or iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
461
+ return async_reduce(function, iterable, initial, threaded=threaded)
455
462
  from functools import reduce
456
463
  if initial is undefined:
457
464
  return reduce(function, iterable)
@@ -462,19 +469,80 @@ def zip(
462
469
  iterable: Iterable | AsyncIterable,
463
470
  /,
464
471
  *iterables: Iterable | AsyncIterable,
472
+ threaded: bool = False,
465
473
  ):
466
474
  """
467
475
  """
468
- if isinstance(iterable, AsyncIterable) or any(isinstance(i, AsyncIterable) for i in iterables):
469
- return async_zip(iterable, *iterables)
476
+ if threaded or isinstance(iterable, AsyncIterable) or any(isinstance(i, AsyncIterable) for i in iterables):
477
+ return async_zip(iterable, *iterables, threaded=threaded)
470
478
  return _zip(iterable, *iterables)
471
479
 
472
480
 
481
+ @overload
482
+ def chain[T](
483
+ iterable: Iterable[T],
484
+ /,
485
+ *iterables: Iterable[T],
486
+ threaded: bool = False,
487
+ ) -> Iterator[T]:
488
+ ...
489
+ @overload
490
+ def chain[T](
491
+ iterable: AsyncIterable[T],
492
+ /,
493
+ *iterables: Iterable[T] | AsyncIterable[T],
494
+ threaded: bool = False,
495
+ ) -> AsyncIterator[T]:
496
+ ...
497
+ def chain[T](
498
+ iterable: Iterable[T] | AsyncIterable[T],
499
+ /,
500
+ *iterables: Iterable[T] | AsyncIterable[T],
501
+ threaded: bool = False,
502
+ ) -> Iterator[T] | AsyncIterator[T]:
503
+ if threaded or not isinstance(iterable, Iterable):
504
+ return async_chain(iterable, *iterables, threaded=threaded)
505
+ return _chain(iterable, *iterables) # type: ignore
506
+
507
+
508
+ @overload
509
+ def chain_from_iterable[T](
510
+ iterables: Iterable[Iterable[T]],
511
+ threaded: Literal[False] = False,
512
+ *,
513
+ async_: Literal[False] = False,
514
+ ) -> Iterator[T]:
515
+ ...
516
+ @overload
517
+ def chain_from_iterable[T](
518
+ iterables: Iterable[Iterable[T] | AsyncIterable[T]] | AsyncIterable[Iterable[T] | AsyncIterable[T]],
519
+ threaded: bool = False,
520
+ *,
521
+ async_: Literal[True],
522
+ ) -> AsyncIterator[T]:
523
+ ...
524
+ def chain_from_iterable[T](
525
+ iterables: Iterable[Iterable[T]] | Iterable[Iterable[T] | AsyncIterable[T]] | AsyncIterable[Iterable[T] | AsyncIterable[T]],
526
+ threaded: bool = False,
527
+ *,
528
+ async_: Literal[False, True] = False,
529
+ ) -> Iterator[T] | AsyncIterator[T]:
530
+ if async_ or threaded or not isinstance(iterables, Iterable):
531
+ if isinstance(iterables, Iterable):
532
+ return async_chain.from_iterable(iterables, threaded=threaded)
533
+ else:
534
+ return async_chain.from_iterable(iterables, threaded=threaded)
535
+ return _chain.from_iterable(iterables) # type: ignore
536
+
537
+ setattr(chain, "from_iterable", chain_from_iterable)
538
+
539
+
473
540
  @overload
474
541
  def chunked[T](
475
542
  iterable: Iterable[T],
476
543
  n: int = 1,
477
544
  /,
545
+ threaded: bool = False,
478
546
  ) -> Iterator[Sequence[T]]:
479
547
  ...
480
548
  @overload
@@ -482,12 +550,14 @@ def chunked[T](
482
550
  iterable: AsyncIterable[T],
483
551
  n: int = 1,
484
552
  /,
553
+ threaded: bool = False,
485
554
  ) -> AsyncIterator[Sequence[T]]:
486
555
  ...
487
556
  def chunked[T](
488
557
  iterable: Iterable[T] | AsyncIterable[T],
489
558
  n: int = 1,
490
559
  /,
560
+ threaded: bool = False,
491
561
  ) -> Iterator[Sequence[T]] | AsyncIterator[Sequence[T]]:
492
562
  """
493
563
  """
@@ -497,10 +567,10 @@ def chunked[T](
497
567
  if n == 1:
498
568
  return ((e,) for e in iterable)
499
569
  return (iterable[i:j] for i, j in pairwise(range(0, len(iterable)+n, n)))
500
- elif isinstance(iterable, Iterable):
570
+ elif not threaded and isinstance(iterable, Iterable):
501
571
  return batched(iterable, n)
502
572
  else:
503
- return async_batched(iterable, n)
573
+ return async_batched(iterable, n, threaded=threaded)
504
574
 
505
575
 
506
576
  def foreach(
@@ -508,11 +578,12 @@ def foreach(
508
578
  iterable: Iterable | AsyncIterable,
509
579
  /,
510
580
  *iterables: Iterable | AsyncIterable,
581
+ threaded: bool = False,
511
582
  ):
512
583
  """
513
584
  """
514
- if not (isinstance(iterable, Iterable) and all(isinstance(it, Iterable) for it in iterables)):
515
- return async_foreach(value, iterable, *iterables)
585
+ if threaded or not (isinstance(iterable, Iterable) and all(isinstance(it, Iterable) for it in iterables)):
586
+ return async_foreach(value, iterable, *iterables, threaded=threaded)
516
587
  if iterables:
517
588
  for args in _zip(iterable, *iterables):
518
589
  value(*args)
@@ -543,11 +614,12 @@ def through(
543
614
  iterable: Iterable | AsyncIterable,
544
615
  /,
545
616
  take_while: None | Callable = None,
617
+ threaded: bool = False,
546
618
  ):
547
619
  """
548
620
  """
549
- if not isinstance(iterable, Iterable):
550
- return async_through(iterable, take_while)
621
+ if threaded or not isinstance(iterable, Iterable):
622
+ return async_through(iterable, take_while, threaded=threaded)
551
623
  if take_while is None:
552
624
  for _ in iterable:
553
625
  pass
@@ -584,6 +656,7 @@ def flatten(
584
656
  iterable: Iterable,
585
657
  /,
586
658
  exclude_types: type | tuple[type, ...] = (Buffer, str),
659
+ threaded: bool = False,
587
660
  ) -> Iterator:
588
661
  ...
589
662
  @overload
@@ -591,17 +664,19 @@ def flatten(
591
664
  iterable: AsyncIterable,
592
665
  /,
593
666
  exclude_types: type | tuple[type, ...] = (Buffer, str),
667
+ threaded: bool = False,
594
668
  ) -> AsyncIterator:
595
669
  ...
596
670
  def flatten(
597
671
  iterable: Iterable | AsyncIterable,
598
672
  /,
599
673
  exclude_types: type | tuple[type, ...] = (Buffer, str),
674
+ threaded: bool = False,
600
675
  ) -> Iterator | AsyncIterator:
601
676
  """
602
677
  """
603
- if not isinstance(iterable, Iterable):
604
- return async_flatten(iterable, exclude_types)
678
+ if threaded or not isinstance(iterable, Iterable):
679
+ return async_flatten(iterable, exclude_types, threaded=threaded)
605
680
  def gen(iterable):
606
681
  for e in iterable:
607
682
  if isinstance(e, (Iterable, AsyncIterable)) and not isinstance(e, exclude_types):
@@ -632,6 +707,7 @@ def collect[K, V](
632
707
  iterable: Iterable[tuple[K, V]] | Mapping[K, V],
633
708
  /,
634
709
  rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
710
+ threaded: bool = False,
635
711
  ) -> MutableMapping[K, V]:
636
712
  ...
637
713
  @overload
@@ -639,6 +715,7 @@ def collect[T](
639
715
  iterable: Iterable[T],
640
716
  /,
641
717
  rettype: Callable[[Iterable[T]], Collection[T]] = list,
718
+ threaded: bool = False,
642
719
  ) -> Collection[T]:
643
720
  ...
644
721
  @overload
@@ -646,6 +723,7 @@ def collect[K, V](
646
723
  iterable: AsyncIterable[tuple[K, V]],
647
724
  /,
648
725
  rettype: Callable[[Iterable[tuple[K, V]]], MutableMapping[K, V]],
726
+ threaded: bool = False,
649
727
  ) -> Coroutine[Any, Any, MutableMapping[K, V]]:
650
728
  ...
651
729
  @overload
@@ -653,17 +731,19 @@ def collect[T](
653
731
  iterable: AsyncIterable[T],
654
732
  /,
655
733
  rettype: Callable[[Iterable[T]], Collection[T]] = list,
734
+ threaded: bool = False,
656
735
  ) -> Coroutine[Any, Any, Collection[T]]:
657
736
  ...
658
737
  def collect(
659
738
  iterable: Iterable | AsyncIterable | Mapping,
660
739
  /,
661
740
  rettype: Callable[[Iterable], Collection] = list,
741
+ threaded: bool = False,
662
742
  ) -> Collection | Coroutine[Any, Any, Collection]:
663
743
  """
664
744
  """
665
- if not isinstance(iterable, Iterable):
666
- return async_collect(iterable, rettype)
745
+ if threaded or not isinstance(iterable, Iterable):
746
+ return async_collect(iterable, rettype, threaded=threaded)
667
747
  return rettype(iterable)
668
748
 
669
749
 
@@ -672,6 +752,7 @@ def group_collect[K, V, C: Container](
672
752
  iterable: Iterable[tuple[K, V]],
673
753
  mapping: None = None,
674
754
  factory: None | C | Callable[[], C] = None,
755
+ threaded: bool = False,
675
756
  ) -> dict[K, C]:
676
757
  ...
677
758
  @overload
@@ -679,6 +760,7 @@ def group_collect[K, V, C: Container, M: MutableMapping](
679
760
  iterable: Iterable[tuple[K, V]],
680
761
  mapping: M,
681
762
  factory: None | C | Callable[[], C] = None,
763
+ threaded: bool = False,
682
764
  ) -> M:
683
765
  ...
684
766
  @overload
@@ -686,6 +768,7 @@ def group_collect[K, V, C: Container](
686
768
  iterable: AsyncIterable[tuple[K, V]],
687
769
  mapping: None = None,
688
770
  factory: None | C | Callable[[], C] = None,
771
+ threaded: bool = False,
689
772
  ) -> Coroutine[Any, Any, dict[K, C]]:
690
773
  ...
691
774
  @overload
@@ -693,17 +776,19 @@ def group_collect[K, V, C: Container, M: MutableMapping](
693
776
  iterable: AsyncIterable[tuple[K, V]],
694
777
  mapping: M,
695
778
  factory: None | C | Callable[[], C] = None,
779
+ threaded: bool = False,
696
780
  ) -> Coroutine[Any, Any, M]:
697
781
  ...
698
782
  def group_collect[K, V, C: Container, M: MutableMapping](
699
783
  iterable: Iterable[tuple[K, V]] | AsyncIterable[tuple[K, V]],
700
784
  mapping: None | M = None,
701
785
  factory: None | C | Callable[[], C] = None,
786
+ threaded: bool = False,
702
787
  ) -> dict[K, C] | M | Coroutine[Any, Any, dict[K, C]] | Coroutine[Any, Any, M]:
703
788
  """
704
789
  """
705
- if not isinstance(iterable, Iterable):
706
- return async_group_collect(iterable, mapping, factory)
790
+ if threaded or not isinstance(iterable, Iterable):
791
+ return async_group_collect(iterable, mapping, factory, threaded=threaded)
707
792
  if factory is None:
708
793
  if isinstance(mapping, defaultdict):
709
794
  factory = mapping.default_factory
@@ -800,6 +885,7 @@ def iter_unique[T](
800
885
  iterable: Iterable[T],
801
886
  /,
802
887
  seen: None | MutableSet = None,
888
+ threaded: bool = False,
803
889
  ) -> Iterator[T]:
804
890
  ...
805
891
  @overload
@@ -807,17 +893,19 @@ def iter_unique[T](
807
893
  iterable: AsyncIterable[T],
808
894
  /,
809
895
  seen: None | MutableSet = None,
896
+ threaded: bool = False,
810
897
  ) -> AsyncIterator[T]:
811
898
  ...
812
899
  def iter_unique[T](
813
900
  iterable: Iterable[T] | AsyncIterable[T],
814
901
  /,
815
902
  seen: None | MutableSet = None,
903
+ threaded: bool = False,
816
904
  ) -> Iterator[T] | AsyncIterator[T]:
817
905
  """
818
906
  """
819
- if not isinstance(iterable, Iterable):
820
- return async_iter_unique(iterable, seen)
907
+ if threaded or not isinstance(iterable, Iterable):
908
+ return async_iter_unique(iterable, seen, threaded=threaded)
821
909
  if seen is None:
822
910
  seen = set()
823
911
  def gen(iterable):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-iterutils"
3
- version = "0.2.4.1"
3
+ version = "0.2.5.1"
4
4
  description = "Python another itertools."
5
5
  authors = ["ChenyangGao <wosiwujm@gmail.com>"]
6
6
  license = "MIT"
@@ -27,7 +27,7 @@ include = [
27
27
 
28
28
  [tool.poetry.dependencies]
29
29
  python = "^3.12"
30
- python-asynctools = ">=0.1.2"
30
+ python-asynctools = ">=0.1.3.4"
31
31
  python-texttools = ">=0.0.3"
32
32
  python-undefined = ">=0.0.3"
33
33