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.
- {dycw_utilities-0.117.0.dist-info → dycw_utilities-0.117.1.dist-info}/METADATA +1 -1
- {dycw_utilities-0.117.0.dist-info → dycw_utilities-0.117.1.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/asyncio.py +40 -12
- {dycw_utilities-0.117.0.dist-info → dycw_utilities-0.117.1.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.117.0.dist-info → dycw_utilities-0.117.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
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=
|
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.
|
92
|
-
dycw_utilities-0.117.
|
93
|
-
dycw_utilities-0.117.
|
94
|
-
dycw_utilities-0.117.
|
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
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:
|
345
|
-
sleep_restart:
|
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
|
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
|
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
|
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
|
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
|
421
|
+
"%r encountered %r whilst initializing; sleeping %s...",
|
417
422
|
get_class_name(self),
|
418
423
|
repr_error(error),
|
419
|
-
self.
|
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
|
431
|
+
"%r encountered %r; sleeping %s...",
|
427
432
|
get_class_name(self),
|
428
433
|
repr_error(error),
|
429
|
-
self.
|
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
|
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:
|
File without changes
|
File without changes
|