dycw-utilities 0.125.12__py3-none-any.whl → 0.125.13__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.125.12
3
+ Version: 0.125.13
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,6 +1,6 @@
1
- utilities/__init__.py,sha256=eu0r7qVMzjFJgG7Su5IuWbXETZTCy5nXfNr7kwpH_yw,61
1
+ utilities/__init__.py,sha256=7ZYwhNHFuejRkKzg0MeSvh2I14YxTE-mRj6ie69FmMU,61
2
2
  utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
3
- utilities/asyncio.py,sha256=G7CaIcR-oANVjKWIH7KFMHpPZqL1CkwCV6FBT8vrkKA,46941
3
+ utilities/asyncio.py,sha256=uUVIpmBMP-tAYPnE2Yi7ZyTno7VYImjNp7uA85MQhys,47865
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.12.dist-info/METADATA,sha256=9JECEW7LQjwHf5sjb53N4xApsa3V9RImfG__u2LDN4E,12852
92
- dycw_utilities-0.125.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- dycw_utilities-0.125.12.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
94
- dycw_utilities-0.125.12.dist-info/RECORD,,
91
+ dycw_utilities-0.125.13.dist-info/METADATA,sha256=hQ21eoRHxkp3q3Y7wQ3F9fXew2_S1sTHV3hd68qX8e4,12852
92
+ dycw_utilities-0.125.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ dycw_utilities-0.125.13.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
94
+ dycw_utilities-0.125.13.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.125.12"
3
+ __version__ = "0.125.13"
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._entries += 1
746
- self._task = create_task(self.run_looper())
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
- looper.auto_start = True
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()
@@ -830,7 +835,8 @@ 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._initialization_attempts += 1
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
@@ -839,14 +845,16 @@ class Looper(Generic[_T]):
839
845
  self,
840
846
  repr_error(error),
841
847
  )
842
- self._initialization_failures += 1
848
+ async with self._lock:
849
+ self._initialization_failures += 1
843
850
  ret = error
844
851
  else:
845
852
  _ = self._debug and self._logger.debug(
846
853
  "%s: finished initializing", self
847
854
  )
848
855
  self._is_initialized.set()
849
- self._initialization_successes += 1
856
+ async with self._lock:
857
+ self._initialization_successes += 1
850
858
  ret = None
851
859
  finally:
852
860
  self._is_initializing.clear()
@@ -935,27 +943,31 @@ class Looper(Generic[_T]):
935
943
  """Restart the looper."""
936
944
  _ = self._debug and self._logger.debug("%s: restarting...", self)
937
945
  self._is_pending_restart.clear()
938
- self._restart_attempts += 1
946
+ async with self._lock:
947
+ self._restart_attempts += 1
939
948
  tear_down = await self.tear_down()
940
949
  initialization = await self.initialize()
941
950
  match tear_down, initialization:
942
951
  case None, None:
943
952
  _ = self._debug and self._logger.debug("%s: finished restarting", self)
944
- self._restart_successes += 1
953
+ async with self._lock:
954
+ self._restart_successes += 1
945
955
  case Exception(), None:
946
956
  _ = self._logger.warning(
947
957
  "%s: encountered %s whilst restarting, during tear down",
948
958
  self,
949
959
  repr_error(tear_down),
950
960
  )
951
- self._restart_failures += 1
961
+ async with self._lock:
962
+ self._restart_failures += 1
952
963
  case None, Exception():
953
964
  _ = self._logger.warning(
954
965
  "%s: encountered %s whilst restarting, during initialization",
955
966
  self,
956
967
  repr_error(initialization),
957
968
  )
958
- self._restart_failures += 1
969
+ async with self._lock:
970
+ self._restart_failures += 1
959
971
  case Exception(), Exception():
960
972
  _ = self._logger.warning(
961
973
  "%s: encountered %s (tear down) and then %s (initialization) whilst restarting",
@@ -963,7 +975,8 @@ class Looper(Generic[_T]):
963
975
  repr_error(tear_down),
964
976
  repr_error(initialization),
965
977
  )
966
- self._restart_failures += 1
978
+ async with self._lock:
979
+ self._restart_failures += 1
967
980
  case _ as never:
968
981
  assert_never(never)
969
982
 
@@ -984,7 +997,8 @@ class Looper(Generic[_T]):
984
997
  _ = await self.initialize()
985
998
  else:
986
999
  _ = self._debug and self._logger.debug("%s: running core...", self)
987
- self._core_attempts += 1
1000
+ async with self._lock:
1001
+ self._core_attempts += 1
988
1002
  try:
989
1003
  await self.core()
990
1004
  except Exception as error: # noqa: BLE001
@@ -993,11 +1007,13 @@ class Looper(Generic[_T]):
993
1007
  self,
994
1008
  repr_error(error),
995
1009
  )
996
- self._core_failures += 1
1010
+ async with self._lock:
1011
+ self._core_failures += 1
997
1012
  self.request_restart()
998
1013
  await sleep(self._backoff)
999
1014
  else:
1000
- self._core_successes += 1
1015
+ async with self._lock:
1016
+ self._core_successes += 1
1001
1017
  await sleep(self._freq)
1002
1018
 
1003
1019
  @property
@@ -1029,7 +1045,8 @@ class Looper(Generic[_T]):
1029
1045
  _ = self._debug and self._logger.debug("%s: stopping...", self)
1030
1046
  self._is_pending_stop.clear()
1031
1047
  self._is_stopped.set()
1032
- self._stops += 1
1048
+ async with self._lock:
1049
+ self._stops += 1
1033
1050
  _ = self._debug and self._logger.debug("%s: stopped", self)
1034
1051
  case _ as never:
1035
1052
  assert_never(never)
@@ -1043,7 +1060,8 @@ class Looper(Generic[_T]):
1043
1060
  case False:
1044
1061
  _ = self._debug and self._logger.debug("%s: tearing down...", self)
1045
1062
  self._is_tearing_down.set()
1046
- self._tear_down_attempts += 1
1063
+ async with self._lock:
1064
+ self._tear_down_attempts += 1
1047
1065
  try:
1048
1066
  await self._tear_down_core()
1049
1067
  except Exception as error: # noqa: BLE001
@@ -1052,13 +1070,15 @@ class Looper(Generic[_T]):
1052
1070
  self,
1053
1071
  repr_error(error),
1054
1072
  )
1055
- self._tear_down_failures += 1
1073
+ async with self._lock:
1074
+ self._tear_down_failures += 1
1056
1075
  ret = error
1057
1076
  else:
1058
1077
  _ = self._debug and self._logger.debug(
1059
1078
  "%s: finished tearing down", self
1060
1079
  )
1061
- self._tear_down_successes += 1
1080
+ async with self._lock:
1081
+ self._tear_down_successes += 1
1062
1082
  ret = None
1063
1083
  finally:
1064
1084
  self._is_tearing_down.clear()