python-iterutils 0.1.11__py3-none-any.whl → 0.2__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,7 +2,7 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 1, 11)
5
+ __version__ = (0, 2)
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",
@@ -38,18 +38,26 @@ from asynctools import (
38
38
  )
39
39
  from decotools import optional
40
40
  from texttools import format_time
41
- from undefined import undefined, Undefined
41
+ from undefined import undefined
42
42
 
43
43
 
44
44
  class SupportsBool(Protocol):
45
45
  def __bool__(self, /) -> bool: ...
46
46
 
47
47
 
48
+ class Reraised(BaseException):
49
+
50
+ def __init__(self, exc: BaseException, /):
51
+ if isinstance(exc, Reraised):
52
+ exc = exc.exception
53
+ self.exception: BaseException = exc
54
+
55
+
48
56
  @dataclass(slots=True, frozen=True)
49
57
  class YieldBase(ABC):
50
58
  value: Any
51
- identity: bool = False
52
- try_call_me: bool = True
59
+ may_await: None | bool = True
60
+ may_call: None | bool = True
53
61
 
54
62
  @property
55
63
  @abstractmethod
@@ -57,12 +65,6 @@ class YieldBase(ABC):
57
65
  ...
58
66
 
59
67
 
60
- class Reraised(BaseException):
61
-
62
- def __init__(self, exc: BaseException, /):
63
- self.exception = exc
64
-
65
-
66
68
  class Return(YieldBase):
67
69
  yield_type = 0
68
70
 
@@ -401,7 +403,7 @@ def filter(
401
403
  def reduce(
402
404
  function: Callable,
403
405
  iterable: Iterable | AsyncIterable,
404
- initial = undefined,
406
+ initial: Any = undefined,
405
407
  /,
406
408
  ):
407
409
  if iscoroutinefunction(function) or isinstance(iterable, AsyncIterable):
@@ -650,18 +652,21 @@ def _get_async(back: int = 2) -> bool:
650
652
  @overload
651
653
  def call_as_async[**Args, T: Coroutine](
652
654
  func: Callable[Args, T], /,
655
+ may_await: None | bool = False,
653
656
  threaded: bool = False,
654
657
  ) -> Callable[Args, T]:
655
658
  ...
656
659
  @overload
657
660
  def call_as_async[**Args, T](
658
661
  func: Callable[Args, T], /,
662
+ may_await: None | bool = False,
659
663
  threaded: bool = False,
660
664
  ) -> Callable[Args, Coroutine[Any, Any, T]]:
661
665
  ...
662
666
  def call_as_async[**Args, T](
663
667
  func: Callable[Args, T],
664
668
  /,
669
+ may_await: None | bool = False,
665
670
  threaded: bool = False,
666
671
  ) -> Callable[Args, T] | Callable[Args, Coroutine[Any, Any, T]]:
667
672
  if iscoroutinefunction(func):
@@ -671,119 +676,145 @@ def call_as_async[**Args, T](
671
676
  return func(*args, **kwds)
672
677
  except (StopIteration, StopAsyncIteration) as e:
673
678
  raise Reraised(e) from e
674
- if threaded:
675
- async def wrapper(*args, **kwds):
676
- return await to_thread(wraps, *args, **kwds)
677
- else:
678
- async def wrapper(*args, **kwds):
679
- return wraps(*args, **kwds)
679
+ async def wrapper(*args, **kwds):
680
+ if threaded:
681
+ value = await to_thread(wraps, *args, **kwds)
682
+ else:
683
+ value = wraps(*args, **kwds)
684
+ if may_await is None or may_await and isawaitable(value):
685
+ value = await value
686
+ return value
680
687
  return wrapper
681
688
 
682
689
 
683
690
  def iter_gen_step(
684
691
  gen_step: Generator | Callable[[], Generator],
692
+ simple: bool = False,
685
693
  ):
686
- if callable(gen_step):
687
- gen = gen_step()
688
- else:
689
- gen = gen_step
694
+ gen = gen_step() if callable(gen_step) else gen_step
690
695
  send = gen.send
691
696
  throw = gen.throw
692
697
  close = gen.close
693
- try:
694
- value = send(None)
695
- while True:
696
- if isinstance(value, YieldBase):
697
- raise StopIteration(value)
698
- try:
699
- if callable(value):
700
- value = value()
701
- except BaseException as e:
702
- value = throw(e)
703
- else:
704
- value = send(value)
705
- yield value
706
- except StopIteration as e:
707
- value = e.value
708
- try_call_me = True
709
- if isinstance(value, YieldBase):
710
- try_call_me = value.try_call_me
711
- value = value.value
712
- if callable(value) and try_call_me:
713
- try:
714
- value = value()
715
- except BaseException as e:
698
+ value: Any = None
699
+ if simple:
700
+ try:
701
+ while True:
702
+ yield (value := send(value))
703
+ except StopIteration as e:
704
+ yield e.value
705
+ finally:
706
+ close()
707
+ else:
708
+ try:
709
+ while True:
710
+ if isinstance(value, YieldBase):
711
+ raise StopIteration(value)
716
712
  try:
713
+ if callable(value):
714
+ value = value()
715
+ except BaseException as e:
717
716
  value = throw(e)
717
+ else:
718
+ value = send(value)
719
+ yield value
720
+ except StopIteration as e:
721
+ may_call: None | bool = True
722
+ value = e.value
723
+ if isinstance(value, YieldBase):
724
+ may_call = value.may_call
725
+ value = value.value
726
+ if may_call is None or may_call and callable(value):
727
+ try:
728
+ value = value()
718
729
  except BaseException as e:
719
- raise Reraised(e) from e
720
- yield value
721
- except BaseException as e:
722
- raise Reraised(e) from e
723
- finally:
724
- close()
730
+ try:
731
+ value = throw(e)
732
+ except BaseException as e:
733
+ raise Reraised(e) from e
734
+ yield value
735
+ finally:
736
+ close()
725
737
 
726
738
 
727
739
  async def iter_gen_step_async(
728
740
  gen_step: Generator | Callable[[], Generator],
729
741
  threaded: bool = False,
742
+ simple: bool = False,
730
743
  ):
731
- if callable(gen_step):
732
- gen = gen_step()
733
- else:
734
- gen = gen_step
735
- send: Callable = call_as_async(gen.send, threaded=threaded)
736
- throw: Callable = call_as_async(gen.throw, threaded=threaded)
744
+ gen = gen_step() if callable(gen_step) else gen_step
745
+ send: Callable = gen.send
746
+ throw: Callable = gen.throw
737
747
  close: Callable = call_as_async(gen.close, threaded=threaded)
738
- try:
739
- value = await send(None)
740
- while True:
741
- if isinstance(value, YieldBase):
742
- raise StopIteration(value)
743
- try:
744
- if callable(value):
745
- value = await call_as_async(value, threaded=threaded)()
746
- if isawaitable(value):
747
- value = await value
748
- except BaseException as e:
749
- if isinstance(e, Reraised):
750
- e = e.exception
751
- value = await throw(e)
748
+ value: Any = None
749
+ if simple:
750
+ send = call_as_async(send, may_await=None, threaded=threaded)
751
+ throw = call_as_async(throw, may_await=None, threaded=threaded)
752
+ try:
753
+ while True:
754
+ yield (value := await send(value))
755
+ except BaseException as e:
756
+ if isinstance(e, Reraised):
757
+ e = e.exception
758
+ if isinstance(e, StopIteration):
759
+ yield e.value
752
760
  else:
753
- value = await send(value)
754
- yield value
755
- except BaseException as e:
756
- if isinstance(e, Reraised):
757
- e = e.exception
758
- if isinstance(e, StopIteration):
759
- value = e.value
760
- identity = False
761
- try_call_me = True
762
- if isinstance(value, YieldBase):
763
- identity = value.identity
764
- try_call_me = value.try_call_me
765
- value = value.value
766
- try:
767
- if callable(value) and try_call_me:
768
- value = await call_as_async(value, threaded=threaded)()
769
- if not identity and isawaitable(value):
770
- value = await value
771
- except BaseException as e:
761
+ raise
762
+ finally:
763
+ await close()
764
+ else:
765
+ send = call_as_async(send, threaded=threaded)
766
+ throw = call_as_async(throw, threaded=threaded)
767
+ try:
768
+ while True:
769
+ if isinstance(value, YieldBase):
770
+ raise StopIteration(value)
772
771
  try:
772
+ if callable(value):
773
+ value = await call_as_async(
774
+ value, may_await=True, threaded=threaded)()
775
+ elif isawaitable(value):
776
+ value = await value
777
+ except BaseException as e:
778
+ if isinstance(e, Reraised):
779
+ e = e.exception
773
780
  value = await throw(e)
781
+ else:
782
+ value = await send(value)
783
+ yield value
784
+ except BaseException as e:
785
+ if isinstance(e, Reraised):
786
+ e = e.exception
787
+ if isinstance(e, StopIteration):
788
+ may_await: None | bool = True
789
+ may_call: None | bool = True
790
+ value = e.value
791
+ if isinstance(value, YieldBase):
792
+ may_await = value.may_await
793
+ may_call = value.may_call
794
+ value = value.value
795
+ try:
796
+ if may_call is None or may_call and callable(value):
797
+ value = await call_as_async(
798
+ value, may_await=may_await, threaded=threaded)()
799
+ elif may_await is None or may_await and isawaitable(value):
800
+ value = await value
774
801
  except BaseException as e:
775
- raise Reraised(e) from e
776
- yield value
777
- else:
778
- raise
779
- finally:
780
- await close()
802
+ try:
803
+ value = await throw(e)
804
+ except BaseException as e:
805
+ raise Reraised(e) from e
806
+ yield value
807
+ else:
808
+ raise
809
+ finally:
810
+ await close()
781
811
 
782
812
 
783
- def run_gen_step[T](
813
+ def run_gen_step(
784
814
  gen_step: Generator | Callable[[], Generator],
815
+ simple: bool = False,
785
816
  threaded: bool = False,
786
- running_flag: None | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]] | SupportsBool = None,
817
+ running_flag: None | SupportsBool | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]] = None,
787
818
  *,
788
819
  async_: None | bool = None,
789
820
  ):
@@ -791,25 +822,24 @@ def run_gen_step[T](
791
822
  async_ = _get_async()
792
823
  if async_:
793
824
  async def process():
794
- gen = iter_gen_step_async(gen_step, threaded=threaded)
825
+ gen = iter_gen_step_async(gen_step, simple=simple, threaded=threaded)
795
826
  try:
796
827
  if running_flag is None:
797
828
  async for value in gen:
798
829
  pass
799
830
  elif callable(running_flag):
800
- pred = running_flag()
801
- if not ((await pred) if isawaitable(pred) else pred):
831
+ pred = call_as_async(running_flag, threaded=threaded)
832
+ if not await pred():
802
833
  raise RuntimeError("stop before starting", gen) from StopIteration()
803
834
  async for value in gen:
804
- pred = running_flag()
805
- if not ((await pred) if isawaitable(pred) else pred):
835
+ if not await pred():
806
836
  raise RuntimeError("stop midway", gen) from StopIteration(value)
807
- else:
837
+ else:
838
+ if not running_flag:
839
+ raise RuntimeError("stop before starting", gen) from StopIteration()
840
+ async for value in gen:
808
841
  if not running_flag:
809
- raise RuntimeError("stop before starting", gen) from StopIteration()
810
- async for value in gen:
811
- if not running_flag:
812
- raise RuntimeError("stop midway", gen) from StopIteration(value)
842
+ raise RuntimeError("stop midway", gen) from StopIteration(value)
813
843
  return value
814
844
  except Reraised as e:
815
845
  raise e.exception
@@ -819,7 +849,7 @@ def run_gen_step[T](
819
849
  raise
820
850
  return process()
821
851
  else:
822
- gen = iter_gen_step(gen_step)
852
+ gen = iter_gen_step(gen_step, simple=simple)
823
853
  try:
824
854
  if running_flag is None:
825
855
  for value in gen:
@@ -844,6 +874,7 @@ def run_gen_step[T](
844
874
  @overload
845
875
  def run_gen_step_iter(
846
876
  gen_step: Generator | Callable[[], Generator],
877
+ simple: bool = False,
847
878
  threaded: bool = False,
848
879
  *,
849
880
  async_: None = None,
@@ -852,6 +883,7 @@ def run_gen_step_iter(
852
883
  @overload
853
884
  def run_gen_step_iter(
854
885
  gen_step: Generator | Callable[[], Generator],
886
+ simple: bool = False,
855
887
  threaded: bool = False,
856
888
  *,
857
889
  async_: Literal[False],
@@ -860,6 +892,7 @@ def run_gen_step_iter(
860
892
  @overload
861
893
  def run_gen_step_iter(
862
894
  gen_step: Generator | Callable[[], Generator],
895
+ simple: bool = False,
863
896
  threaded: bool = False,
864
897
  *,
865
898
  async_: Literal[True],
@@ -867,16 +900,14 @@ def run_gen_step_iter(
867
900
  ...
868
901
  def run_gen_step_iter(
869
902
  gen_step: Generator | Callable[[], Generator],
903
+ simple: bool = False,
870
904
  threaded: bool = False,
871
905
  *,
872
906
  async_: None | bool = None,
873
907
  ) -> Iterator | AsyncIterator:
874
908
  if async_ is None:
875
909
  async_ = _get_async()
876
- if callable(gen_step):
877
- gen = gen_step()
878
- else:
879
- gen = gen_step
910
+ gen = gen_step() if callable(gen_step) else gen_step
880
911
  send: Callable = gen.send
881
912
  throw: Callable = gen.throw
882
913
  close: Callable = gen.close
@@ -884,27 +915,30 @@ def run_gen_step_iter(
884
915
  send = call_as_async(send, threaded=threaded)
885
916
  throw = call_as_async(throw, threaded=threaded)
886
917
  close = call_as_async(close, threaded=threaded)
887
- async def process():
888
- async def extract(value):
889
- identity = False
890
- try_call_me = True
891
- yield_type = -1
892
- if isinstance(value, YieldBase):
893
- identity = value.identity
894
- try_call_me = value.try_call_me
895
- yield_type = value.yield_type
896
- value = value.value
897
- if try_call_me and callable(value):
898
- value = await call_as_async(value, threaded=threaded)()
899
- if not identity and isawaitable(value):
900
- value = await value
901
- return yield_type, value
918
+ async def aextract(value, /):
919
+ may_await: None | bool = None if simple else False
920
+ may_call: None | bool = not simple
921
+ yield_type = -1
922
+ if isinstance(value, YieldBase):
923
+ yield_type = value.yield_type
924
+ may_await = value.may_await
925
+ may_call = value.may_call
926
+ value = value.value
927
+ if may_call is None or may_call and callable(value):
928
+ value = await call_as_async(
929
+ value, may_await=may_await, threaded=threaded)()
930
+ elif may_await is None or may_await and isawaitable(value):
931
+ value = await value
932
+ return yield_type, value
933
+ async def aprocess():
902
934
  try:
903
935
  value = await send(None)
904
936
  while True:
905
937
  try:
906
- yield_type, value = await extract(value)
938
+ yield_type, value = await aextract(value)
907
939
  match yield_type:
940
+ case 0:
941
+ return
908
942
  case 1:
909
943
  yield value
910
944
  case 2:
@@ -921,7 +955,7 @@ def run_gen_step_iter(
921
955
  e = e.exception
922
956
  if isinstance(e, StopIteration):
923
957
  try:
924
- yield_type, value = await extract(e.value)
958
+ yield_type, value = await aextract(e.value)
925
959
  match yield_type:
926
960
  case 1:
927
961
  yield value
@@ -936,18 +970,19 @@ def run_gen_step_iter(
936
970
  raise
937
971
  finally:
938
972
  await close()
973
+ return aprocess()
939
974
  else:
975
+ def extract(value, /):
976
+ may_call: None | bool = not simple
977
+ yield_type = -1
978
+ if isinstance(value, YieldBase):
979
+ yield_type = value.yield_type
980
+ may_call = value.may_call
981
+ value = value.value
982
+ if may_call is None or may_call and callable(value):
983
+ value = value()
984
+ return yield_type, value
940
985
  def process():
941
- def extract(value, /):
942
- try_call_me = True
943
- yield_type = -1
944
- if isinstance(value, YieldBase):
945
- try_call_me = value.try_call_me
946
- yield_type = value.yield_type
947
- value = value.value
948
- if try_call_me and callable(value):
949
- value = value()
950
- return yield_type, value
951
986
  try:
952
987
  value = send(None)
953
988
  while True:
@@ -978,7 +1013,7 @@ def run_gen_step_iter(
978
1013
  throw(e)
979
1014
  finally:
980
1015
  close()
981
- return process()
1016
+ return process()
982
1017
 
983
1018
 
984
1019
  @optional
@@ -986,23 +1021,26 @@ def as_gen_step(
986
1021
  func: Callable,
987
1022
  /,
988
1023
  iter: bool = False,
1024
+ simple: bool = False,
989
1025
  threaded: bool = False,
990
- running_flag: None | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]] | SupportsBool = None,
1026
+ running_flag: None | SupportsBool | Callable[[], SupportsBool] | Callable[[], Awaitable[SupportsBool]] = None,
991
1027
  *,
992
1028
  async_: None | bool = None,
993
1029
  ) -> Callable:
994
- if async_ is None:
995
- async_ = _get_async()
1030
+ """装饰器,构建一个 gen_step 函数
1031
+ """
996
1032
  def wrapper(*args, **kwds):
997
1033
  if iter:
998
1034
  return run_gen_step_iter(
999
1035
  func(*args, **kwds),
1036
+ simple=simple,
1000
1037
  threaded=threaded,
1001
1038
  async_=async_, # type: ignore
1002
1039
  )
1003
1040
  else:
1004
1041
  return run_gen_step(
1005
1042
  func(*args, **kwds),
1043
+ simple=simple,
1006
1044
  threaded=threaded,
1007
1045
  running_flag=running_flag,
1008
1046
  async_=async_,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-iterutils
3
- Version: 0.1.11
3
+ Version: 0.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
@@ -0,0 +1,7 @@
1
+ LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
+ iterutils/__init__.py,sha256=LEkMyVkA2qLrVtJDuTXgUz0cUSexnjyEcJ0skHehf4M,38403
3
+ iterutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ python_iterutils-0.2.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
5
+ python_iterutils-0.2.dist-info/METADATA,sha256=EYmtSSWyFbN7QMzuv79s2UKsPoJ3fNvr_SmLsL8SnlE,1465
6
+ python_iterutils-0.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
7
+ python_iterutils-0.2.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
- iterutils/__init__.py,sha256=4N0xHGZpr82-wdumeqYtIZWLhFsVpOPtzcQ-AS3wPlA,36665
3
- iterutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- python_iterutils-0.1.11.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
5
- python_iterutils-0.1.11.dist-info/METADATA,sha256=wDmScgucOm3H7FiWNqh0QCUzvd10liYfMIEk7ouDFQI,1468
6
- python_iterutils-0.1.11.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
7
- python_iterutils-0.1.11.dist-info/RECORD,,