python-iterutils 0.1.8__tar.gz → 0.1.10__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.1.8
3
+ Version: 0.1.10
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.0.10.1)
23
+ Requires-Dist: python-asynctools (>=0.1.2)
24
24
  Requires-Dist: python-decotools (>=0.0.2)
25
25
  Requires-Dist: python-texttools (>=0.0.3)
26
26
  Requires-Dist: python-undefined (>=0.0.3)
@@ -2,13 +2,14 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 1, 8)
5
+ __version__ = (0, 1, 10)
6
6
  __all__ = [
7
7
  "Return", "Yield", "YieldFrom", "iterable", "async_iterable", "foreach", "async_foreach",
8
8
  "through", "async_through", "flatten", "async_flatten", "collect", "async_collect",
9
9
  "group_collect", "async_group_collect", "map", "filter", "reduce", "zip", "chunked",
10
10
  "iter_unique", "async_iter_unique", "wrap_iter", "wrap_aiter", "acc_step", "cut_iter",
11
- "run_gen_step", "run_gen_step_iter", "as_gen_step", "bfs_gen", "with_iter_next", "backgroud_loop",
11
+ "iter_gen_step", "iter_gen_step_async", "run_gen_step", "run_gen_step_iter",
12
+ "as_gen_step", "bfs_gen", "with_iter_next", "backgroud_loop",
12
13
  ]
13
14
 
14
15
  from abc import ABC, abstractmethod
@@ -52,6 +53,12 @@ class YieldBase(ABC):
52
53
  ...
53
54
 
54
55
 
56
+ class Reraised(BaseException):
57
+
58
+ def __init__(self, exc: BaseException, /):
59
+ self.exception = exc
60
+
61
+
55
62
  class Return(YieldBase):
56
63
  yield_type = 0
57
64
 
@@ -636,110 +643,163 @@ def _get_async(back: int = 2) -> bool:
636
643
  return False
637
644
 
638
645
 
639
- def run_gen_step[T](
640
- gen_step: Generator[Any, Any, T] | Callable[[], Generator[Any, Any, T]],
641
- *,
642
- async_: None | bool = None,
646
+ @overload
647
+ def call_as_async[**Args, T: Coroutine](
648
+ func: Callable[Args, T], /,
643
649
  threaded: bool = False,
644
- as_iter: bool = False,
645
- ) -> T:
646
- if async_ is None:
647
- async_ = _get_async()
650
+ ) -> Callable[Args, T]:
651
+ ...
652
+ @overload
653
+ def call_as_async[**Args, T](
654
+ func: Callable[Args, T], /,
655
+ threaded: bool = False,
656
+ ) -> Callable[Args, Coroutine[Any, Any, T]]:
657
+ ...
658
+ def call_as_async[**Args, T](
659
+ func: Callable[Args, T],
660
+ /,
661
+ threaded: bool = False,
662
+ ) -> Callable[Args, T] | Callable[Args, Coroutine[Any, Any, T]]:
663
+ if iscoroutinefunction(func):
664
+ return func
665
+ def wraps(*args, **kwds):
666
+ try:
667
+ return func(*args, **kwds)
668
+ except (StopIteration, StopAsyncIteration) as e:
669
+ raise Reraised(e) from e
670
+ if threaded:
671
+ async def wrapper(*args, **kwds):
672
+ return await to_thread(wraps, *args, **kwds)
673
+ else:
674
+ async def wrapper(*args, **kwds):
675
+ return wraps(*args, **kwds)
676
+ return wrapper
677
+
678
+
679
+ def iter_gen_step(
680
+ gen_step: Generator | Callable[[], Generator],
681
+ ):
648
682
  if callable(gen_step):
649
683
  gen = gen_step()
650
- close = gen.close
651
684
  else:
652
685
  gen = gen_step
653
- close = None
654
- send = gen.send
686
+ send = gen.send
655
687
  throw = gen.throw
656
- if async_:
657
- async def process():
688
+ close = gen.close
689
+ try:
690
+ value = send(None)
691
+ while True:
692
+ if isinstance(value, YieldBase):
693
+ raise StopIteration(value)
658
694
  try:
659
- if threaded:
660
- value = await to_thread(send, None)
661
- else:
662
- value = send(None)
663
- while True:
664
- if isinstance(value, YieldBase):
665
- raise StopIteration(value)
666
- try:
667
- if callable(value):
668
- value = value()
669
- if isawaitable(value):
670
- value = await value
671
- except BaseException as e:
672
- if threaded:
673
- value = await to_thread(throw, e)
674
- else:
675
- value = throw(e)
676
- else:
677
- if threaded:
678
- value = await to_thread(send, value)
679
- else:
680
- value = send(value)
681
- except StopIteration as e:
682
- value = e.value
683
- identity = False
684
- try_call_me = True
685
- if isinstance(value, YieldBase):
686
- identity = value.identity
687
- try_call_me = value.try_call_me
688
- value = value.value
689
- if callable(value) and try_call_me:
695
+ if callable(value):
690
696
  value = value()
691
- if not identity and isawaitable(value):
692
- value = await value
693
- return value
694
- finally:
695
- if close is not None:
696
- if threaded:
697
- await to_thread(close)
698
- else:
699
- close()
700
- result = process()
701
- if as_iter:
702
- async def wrap(result):
703
- iterable = await result
704
- try:
705
- iterable = aiter(iterable)
706
- except TypeError:
707
- for val in iter(iterable):
708
- if isawaitable(val):
709
- val = await val
710
- yield val
711
- else:
712
- async for val in iterable:
713
- yield val
714
- result = wrap(result)
715
- return result
716
- else:
717
- try:
718
- value = send(None)
719
- while True:
720
- if isinstance(value, YieldBase):
721
- raise StopIteration(value)
697
+ except BaseException as e:
698
+ value = throw(e)
699
+ else:
700
+ value = send(value)
701
+ yield value
702
+ except StopIteration as e:
703
+ value = e.value
704
+ try_call_me = True
705
+ if isinstance(value, YieldBase):
706
+ try_call_me = value.try_call_me
707
+ value = value.value
708
+ if callable(value) and try_call_me:
709
+ try:
710
+ value = value()
711
+ except BaseException as e:
722
712
  try:
723
- if callable(value):
724
- value = value()
725
- except BaseException as e:
726
713
  value = throw(e)
727
- else:
728
- value = send(value)
729
- except StopIteration as e:
714
+ except BaseException as e:
715
+ raise Reraised(e) from e
716
+ yield value
717
+ except BaseException as e:
718
+ raise Reraised(e) from e
719
+ finally:
720
+ close()
721
+
722
+
723
+ async def iter_gen_step_async(
724
+ gen_step: Generator | Callable[[], Generator],
725
+ threaded: bool = False,
726
+ ):
727
+ if callable(gen_step):
728
+ gen = gen_step()
729
+ else:
730
+ gen = gen_step
731
+ send: Callable = call_as_async(gen.send, threaded=threaded)
732
+ throw: Callable = call_as_async(gen.throw, threaded=threaded)
733
+ close: Callable = call_as_async(gen.close, threaded=threaded)
734
+ try:
735
+ value = await send(None)
736
+ while True:
737
+ if isinstance(value, YieldBase):
738
+ raise StopIteration(value)
739
+ try:
740
+ if callable(value):
741
+ value = await call_as_async(value, threaded=threaded)()
742
+ if isawaitable(value):
743
+ value = await value
744
+ except BaseException as e:
745
+ if isinstance(e, Reraised):
746
+ e = e.exception
747
+ value = await throw(e)
748
+ else:
749
+ value = await send(value)
750
+ yield value
751
+ except BaseException as e:
752
+ if isinstance(e, Reraised):
753
+ e = e.exception
754
+ if isinstance(e, StopIteration):
730
755
  value = e.value
756
+ identity = False
731
757
  try_call_me = True
732
758
  if isinstance(value, YieldBase):
759
+ identity = value.identity
733
760
  try_call_me = value.try_call_me
734
761
  value = value.value
735
- if callable(value) and try_call_me:
736
- value = value()
737
- if as_iter:
738
- value = iter(value)
762
+ try:
763
+ if callable(value) and try_call_me:
764
+ value = await call_as_async(value, threaded=threaded)()
765
+ if not identity and isawaitable(value):
766
+ value = await value
767
+ except BaseException as e:
768
+ try:
769
+ value = await throw(e)
770
+ except BaseException as e:
771
+ raise Reraised(e) from e
772
+ yield value
773
+ else:
774
+ raise
775
+ finally:
776
+ await close()
777
+
778
+
779
+ def run_gen_step[T](
780
+ gen_step: Generator | Callable[[], Generator],
781
+ *,
782
+ async_: None | bool = None,
783
+ threaded: bool = False,
784
+ ):
785
+ if async_ is None:
786
+ async_ = _get_async()
787
+ if async_:
788
+ async def process():
789
+ try:
790
+ async for value in iter_gen_step_async(gen_step, threaded=threaded):
791
+ pass
792
+ return value
793
+ except Reraised as e:
794
+ raise e.exception
795
+ return process()
796
+ else:
797
+ try:
798
+ for value in iter_gen_step(gen_step):
799
+ pass
739
800
  return value
740
- finally:
741
- if close is not None:
742
- close()
801
+ except Reraised as e:
802
+ raise e.exception
743
803
 
744
804
 
745
805
  @overload
@@ -776,33 +836,32 @@ def run_gen_step_iter(
776
836
  async_ = _get_async()
777
837
  if callable(gen_step):
778
838
  gen = gen_step()
779
- close = gen.close
780
839
  else:
781
840
  gen = gen_step
782
- close = None
783
- send = gen.send
784
- throw = gen.throw
841
+ send: Callable = gen.send
842
+ throw: Callable = gen.throw
843
+ close: Callable = gen.close
785
844
  if async_:
845
+ send = call_as_async(send, threaded=threaded)
846
+ throw = call_as_async(throw, threaded=threaded)
847
+ close = call_as_async(close, threaded=threaded)
786
848
  async def process():
787
849
  async def extract(value):
788
850
  identity = False
789
851
  try_call_me = True
790
852
  yield_type = -1
791
853
  if isinstance(value, YieldBase):
792
- identity = value.identity
854
+ identity = value.identity
793
855
  try_call_me = value.try_call_me
794
- yield_type = value.yield_type
795
- value = value.value
856
+ yield_type = value.yield_type
857
+ value = value.value
796
858
  if try_call_me and callable(value):
797
- value = value()
859
+ value = await call_as_async(value, threaded=threaded)()
798
860
  if not identity and isawaitable(value):
799
861
  value = await value
800
862
  return yield_type, value
801
863
  try:
802
- if threaded:
803
- value = await to_thread(send, None)
804
- else:
805
- value = send(None)
864
+ value = await send(None)
806
865
  while True:
807
866
  try:
808
867
  yield_type, value = await extract(value)
@@ -813,29 +872,31 @@ def run_gen_step_iter(
813
872
  async for val in ensure_aiter(value, threaded=threaded):
814
873
  yield val
815
874
  except BaseException as e:
816
- if threaded:
817
- value = await to_thread(throw, e)
818
- else:
819
- value = throw(e)
875
+ if isinstance(e, Reraised):
876
+ e = e.exception
877
+ value = await throw(e)
820
878
  else:
821
- if threaded:
822
- value = await to_thread(send, value)
823
- else:
824
- value = send(value)
825
- except StopIteration as e:
826
- yield_type, value = await extract(e.value)
827
- match yield_type:
828
- case 1:
829
- yield value
830
- case 2:
831
- async for val in ensure_aiter(value, threaded=threaded):
832
- yield val
879
+ value = await send(value)
880
+ except BaseException as e:
881
+ if isinstance(e, Reraised):
882
+ e = e.exception
883
+ if isinstance(e, StopIteration):
884
+ try:
885
+ yield_type, value = await extract(e.value)
886
+ match yield_type:
887
+ case 1:
888
+ yield value
889
+ case 2:
890
+ async for val in ensure_aiter(value, threaded=threaded):
891
+ yield val
892
+ except BaseException as e:
893
+ if isinstance(e, Reraised):
894
+ e = e.exception
895
+ await throw(e)
896
+ else:
897
+ raise
833
898
  finally:
834
- if close is not None:
835
- if threaded:
836
- await to_thread(close)
837
- else:
838
- close()
899
+ await close()
839
900
  else:
840
901
  def process():
841
902
  def extract(value, /):
@@ -865,17 +926,19 @@ def run_gen_step_iter(
865
926
  else:
866
927
  value = send(value)
867
928
  except StopIteration as e:
868
- yield_type, value = extract(e.value)
869
- match yield_type:
870
- case 1:
871
- yield value
872
- case 2:
873
- yield from value
874
- case _:
875
- return value
929
+ try:
930
+ yield_type, value = extract(e.value)
931
+ match yield_type:
932
+ case 1:
933
+ yield value
934
+ case 2:
935
+ yield from value
936
+ case _:
937
+ return value
938
+ except BaseException as e:
939
+ throw(e)
876
940
  finally:
877
- if close is not None:
878
- close()
941
+ close()
879
942
  return process()
880
943
 
881
944
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-iterutils"
3
- version = "0.1.8"
3
+ version = "0.1.10"
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.0.10.1"
30
+ python-asynctools = ">=0.1.2"
31
31
  python-decotools = ">=0.0.2"
32
32
  python-texttools = ">=0.0.3"
33
33
  python-undefined = ">=0.0.3"