dycw-utilities 0.117.0__py3-none-any.whl → 0.117.1__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.117.0
3
+ Version: 0.117.1
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,7 +1,7 @@
1
- utilities/__init__.py,sha256=P9EtLQQfrOCDM1TAOhodQ4gfhNisheGhmugAZrQJYYc,60
1
+ utilities/__init__.py,sha256=3AZFp33-B-_k917jGyOdDiXXC3IjJevPa1TRWy9GCgs,60
2
2
  utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
3
3
  utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
4
- utilities/asyncio.py,sha256=HqPgdti3ZJPH7uHJkvmZ2weIVKYEpB6FKh6FBriMAPU,24287
4
+ utilities/asyncio.py,sha256=R_UJvKhbhjUKxzotJUoFiE05pVy5Y6rQqwJodAjFMHY,25443
5
5
  utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
6
6
  utilities/atools.py,sha256=IYMuFSFGSKyuQmqD6v5IUtDlz8PPw0Sr87Cub_gRU3M,1168
7
7
  utilities/cachetools.py,sha256=C1zqOg7BYz0IfQFK8e3qaDDgEZxDpo47F15RTfJM37Q,2910
@@ -88,7 +88,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
88
88
  utilities/whenever.py,sha256=fC0ZtnO0AyFHsxP4SWj0POI1bf4BIL3Hh4rR51BHfaw,17803
89
89
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
90
90
  utilities/zoneinfo.py,sha256=-Xm57PMMwDTYpxJdkiJG13wnbwK--I7XItBh5WVhD-o,1874
91
- dycw_utilities-0.117.0.dist-info/METADATA,sha256=OB8XvTMe2rLu98khXHV7Y43VtZl_4iotbtejKesZsZg,12943
92
- dycw_utilities-0.117.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- dycw_utilities-0.117.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
94
- dycw_utilities-0.117.0.dist-info/RECORD,,
91
+ dycw_utilities-0.117.1.dist-info/METADATA,sha256=jFmm81hWyjNuttvOK52BPLHNdskY53ciWAA7CLMYy_I,12943
92
+ dycw_utilities-0.117.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ dycw_utilities-0.117.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
94
+ dycw_utilities-0.117.1.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.117.0"
3
+ __version__ = "0.117.1"
utilities/asyncio.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import datetime as dt
3
4
  from abc import ABC, abstractmethod
4
5
  from asyncio import (
5
6
  CancelledError,
@@ -32,6 +33,7 @@ from typing import (
32
33
  TYPE_CHECKING,
33
34
  Any,
34
35
  Generic,
36
+ Literal,
35
37
  NoReturn,
36
38
  Self,
37
39
  TextIO,
@@ -46,6 +48,7 @@ from utilities.datetime import (
46
48
  MINUTE,
47
49
  SECOND,
48
50
  datetime_duration_to_float,
51
+ datetime_duration_to_timedelta,
49
52
  get_now,
50
53
  round_datetime,
51
54
  )
@@ -62,7 +65,6 @@ from utilities.types import (
62
65
  )
63
66
 
64
67
  if TYPE_CHECKING:
65
- import datetime as dt
66
68
  from asyncio import _CoroutineLike
67
69
  from asyncio.subprocess import Process
68
70
  from collections.abc import AsyncIterator, Sequence
@@ -337,12 +339,15 @@ class ExceptionProcessor(QueueProcessor[Exception | type[Exception]]):
337
339
  ##
338
340
 
339
341
 
342
+ type _DurationOrEvery = Duration | tuple[Literal["every"], Duration]
343
+
344
+
340
345
  @dataclass(kw_only=True, unsafe_hash=True)
341
346
  class InfiniteLooper(ABC, Generic[THashable]):
342
347
  """An infinite loop which can throw exceptions by setting events."""
343
348
 
344
- sleep_core: Duration = SECOND
345
- sleep_restart: Duration = MINUTE
349
+ sleep_core: _DurationOrEvery = SECOND
350
+ sleep_restart: _DurationOrEvery = MINUTE
346
351
  logger: str | None = None
347
352
  _events: Mapping[THashable, Event] = field(
348
353
  default_factory=dict, init=False, repr=False, hash=False
@@ -369,7 +374,7 @@ class InfiniteLooper(ABC, Generic[THashable]):
369
374
  await self._initialize()
370
375
  except Exception as error: # noqa: BLE001
371
376
  self._error_upon_initialize(error)
372
- await sleep_dur(duration=self.sleep_restart)
377
+ await self._run_sleep(self.sleep_restart)
373
378
  else:
374
379
  while True:
375
380
  try:
@@ -380,14 +385,14 @@ class InfiniteLooper(ABC, Generic[THashable]):
380
385
  )
381
386
  except StopIteration:
382
387
  await self._core()
383
- await sleep_dur(duration=self.sleep_core)
388
+ await self._run_sleep(self.sleep_core)
384
389
  else:
385
390
  self._raise_error(event)
386
391
  except InfiniteLooperError:
387
392
  raise
388
393
  except Exception as error: # noqa: BLE001
389
394
  self._error_upon_core(error)
390
- await sleep_dur(duration=self.sleep_restart)
395
+ await self._run_sleep(self.sleep_restart)
391
396
 
392
397
  async def _run_looper_with_coroutines(
393
398
  self, *coroutines: Callable[[], Coroutine1[None]]
@@ -401,7 +406,7 @@ class InfiniteLooper(ABC, Generic[THashable]):
401
406
  _ = [tg.create_task(c()) for c in coroutines]
402
407
  except ExceptionGroup as error:
403
408
  self._error_group_upon_coroutines(error)
404
- await sleep_dur(duration=self.sleep_restart)
409
+ await self._run_sleep(self.sleep_restart)
405
410
 
406
411
  async def _initialize(self) -> None:
407
412
  """Initialize the loop."""
@@ -413,20 +418,20 @@ class InfiniteLooper(ABC, Generic[THashable]):
413
418
  """Handle any errors upon initializing the looper."""
414
419
  if self.logger is not None:
415
420
  getLogger(name=self.logger).error(
416
- "%r encountered %r whilst initializing; sleeping for %s...",
421
+ "%r encountered %r whilst initializing; sleeping %s...",
417
422
  get_class_name(self),
418
423
  repr_error(error),
419
- self.sleep_restart,
424
+ self._sleep_restart_desc,
420
425
  )
421
426
 
422
427
  def _error_upon_core(self, error: Exception, /) -> None:
423
428
  """Handle any errors upon running the core function."""
424
429
  if self.logger is not None:
425
430
  getLogger(name=self.logger).error(
426
- "%r encountered %r; sleeping for %s...",
431
+ "%r encountered %r; sleeping %s...",
427
432
  get_class_name(self),
428
433
  repr_error(error),
429
- self.sleep_restart,
434
+ self._sleep_restart_desc,
430
435
  )
431
436
 
432
437
  def _error_group_upon_coroutines(self, group: ExceptionGroup, /) -> None:
@@ -439,7 +444,7 @@ class InfiniteLooper(ABC, Generic[THashable]):
439
444
  f"- Error #{i}/{n}: {repr_error(e)}"
440
445
  for i, e in enumerate(errors, start=1)
441
446
  )
442
- msgs.append(f"Sleeping for {self.sleep_restart}...")
447
+ msgs.append(f"Sleeping {self._sleep_restart_desc}...")
443
448
  getLogger(name=self.logger).error("\n".join(msgs))
444
449
 
445
450
  def _raise_error(self, event: THashable, /) -> NoReturn:
@@ -454,6 +459,29 @@ class InfiniteLooper(ABC, Generic[THashable]):
454
459
  event: Event() for event, _ in self._yield_events_and_exceptions()
455
460
  }
456
461
 
462
+ async def _run_sleep(self, sleep: _DurationOrEvery, /) -> None:
463
+ """Sleep until the next part of the loop."""
464
+ match sleep:
465
+ case int() | float() | dt.timedelta() as duration:
466
+ await sleep_dur(duration=duration)
467
+ case "every", (int() | float() | dt.timedelta()) as duration:
468
+ await sleep_until_rounded(duration)
469
+ case _ as never:
470
+ assert_never(never)
471
+
472
+ @property
473
+ def _sleep_restart_desc(self) -> str:
474
+ """Get a description of the sleep until restart."""
475
+ match self.sleep_restart:
476
+ case int() | float() | dt.timedelta() as duration:
477
+ timedelta = datetime_duration_to_timedelta(duration)
478
+ return f"for {timedelta}"
479
+ case "every", (int() | float() | dt.timedelta()) as duration:
480
+ timedelta = datetime_duration_to_timedelta(duration)
481
+ return f"until next {timedelta}"
482
+ case _ as never:
483
+ assert_never(never)
484
+
457
485
  def _set_event(self, event: THashable, /) -> None:
458
486
  """Set the given event."""
459
487
  try: