dycw-utilities 0.125.12__py3-none-any.whl → 0.125.14__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.
- {dycw_utilities-0.125.12.dist-info → dycw_utilities-0.125.14.dist-info}/METADATA +1 -1
- {dycw_utilities-0.125.12.dist-info → dycw_utilities-0.125.14.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/asyncio.py +120 -45
- {dycw_utilities-0.125.12.dist-info → dycw_utilities-0.125.14.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.125.12.dist-info → dycw_utilities-0.125.14.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=FUi2dI2qq8_0UHJ0RQEHLRzzmOO3YY-SHiWkJPnb-P4,61
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
|
-
utilities/asyncio.py,sha256=
|
3
|
+
utilities/asyncio.py,sha256=UUcMb_QT4g4-EW0qIoiSENu8x6Fcjn5_X-vvbMrLBfE,50658
|
4
4
|
utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
|
5
5
|
utilities/atools.py,sha256=IYMuFSFGSKyuQmqD6v5IUtDlz8PPw0Sr87Cub_gRU3M,1168
|
6
6
|
utilities/cachetools.py,sha256=C1zqOg7BYz0IfQFK8e3qaDDgEZxDpo47F15RTfJM37Q,2910
|
@@ -88,7 +88,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
88
88
|
utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
|
89
89
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
90
90
|
utilities/zoneinfo.py,sha256=-5j7IQ9nb7gR43rdgA7ms05im-XuqhAk9EJnQBXxCoQ,1874
|
91
|
-
dycw_utilities-0.125.
|
92
|
-
dycw_utilities-0.125.
|
93
|
-
dycw_utilities-0.125.
|
94
|
-
dycw_utilities-0.125.
|
91
|
+
dycw_utilities-0.125.14.dist-info/METADATA,sha256=ptsWeHCzCc0Tmvlmzovy3NZ4PLYMSEeT8VdauAv3b0k,12852
|
92
|
+
dycw_utilities-0.125.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
93
|
+
dycw_utilities-0.125.14.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
94
|
+
dycw_utilities-0.125.14.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/asyncio.py
CHANGED
@@ -5,6 +5,7 @@ from abc import ABC, abstractmethod
|
|
5
5
|
from asyncio import (
|
6
6
|
CancelledError,
|
7
7
|
Event,
|
8
|
+
Lock,
|
8
9
|
PriorityQueue,
|
9
10
|
Queue,
|
10
11
|
QueueEmpty,
|
@@ -719,6 +720,7 @@ class Looper(Generic[_T]):
|
|
719
720
|
_is_stopped: Event = field(default_factory=Event, init=False, repr=False)
|
720
721
|
_is_tearing_down: Event = field(default_factory=Event, init=False, repr=False)
|
721
722
|
# internal objects
|
723
|
+
_lock: Lock = field(default_factory=Lock, init=False, repr=False, hash=False)
|
722
724
|
_logger: Logger = field(init=False, repr=False, hash=False)
|
723
725
|
_queue: EnhancedQueue[_T] = field(
|
724
726
|
default_factory=EnhancedQueue, init=False, repr=False, hash=False
|
@@ -742,8 +744,9 @@ class Looper(Generic[_T]):
|
|
742
744
|
case False:
|
743
745
|
_ = self._debug and self._logger.debug("%s: entering context...", self)
|
744
746
|
self._is_entered.set()
|
745
|
-
self.
|
746
|
-
|
747
|
+
async with self._lock:
|
748
|
+
self._entries += 1
|
749
|
+
self._task = create_task(self.run_looper())
|
747
750
|
for looper in self._yield_sub_loopers():
|
748
751
|
_ = self._debug and self._logger.debug(
|
749
752
|
"%s: adding sub-looper %s", self, looper
|
@@ -752,7 +755,8 @@ class Looper(Generic[_T]):
|
|
752
755
|
self._logger.warning(
|
753
756
|
"%s: changing sub-looper %s to auto-start...", self, looper
|
754
757
|
)
|
755
|
-
|
758
|
+
async with self._lock:
|
759
|
+
looper.auto_start = True
|
756
760
|
_ = await self._stack.enter_async_context(looper)
|
757
761
|
if self.auto_start:
|
758
762
|
_ = self._debug and self._logger.debug("%s: auto-starting...", self)
|
@@ -797,9 +801,6 @@ class Looper(Generic[_T]):
|
|
797
801
|
case Task() as task:
|
798
802
|
return task.__await__()
|
799
803
|
case _ as never:
|
800
|
-
self._logger.warning( # pragma: no cover
|
801
|
-
"Got %s of type %s", self._task, type(self._task)
|
802
|
-
)
|
803
804
|
assert_never(never)
|
804
805
|
|
805
806
|
def __len__(self) -> int:
|
@@ -812,6 +813,10 @@ class Looper(Generic[_T]):
|
|
812
813
|
"""Check if the queue is empty."""
|
813
814
|
return self._queue.empty()
|
814
815
|
|
816
|
+
def get_all_nowait(self, *, reverse: bool = False) -> Sequence[_T]:
|
817
|
+
"""Remove and return all items from the queue without blocking."""
|
818
|
+
return self._queue.get_all_nowait(reverse=reverse)
|
819
|
+
|
815
820
|
def get_left_nowait(self) -> _T:
|
816
821
|
"""Remove and return an item from the start of the queue without blocking."""
|
817
822
|
return self._queue.get_left_nowait()
|
@@ -820,7 +825,7 @@ class Looper(Generic[_T]):
|
|
820
825
|
"""Remove and return an item from the end of the queue without blocking."""
|
821
826
|
return self._queue.get_right_nowait()
|
822
827
|
|
823
|
-
async def initialize(self) -> Exception | None:
|
828
|
+
async def initialize(self, *, sleep_if_failure: bool) -> Exception | None:
|
824
829
|
"""Initialize the looper."""
|
825
830
|
match self._is_initializing.is_set():
|
826
831
|
case True:
|
@@ -830,23 +835,38 @@ class Looper(Generic[_T]):
|
|
830
835
|
_ = self._debug and self._logger.debug("%s: initializing...", self)
|
831
836
|
self._is_initializing.set()
|
832
837
|
self._is_initialized.clear()
|
833
|
-
self.
|
838
|
+
async with self._lock:
|
839
|
+
self._initialization_attempts += 1
|
834
840
|
try:
|
835
841
|
await self._initialize_core()
|
836
842
|
except Exception as error: # noqa: BLE001
|
837
|
-
|
838
|
-
|
839
|
-
self,
|
840
|
-
repr_error(error),
|
841
|
-
)
|
842
|
-
self._initialization_failures += 1
|
843
|
+
async with self._lock:
|
844
|
+
self._initialization_failures += 1
|
843
845
|
ret = error
|
846
|
+
match sleep_if_failure:
|
847
|
+
case True:
|
848
|
+
_ = self._logger.warning(
|
849
|
+
"%s: encountered %s whilst initializing; sleeping for %s...",
|
850
|
+
self,
|
851
|
+
repr_error(error),
|
852
|
+
self.backoff,
|
853
|
+
)
|
854
|
+
await sleep(self._backoff)
|
855
|
+
case False:
|
856
|
+
_ = self._logger.warning(
|
857
|
+
"%s: encountered %s whilst initializing",
|
858
|
+
self,
|
859
|
+
repr_error(error),
|
860
|
+
)
|
861
|
+
case _ as never:
|
862
|
+
assert_never(never)
|
844
863
|
else:
|
845
864
|
_ = self._debug and self._logger.debug(
|
846
865
|
"%s: finished initializing", self
|
847
866
|
)
|
848
867
|
self._is_initialized.set()
|
849
|
-
self.
|
868
|
+
async with self._lock:
|
869
|
+
self._initialization_successes += 1
|
850
870
|
ret = None
|
851
871
|
finally:
|
852
872
|
self._is_initializing.clear()
|
@@ -931,39 +951,75 @@ class Looper(Generic[_T]):
|
|
931
951
|
case _ as never:
|
932
952
|
assert_never(never)
|
933
953
|
|
934
|
-
async def restart(self) -> None:
|
954
|
+
async def restart(self, *, sleep_if_failure: bool) -> None:
|
935
955
|
"""Restart the looper."""
|
936
956
|
_ = self._debug and self._logger.debug("%s: restarting...", self)
|
937
957
|
self._is_pending_restart.clear()
|
938
|
-
self.
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
958
|
+
async with self._lock:
|
959
|
+
self._restart_attempts += 1
|
960
|
+
tear_down = await self.tear_down(sleep_if_failure=False)
|
961
|
+
initialization = await self.initialize(sleep_if_failure=False)
|
962
|
+
match tear_down, initialization, sleep_if_failure:
|
963
|
+
case None, None, bool():
|
943
964
|
_ = self._debug and self._logger.debug("%s: finished restarting", self)
|
944
|
-
self.
|
945
|
-
|
965
|
+
async with self._lock:
|
966
|
+
self._restart_successes += 1
|
967
|
+
case Exception(), None, True:
|
968
|
+
async with self._lock:
|
969
|
+
self._restart_failures += 1
|
970
|
+
_ = self._logger.warning(
|
971
|
+
"%s: encountered %s whilst restarting (tear down); sleeping for %s...",
|
972
|
+
self,
|
973
|
+
repr_error(tear_down),
|
974
|
+
self.backoff,
|
975
|
+
)
|
976
|
+
await sleep(self._backoff)
|
977
|
+
case Exception(), None, False:
|
978
|
+
async with self._lock:
|
979
|
+
self._restart_failures += 1
|
946
980
|
_ = self._logger.warning(
|
947
|
-
"%s: encountered %s whilst restarting
|
981
|
+
"%s: encountered %s whilst restarting (tear down)",
|
948
982
|
self,
|
949
983
|
repr_error(tear_down),
|
950
984
|
)
|
951
|
-
|
952
|
-
|
985
|
+
case None, Exception(), True:
|
986
|
+
async with self._lock:
|
987
|
+
self._restart_failures += 1
|
953
988
|
_ = self._logger.warning(
|
954
|
-
"%s: encountered %s whilst restarting
|
989
|
+
"%s: encountered %s whilst restarting (initialize); sleeping for %s...",
|
955
990
|
self,
|
956
991
|
repr_error(initialization),
|
992
|
+
self.backoff,
|
957
993
|
)
|
958
|
-
self.
|
959
|
-
case Exception(),
|
994
|
+
await sleep(self._backoff)
|
995
|
+
case None, Exception(), False:
|
996
|
+
async with self._lock:
|
997
|
+
self._restart_failures += 1
|
998
|
+
_ = self._logger.warning(
|
999
|
+
"%s: encountered %s whilst restarting (initialize)",
|
1000
|
+
self,
|
1001
|
+
repr_error(initialization),
|
1002
|
+
)
|
1003
|
+
case Exception(), Exception(), True:
|
1004
|
+
async with self._lock:
|
1005
|
+
self._restart_failures += 1
|
1006
|
+
_ = self._logger.warning(
|
1007
|
+
"%s: encountered %s (tear down) and then %s (initialization) whilst restarting; sleeping for %s...",
|
1008
|
+
self,
|
1009
|
+
repr_error(tear_down),
|
1010
|
+
repr_error(initialization),
|
1011
|
+
self.backoff,
|
1012
|
+
)
|
1013
|
+
await sleep(self._backoff)
|
1014
|
+
case Exception(), Exception(), False:
|
1015
|
+
async with self._lock:
|
1016
|
+
self._restart_failures += 1
|
960
1017
|
_ = self._logger.warning(
|
961
1018
|
"%s: encountered %s (tear down) and then %s (initialization) whilst restarting",
|
962
1019
|
self,
|
963
1020
|
repr_error(tear_down),
|
964
1021
|
repr_error(initialization),
|
965
1022
|
)
|
966
|
-
self._restart_failures += 1
|
967
1023
|
case _ as never:
|
968
1024
|
assert_never(never)
|
969
1025
|
|
@@ -979,12 +1035,13 @@ class Looper(Generic[_T]):
|
|
979
1035
|
):
|
980
1036
|
await self.stop()
|
981
1037
|
elif self._is_pending_restart.is_set():
|
982
|
-
await self.restart()
|
1038
|
+
await self.restart(sleep_if_failure=True)
|
983
1039
|
elif not self._is_initialized.is_set():
|
984
|
-
_ = await self.initialize()
|
1040
|
+
_ = await self.initialize(sleep_if_failure=True)
|
985
1041
|
else:
|
986
1042
|
_ = self._debug and self._logger.debug("%s: running core...", self)
|
987
|
-
self.
|
1043
|
+
async with self._lock:
|
1044
|
+
self._core_attempts += 1
|
988
1045
|
try:
|
989
1046
|
await self.core()
|
990
1047
|
except Exception as error: # noqa: BLE001
|
@@ -993,11 +1050,13 @@ class Looper(Generic[_T]):
|
|
993
1050
|
self,
|
994
1051
|
repr_error(error),
|
995
1052
|
)
|
996
|
-
self.
|
1053
|
+
async with self._lock:
|
1054
|
+
self._core_failures += 1
|
997
1055
|
self.request_restart()
|
998
1056
|
await sleep(self._backoff)
|
999
1057
|
else:
|
1000
|
-
self.
|
1058
|
+
async with self._lock:
|
1059
|
+
self._core_successes += 1
|
1001
1060
|
await sleep(self._freq)
|
1002
1061
|
|
1003
1062
|
@property
|
@@ -1029,12 +1088,13 @@ class Looper(Generic[_T]):
|
|
1029
1088
|
_ = self._debug and self._logger.debug("%s: stopping...", self)
|
1030
1089
|
self._is_pending_stop.clear()
|
1031
1090
|
self._is_stopped.set()
|
1032
|
-
self.
|
1091
|
+
async with self._lock:
|
1092
|
+
self._stops += 1
|
1033
1093
|
_ = self._debug and self._logger.debug("%s: stopped", self)
|
1034
1094
|
case _ as never:
|
1035
1095
|
assert_never(never)
|
1036
1096
|
|
1037
|
-
async def tear_down(self) -> Exception | None:
|
1097
|
+
async def tear_down(self, *, sleep_if_failure: bool) -> Exception | None:
|
1038
1098
|
"""Tear down the looper."""
|
1039
1099
|
match self._is_tearing_down.is_set():
|
1040
1100
|
case True:
|
@@ -1043,22 +1103,37 @@ class Looper(Generic[_T]):
|
|
1043
1103
|
case False:
|
1044
1104
|
_ = self._debug and self._logger.debug("%s: tearing down...", self)
|
1045
1105
|
self._is_tearing_down.set()
|
1046
|
-
self.
|
1106
|
+
async with self._lock:
|
1107
|
+
self._tear_down_attempts += 1
|
1047
1108
|
try:
|
1048
1109
|
await self._tear_down_core()
|
1049
1110
|
except Exception as error: # noqa: BLE001
|
1050
|
-
|
1051
|
-
|
1052
|
-
self,
|
1053
|
-
repr_error(error),
|
1054
|
-
)
|
1055
|
-
self._tear_down_failures += 1
|
1111
|
+
async with self._lock:
|
1112
|
+
self._tear_down_failures += 1
|
1056
1113
|
ret = error
|
1114
|
+
match sleep_if_failure:
|
1115
|
+
case True:
|
1116
|
+
_ = self._logger.warning(
|
1117
|
+
"%s: encountered %s whilst tearing down; sleeping for %s...",
|
1118
|
+
self,
|
1119
|
+
repr_error(error),
|
1120
|
+
self.backoff,
|
1121
|
+
)
|
1122
|
+
await sleep(self._backoff)
|
1123
|
+
case False:
|
1124
|
+
_ = self._logger.warning(
|
1125
|
+
"%s: encountered %s whilst tearing down",
|
1126
|
+
self,
|
1127
|
+
repr_error(error),
|
1128
|
+
)
|
1129
|
+
case _ as never:
|
1130
|
+
assert_never(never)
|
1057
1131
|
else:
|
1058
1132
|
_ = self._debug and self._logger.debug(
|
1059
1133
|
"%s: finished tearing down", self
|
1060
1134
|
)
|
1061
|
-
self.
|
1135
|
+
async with self._lock:
|
1136
|
+
self._tear_down_successes += 1
|
1062
1137
|
ret = None
|
1063
1138
|
finally:
|
1064
1139
|
self._is_tearing_down.clear()
|
File without changes
|
File without changes
|