dycw-utilities 0.129.2__py3-none-any.whl → 0.129.4__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.129.2
3
+ Version: 0.129.4
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=xCbJwDm5euQ0FhR3M7TD-JZyt1BghWGAEn2rH1dZO9k,60
1
+ utilities/__init__.py,sha256=iWGDxgmsVT0VQXeoYsnAQdkemzRAZrOSjZyR1ckem_k,60
2
2
  utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
3
- utilities/asyncio.py,sha256=mP67R3RwY6cTCgiNlxA9h-o3Y6xv5uGzKKB08C49uKI,37001
3
+ utilities/asyncio.py,sha256=3n5EIcSq2xtEF1i4oR0oY2JmBq3NyugeHKFK39Mt22s,37987
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
@@ -29,7 +29,7 @@ utilities/iterables.py,sha256=mDqw2_0MUVp-P8FklgcaVTi2TXduH0MxbhTDzzhSBho,44915
29
29
  utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
30
30
  utilities/libcst.py,sha256=Jto5ppzRzsxn4AD32IS8n0lbgLYXwsVJB6EY8giNZyY,4974
31
31
  utilities/lightweight_charts.py,sha256=0xNfcsrgFI0R9xL25LtSm-W5yhfBI93qQNT6HyaXAhg,2769
32
- utilities/logging.py,sha256=a99gX9oQUe_Oxs5rDtTwUVuOwhRyeO_GfoFNKVaEny0,25641
32
+ utilities/logging.py,sha256=sLNnk79ZvkSKjgiUemz2IfUnGykqxYOfv4qzYXrznJc,24749
33
33
  utilities/loguru.py,sha256=MEMQVWrdECxk1e3FxGzmOf21vWT9j8CAir98SEXFKPA,3809
34
34
  utilities/luigi.py,sha256=fpH9MbxJDuo6-k9iCXRayFRtiVbUtibCJKugf7ygpv0,5988
35
35
  utilities/math.py,sha256=-mQgbah-dPJwOEWf3SonrFoVZ2AVxMgpeQ3dfVa-oJA,26764
@@ -89,7 +89,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
89
89
  utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
90
90
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
91
91
  utilities/zoneinfo.py,sha256=-5j7IQ9nb7gR43rdgA7ms05im-XuqhAk9EJnQBXxCoQ,1874
92
- dycw_utilities-0.129.2.dist-info/METADATA,sha256=2XZ9vn3lnybj_7rhJwuTFSU8SVBRLkroYURNVY1_9sc,12803
93
- dycw_utilities-0.129.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- dycw_utilities-0.129.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.129.2.dist-info/RECORD,,
92
+ dycw_utilities-0.129.4.dist-info/METADATA,sha256=On504jBueWCjsq6PhxCZPKQvCLqVXkN5gFiE75xg5zc,12803
93
+ dycw_utilities-0.129.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ dycw_utilities-0.129.4.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.129.4.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.129.2"
3
+ __version__ = "0.129.4"
utilities/asyncio.py CHANGED
@@ -353,6 +353,7 @@ class Looper(Generic[_T]):
353
353
  _is_entered: Event = field(default_factory=Event, init=False, repr=False)
354
354
  _is_initialized: Event = field(default_factory=Event, init=False, repr=False)
355
355
  _is_initializing: Event = field(default_factory=Event, init=False, repr=False)
356
+ _is_pending_back_off: Event = field(default_factory=Event, init=False, repr=False)
356
357
  _is_pending_restart: Event = field(default_factory=Event, init=False, repr=False)
357
358
  _is_pending_stop: Event = field(default_factory=Event, init=False, repr=False)
358
359
  _is_pending_stop_when_empty: Event = field(
@@ -439,6 +440,11 @@ class Looper(Generic[_T]):
439
440
  def __len__(self) -> int:
440
441
  return self._queue.qsize()
441
442
 
443
+ async def _apply_back_off(self) -> None:
444
+ """Apply a back off period."""
445
+ await sleep(self._backoff)
446
+ self._is_pending_back_off.clear()
447
+
442
448
  async def core(self) -> None:
443
449
  """Core part of running the looper."""
444
450
 
@@ -492,7 +498,7 @@ class Looper(Generic[_T]):
492
498
  repr_error(error),
493
499
  self.backoff,
494
500
  )
495
- await sleep(self._backoff)
501
+ await self._apply_back_off()
496
502
  case _ as never:
497
503
  assert_never(never)
498
504
  else:
@@ -549,6 +555,21 @@ class Looper(Generic[_T]):
549
555
  **kwargs,
550
556
  )
551
557
 
558
+ def request_back_off(self) -> None:
559
+ """Request the looper to back off."""
560
+ match self._is_pending_back_off.is_set():
561
+ case True:
562
+ _ = self._debug and self._logger.debug(
563
+ "%s: already requested back off", self
564
+ )
565
+ case False:
566
+ _ = self._debug and self._logger.debug(
567
+ "%s: requesting back off...", self
568
+ )
569
+ self._is_pending_back_off.set()
570
+ case _ as never:
571
+ assert_never(never)
572
+
552
573
  def request_restart(self) -> None:
553
574
  """Request the looper to restart."""
554
575
  match self._is_pending_restart.is_set():
@@ -563,6 +584,7 @@ class Looper(Generic[_T]):
563
584
  self._is_pending_restart.set()
564
585
  case _ as never:
565
586
  assert_never(never)
587
+ self.request_back_off()
566
588
 
567
589
  def request_stop(self) -> None:
568
590
  """Request the looper to stop."""
@@ -602,9 +624,7 @@ class Looper(Generic[_T]):
602
624
  initialization = await self.initialize(skip_sleep_if_failure=True)
603
625
  match tear_down, initialization:
604
626
  case None, None:
605
- _ = self._debug and self._logger.debug(
606
- "%s: finished restarting; sleeping for %s...", self, self.backoff
607
- )
627
+ _ = self._debug and self._logger.debug("%s: finished restarting", self)
608
628
  async with self._lock:
609
629
  self._restart_successes += 1
610
630
  case Exception(), None:
@@ -616,6 +636,7 @@ class Looper(Generic[_T]):
616
636
  repr_error(tear_down),
617
637
  self.backoff,
618
638
  )
639
+ await self._apply_back_off()
619
640
  case None, Exception():
620
641
  async with self._lock:
621
642
  self._restart_failures += 1
@@ -625,6 +646,7 @@ class Looper(Generic[_T]):
625
646
  repr_error(initialization),
626
647
  self.backoff,
627
648
  )
649
+ await self._apply_back_off()
628
650
  case Exception(), Exception():
629
651
  async with self._lock:
630
652
  self._restart_failures += 1
@@ -635,9 +657,9 @@ class Looper(Generic[_T]):
635
657
  repr_error(initialization),
636
658
  self.backoff,
637
659
  )
660
+ await self._apply_back_off()
638
661
  case _ as never:
639
662
  assert_never(never)
640
- await sleep(self._backoff)
641
663
 
642
664
  async def run_looper(self) -> None:
643
665
  """Run the looper."""
@@ -651,6 +673,8 @@ class Looper(Generic[_T]):
651
673
  self._is_pending_stop_when_empty.is_set() and self.empty()
652
674
  ):
653
675
  await self.stop()
676
+ elif self._is_pending_back_off.is_set():
677
+ await self._apply_back_off()
654
678
  elif self._is_pending_restart.is_set():
655
679
  await self.restart()
656
680
  elif not self._is_initialized.is_set():
@@ -758,7 +782,7 @@ class Looper(Generic[_T]):
758
782
  repr_error(error),
759
783
  self.backoff,
760
784
  )
761
- await sleep(self._backoff)
785
+ await self._apply_back_off()
762
786
  case _ as never:
763
787
  assert_never(never)
764
788
  else:
utilities/logging.py CHANGED
@@ -23,7 +23,7 @@ from logging import (
23
23
  )
24
24
  from logging.handlers import BaseRotatingHandler, TimedRotatingFileHandler
25
25
  from pathlib import Path
26
- from re import Pattern, search
26
+ from re import Pattern
27
27
  from sys import stdout
28
28
  from time import time
29
29
  from typing import (
@@ -751,29 +751,6 @@ class _AdvancedLogRecord(LogRecord):
751
751
  cls.time_zone = time_zone.key # skipif-ci-and-windows
752
752
  super().__init_subclass__(**kwargs) # skipif-ci-and-windows
753
753
 
754
- @override
755
- def getMessage(self) -> str:
756
- """Return the message for this LogRecord."""
757
- msg = str(self.msg) # pragma: no cover
758
- if self.args: # pragma: no cover
759
- try:
760
- return msg % self.args # compability for 3rd party code
761
- except ValueError as error:
762
- if len(error.args) == 0:
763
- raise
764
- first = error.args[0]
765
- if search("unsupported format character", first):
766
- return msg.format(*self.args)
767
- raise
768
- except TypeError as error:
769
- if len(error.args) == 0:
770
- raise
771
- first = error.args[0]
772
- if search("not all arguments converted", first):
773
- return msg.format(*self.args)
774
- raise
775
- return msg # pragma: no cover
776
-
777
754
  @classmethod
778
755
  def get_now(cls) -> Any:
779
756
  """Get the current zoned datetime."""