dycw-utilities 0.116.6__py3-none-any.whl → 0.117.0__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.116.6.dist-info → dycw_utilities-0.117.0.dist-info}/METADATA +1 -1
- {dycw_utilities-0.116.6.dist-info → dycw_utilities-0.117.0.dist-info}/RECORD +8 -8
- utilities/__init__.py +1 -1
- utilities/asyncio.py +32 -1
- utilities/datetime.py +58 -55
- utilities/whenever.py +2 -2
- {dycw_utilities-0.116.6.dist-info → dycw_utilities-0.117.0.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.116.6.dist-info → dycw_utilities-0.117.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=P9EtLQQfrOCDM1TAOhodQ4gfhNisheGhmugAZrQJYYc,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=HqPgdti3ZJPH7uHJkvmZ2weIVKYEpB6FKh6FBriMAPU,24287
|
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
|
@@ -12,7 +12,7 @@ utilities/contextvars.py,sha256=RsSGGrbQqqZ67rOydnM7WWIsM2lIE31UHJLejnHJPWY,505
|
|
12
12
|
utilities/cryptography.py,sha256=_CiK_K6c_-uQuUhsUNjNjTL-nqxAh4_1zTfS11Xe120,972
|
13
13
|
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
14
14
|
utilities/dataclasses.py,sha256=iiC1wpGXWhaocIikzwBt8bbLWyImoUlOlcDZJGejaIg,33011
|
15
|
-
utilities/datetime.py,sha256=
|
15
|
+
utilities/datetime.py,sha256=VOwjPibw63Myv-CRYhT2eEHpz277GqUiEDEaI7p-nQw,38985
|
16
16
|
utilities/enum.py,sha256=HoRwVCWzsnH0vpO9ZEcAAIZLMv0Sn2vJxxA4sYMQgDs,5793
|
17
17
|
utilities/errors.py,sha256=gxsaa7eq7jbYl41Of40-ivjXqJB5gt4QAcJ0smZZMJE,829
|
18
18
|
utilities/eventkit.py,sha256=6M5Xu1SzN-juk9PqBHwy5dS-ta7T0qA6SMpDsakOJ0E,13039
|
@@ -85,10 +85,10 @@ utilities/tzlocal.py,sha256=3upDNFBvGh1l9njmLR2z2S6K6VxQSb7QizYGUbAH3JU,960
|
|
85
85
|
utilities/uuid.py,sha256=jJTFxz-CWgltqNuzmythB7iEQ-Q1mCwPevUfKthZT3c,611
|
86
86
|
utilities/version.py,sha256=QFuyEeQA6jI0ruBEcmhqG36f-etg1AEiD1drBBqhQrs,5358
|
87
87
|
utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
88
|
-
utilities/whenever.py,sha256=
|
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.
|
92
|
-
dycw_utilities-0.
|
93
|
-
dycw_utilities-0.
|
94
|
-
dycw_utilities-0.
|
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,,
|
utilities/__init__.py
CHANGED
utilities/asyncio.py
CHANGED
@@ -41,7 +41,14 @@ from typing import (
|
|
41
41
|
override,
|
42
42
|
)
|
43
43
|
|
44
|
-
from utilities.datetime import
|
44
|
+
from utilities.datetime import (
|
45
|
+
MILLISECOND,
|
46
|
+
MINUTE,
|
47
|
+
SECOND,
|
48
|
+
datetime_duration_to_float,
|
49
|
+
get_now,
|
50
|
+
round_datetime,
|
51
|
+
)
|
45
52
|
from utilities.errors import ImpossibleCaseError, repr_error
|
46
53
|
from utilities.functions import ensure_int, ensure_not_none, get_class_name
|
47
54
|
from utilities.reprlib import get_repr
|
@@ -55,6 +62,7 @@ from utilities.types import (
|
|
55
62
|
)
|
56
63
|
|
57
64
|
if TYPE_CHECKING:
|
65
|
+
import datetime as dt
|
58
66
|
from asyncio import _CoroutineLike
|
59
67
|
from asyncio.subprocess import Process
|
60
68
|
from collections.abc import AsyncIterator, Sequence
|
@@ -686,6 +694,27 @@ async def sleep_dur(*, duration: Duration | None = None) -> None:
|
|
686
694
|
##
|
687
695
|
|
688
696
|
|
697
|
+
async def sleep_until(datetime: dt.datetime, /) -> None:
|
698
|
+
"""Sleep until a given time."""
|
699
|
+
await sleep_dur(duration=datetime - get_now())
|
700
|
+
|
701
|
+
|
702
|
+
##
|
703
|
+
|
704
|
+
|
705
|
+
async def sleep_until_rounded(
|
706
|
+
duration: Duration, /, *, rel_tol: float | None = None, abs_tol: float | None = None
|
707
|
+
) -> None:
|
708
|
+
"""Sleep until a rounded time; accepts durations."""
|
709
|
+
datetime = round_datetime(
|
710
|
+
get_now(), duration, mode="ceil", rel_tol=rel_tol, abs_tol=abs_tol
|
711
|
+
)
|
712
|
+
await sleep_until(datetime)
|
713
|
+
|
714
|
+
|
715
|
+
##
|
716
|
+
|
717
|
+
|
689
718
|
@dataclass(kw_only=True, slots=True)
|
690
719
|
class StreamCommandOutput:
|
691
720
|
process: Process
|
@@ -768,6 +797,8 @@ __all__ = [
|
|
768
797
|
"put_items",
|
769
798
|
"put_items_nowait",
|
770
799
|
"sleep_dur",
|
800
|
+
"sleep_until",
|
801
|
+
"sleep_until_rounded",
|
771
802
|
"stream_command",
|
772
803
|
"timeout_dur",
|
773
804
|
]
|
utilities/datetime.py
CHANGED
@@ -334,6 +334,52 @@ def datetime_duration_to_float(duration: Duration, /) -> float:
|
|
334
334
|
assert_never(never)
|
335
335
|
|
336
336
|
|
337
|
+
def datetime_duration_to_microseconds(duration: Duration, /) -> int:
|
338
|
+
"""Compute the number of microseconds in a datetime duration."""
|
339
|
+
timedelta = datetime_duration_to_timedelta(duration)
|
340
|
+
return (
|
341
|
+
_MICROSECONDS_PER_DAY * timedelta.days
|
342
|
+
+ _MICROSECONDS_PER_SECOND * timedelta.seconds
|
343
|
+
+ timedelta.microseconds
|
344
|
+
)
|
345
|
+
|
346
|
+
|
347
|
+
@overload
|
348
|
+
def datetime_duration_to_milliseconds(
|
349
|
+
duration: Duration, /, *, strict: Literal[True]
|
350
|
+
) -> int: ...
|
351
|
+
@overload
|
352
|
+
def datetime_duration_to_milliseconds(
|
353
|
+
duration: Duration, /, *, strict: bool = False
|
354
|
+
) -> float: ...
|
355
|
+
def datetime_duration_to_milliseconds(
|
356
|
+
duration: Duration, /, *, strict: bool = False
|
357
|
+
) -> int | float:
|
358
|
+
"""Compute the number of milliseconds in a datetime duration."""
|
359
|
+
timedelta = datetime_duration_to_timedelta(duration)
|
360
|
+
microseconds = datetime_duration_to_microseconds(timedelta)
|
361
|
+
milliseconds, remainder = divmod(microseconds, _MICROSECONDS_PER_MILLISECOND)
|
362
|
+
match remainder, strict:
|
363
|
+
case 0, _:
|
364
|
+
return milliseconds
|
365
|
+
case _, True:
|
366
|
+
raise TimedeltaToMillisecondsError(duration=duration, remainder=remainder)
|
367
|
+
case _, False:
|
368
|
+
return milliseconds + remainder / _MICROSECONDS_PER_MILLISECOND
|
369
|
+
case _ as never:
|
370
|
+
assert_never(never)
|
371
|
+
|
372
|
+
|
373
|
+
@dataclass(kw_only=True, slots=True)
|
374
|
+
class TimedeltaToMillisecondsError(Exception):
|
375
|
+
duration: Duration
|
376
|
+
remainder: int
|
377
|
+
|
378
|
+
@override
|
379
|
+
def __str__(self) -> str:
|
380
|
+
return f"Unable to convert {self.duration} to milliseconds; got {self.remainder} microsecond(s)"
|
381
|
+
|
382
|
+
|
337
383
|
def datetime_duration_to_timedelta(duration: Duration, /) -> dt.timedelta:
|
338
384
|
"""Ensure a datetime duration is a timedelta."""
|
339
385
|
match duration:
|
@@ -651,8 +697,9 @@ YEAR = get_years(n=1)
|
|
651
697
|
##
|
652
698
|
|
653
699
|
|
654
|
-
def is_integral_timedelta(
|
655
|
-
"""Check if a
|
700
|
+
def is_integral_timedelta(duration: Duration, /) -> bool:
|
701
|
+
"""Check if a duration is integral."""
|
702
|
+
timedelta = datetime_duration_to_timedelta(duration)
|
656
703
|
return (timedelta.seconds == 0) and (timedelta.microseconds == 0)
|
657
704
|
|
658
705
|
|
@@ -679,9 +726,9 @@ def is_weekday(date: dt.date, /) -> bool:
|
|
679
726
|
##
|
680
727
|
|
681
728
|
|
682
|
-
def is_zero_time(
|
729
|
+
def is_zero_time(duration: Duration, /) -> bool:
|
683
730
|
"""Check if a timedelta is 0."""
|
684
|
-
return
|
731
|
+
return datetime_duration_to_timedelta(duration) == ZERO_TIME
|
685
732
|
|
686
733
|
|
687
734
|
##
|
@@ -763,7 +810,7 @@ def mean_timedelta(
|
|
763
810
|
case 1:
|
764
811
|
return one(timedeltas)
|
765
812
|
case _:
|
766
|
-
microseconds = list(map(
|
813
|
+
microseconds = list(map(datetime_duration_to_microseconds, timedeltas))
|
767
814
|
mean_float = fmean(microseconds, weights=weights)
|
768
815
|
mean_int = round_(mean_float, mode=mode, rel_tol=rel_tol, abs_tol=abs_tol)
|
769
816
|
return microseconds_to_timedelta(mean_int)
|
@@ -781,7 +828,7 @@ class MeanTimeDeltaError(Exception):
|
|
781
828
|
|
782
829
|
def microseconds_since_epoch(datetime: dt.datetime, /) -> int:
|
783
830
|
"""Compute the number of microseconds since the epoch."""
|
784
|
-
return
|
831
|
+
return datetime_duration_to_microseconds(timedelta_since_epoch(datetime))
|
785
832
|
|
786
833
|
|
787
834
|
def microseconds_to_timedelta(microseconds: int, /) -> dt.timedelta:
|
@@ -980,7 +1027,7 @@ class _ParseTwoDigitYearInvalidStringError(Exception):
|
|
980
1027
|
|
981
1028
|
def round_datetime(
|
982
1029
|
datetime: dt.datetime,
|
983
|
-
|
1030
|
+
duration: Duration,
|
984
1031
|
/,
|
985
1032
|
*,
|
986
1033
|
mode: RoundMode = "standard",
|
@@ -990,7 +1037,7 @@ def round_datetime(
|
|
990
1037
|
"""Round a datetime to a timedelta."""
|
991
1038
|
if datetime.tzinfo is None:
|
992
1039
|
dividend = microseconds_since_epoch(datetime)
|
993
|
-
divisor =
|
1040
|
+
divisor = datetime_duration_to_microseconds(duration)
|
994
1041
|
quotient, remainder = divmod(dividend, divisor)
|
995
1042
|
rnd_remainder = round_(
|
996
1043
|
remainder / divisor, mode=mode, rel_tol=rel_tol, abs_tol=abs_tol
|
@@ -1000,7 +1047,7 @@ def round_datetime(
|
|
1000
1047
|
return microseconds_since_epoch_to_datetime(microseconds)
|
1001
1048
|
local = datetime.replace(tzinfo=None)
|
1002
1049
|
rounded = round_datetime(
|
1003
|
-
local,
|
1050
|
+
local, duration, mode=mode, rel_tol=rel_tol, abs_tol=abs_tol
|
1004
1051
|
)
|
1005
1052
|
return rounded.replace(tzinfo=datetime.tzinfo)
|
1006
1053
|
|
@@ -1175,50 +1222,6 @@ def timedelta_since_epoch(date_or_datetime: DateOrDateTime, /) -> dt.timedelta:
|
|
1175
1222
|
assert_never(never)
|
1176
1223
|
|
1177
1224
|
|
1178
|
-
def timedelta_to_microseconds(timedelta: dt.timedelta, /) -> int:
|
1179
|
-
"""Compute the number of microseconds in a timedelta."""
|
1180
|
-
return (
|
1181
|
-
_MICROSECONDS_PER_DAY * timedelta.days
|
1182
|
-
+ _MICROSECONDS_PER_SECOND * timedelta.seconds
|
1183
|
-
+ timedelta.microseconds
|
1184
|
-
)
|
1185
|
-
|
1186
|
-
|
1187
|
-
@overload
|
1188
|
-
def timedelta_to_milliseconds(
|
1189
|
-
timedelta: dt.timedelta, /, *, strict: Literal[True]
|
1190
|
-
) -> int: ...
|
1191
|
-
@overload
|
1192
|
-
def timedelta_to_milliseconds(
|
1193
|
-
timedelta: dt.timedelta, /, *, strict: bool = False
|
1194
|
-
) -> float: ...
|
1195
|
-
def timedelta_to_milliseconds(
|
1196
|
-
timedelta: dt.timedelta, /, *, strict: bool = False
|
1197
|
-
) -> int | float:
|
1198
|
-
"""Compute the number of milliseconds in a timedelta."""
|
1199
|
-
microseconds = timedelta_to_microseconds(timedelta)
|
1200
|
-
milliseconds, remainder = divmod(microseconds, _MICROSECONDS_PER_MILLISECOND)
|
1201
|
-
match remainder, strict:
|
1202
|
-
case 0, _:
|
1203
|
-
return milliseconds
|
1204
|
-
case _, True:
|
1205
|
-
raise TimedeltaToMillisecondsError(timedelta=timedelta, remainder=remainder)
|
1206
|
-
case _, False:
|
1207
|
-
return milliseconds + remainder / _MICROSECONDS_PER_MILLISECOND
|
1208
|
-
case _ as never:
|
1209
|
-
assert_never(never)
|
1210
|
-
|
1211
|
-
|
1212
|
-
@dataclass(kw_only=True, slots=True)
|
1213
|
-
class TimedeltaToMillisecondsError(Exception):
|
1214
|
-
timedelta: dt.timedelta
|
1215
|
-
remainder: int
|
1216
|
-
|
1217
|
-
@override
|
1218
|
-
def __str__(self) -> str:
|
1219
|
-
return f"Unable to convert {self.timedelta} to milliseconds; got {self.remainder} microsecond(s)"
|
1220
|
-
|
1221
|
-
|
1222
1225
|
##
|
1223
1226
|
|
1224
1227
|
|
@@ -1367,6 +1370,8 @@ __all__ = [
|
|
1367
1370
|
"date_to_datetime",
|
1368
1371
|
"date_to_month",
|
1369
1372
|
"datetime_duration_to_float",
|
1373
|
+
"datetime_duration_to_microseconds",
|
1374
|
+
"datetime_duration_to_milliseconds",
|
1370
1375
|
"datetime_duration_to_timedelta",
|
1371
1376
|
"datetime_utc",
|
1372
1377
|
"days_since_epoch",
|
@@ -1407,8 +1412,6 @@ __all__ = [
|
|
1407
1412
|
"serialize_month",
|
1408
1413
|
"sub_duration",
|
1409
1414
|
"timedelta_since_epoch",
|
1410
|
-
"timedelta_to_microseconds",
|
1411
|
-
"timedelta_to_milliseconds",
|
1412
1415
|
"yield_days",
|
1413
1416
|
"yield_weekdays",
|
1414
1417
|
]
|
utilities/whenever.py
CHANGED
@@ -14,8 +14,8 @@ from utilities.datetime import (
|
|
14
14
|
_MICROSECONDS_PER_SECOND,
|
15
15
|
ZERO_TIME,
|
16
16
|
check_date_not_datetime,
|
17
|
+
datetime_duration_to_microseconds,
|
17
18
|
parse_two_digit_year,
|
18
|
-
timedelta_to_microseconds,
|
19
19
|
)
|
20
20
|
from utilities.math import ParseNumberError, parse_number
|
21
21
|
from utilities.re import (
|
@@ -601,7 +601,7 @@ class SerializeZonedDateTimeError(Exception):
|
|
601
601
|
|
602
602
|
def _to_datetime_delta(timedelta: dt.timedelta, /) -> DateTimeDelta:
|
603
603
|
"""Serialize a timedelta."""
|
604
|
-
total_microseconds =
|
604
|
+
total_microseconds = datetime_duration_to_microseconds(timedelta)
|
605
605
|
if total_microseconds == 0:
|
606
606
|
return DateTimeDelta()
|
607
607
|
if total_microseconds >= 1:
|
File without changes
|
File without changes
|