dycw-utilities 0.131.6__py3-none-any.whl → 0.131.8__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.131.6
3
+ Version: 0.131.8
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=IYqBm-WAwWhDKdOqlSq4UGAvQ_vBiK8qzv2Mq0YUuRo,60
1
+ utilities/__init__.py,sha256=7GFnOq-ksc-RNtwI9lMII4eofdNt78J6EbkJmHRGm6E,60
2
2
  utilities/aiolimiter.py,sha256=mD0wEiqMgwpty4XTbawFpnkkmJS6R4JRsVXFUaoitSU,628
3
3
  utilities/altair.py,sha256=HeZBVUocjkrTNwwKrClppsIqgNFF-ykv05HfZSoHYno,9104
4
- utilities/asyncio.py,sha256=lvdgBhuMtxq0dpiwF9g2WMMrit3kqXibN1V5NZ4xdbo,38046
4
+ utilities/asyncio.py,sha256=yfKvAIDCRrWdyQMVZMo4DJQx4nVrXoAcqwhNuF95Ryo,38186
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
@@ -24,7 +24,7 @@ utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
24
24
  utilities/git.py,sha256=oi7-_l5e9haSANSCvQw25ufYGoNahuUPHAZ6114s3JQ,1191
25
25
  utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
26
26
  utilities/http.py,sha256=WcahTcKYRtZ04WXQoWt5EGCgFPcyHD3EJdlMfxvDt-0,946
27
- utilities/hypothesis.py,sha256=kTxXlZJyBauO3jurT7nIFWXhhmlamUvsNf65OQFEpEc,48084
27
+ utilities/hypothesis.py,sha256=-m9YWVgDkKdBfPkZHJ4-vCOGORVHqgtDhbXllfPrr7o,49873
28
28
  utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
29
29
  utilities/inflect.py,sha256=DbqB5Q9FbRGJ1NbvEiZBirRMxCxgrz91zy5jCO9ZIs0,347
30
30
  utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
@@ -78,7 +78,7 @@ utilities/tempfile.py,sha256=VqmZJAhTJ1OaVywFzk5eqROV8iJbW9XQ_QYAV0bpdRo,1384
78
78
  utilities/tenacity.py,sha256=1PUvODiBVgeqIh7G5TRt5WWMSqjLYkEqP53itT97WQc,4914
79
79
  utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
80
80
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
81
- utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
81
+ utilities/timer.py,sha256=VeSl3ot8-f4D1d3HjjSsgKvjxHJGXd_sW4KcTExOR64,2475
82
82
  utilities/traceback.py,sha256=l9onlqDdW5GCSIFbU_-htBE7KlsvsJdNtGrK6-k0RCQ,8759
83
83
  utilities/types.py,sha256=gP04CcCOyFrG7BgblVCsrrChiuO2x842NDVW-GF7odo,18370
84
84
  utilities/typing.py,sha256=kQWywPcRbFBKmvQBELmgbiqSHsnlo_D0ru53vl6KDeY,13846
@@ -88,10 +88,10 @@ utilities/uuid.py,sha256=jJTFxz-CWgltqNuzmythB7iEQ-Q1mCwPevUfKthZT3c,611
88
88
  utilities/version.py,sha256=ufhJMmI6KPs1-3wBI71aj5wCukd3sP_m11usLe88DNA,5117
89
89
  utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
90
90
  utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
91
- utilities/whenever2.py,sha256=XxiAEp4onJNhIi6G7L2HuzkMJZGA3j-I_fuXxmb5vtY,5432
91
+ utilities/whenever2.py,sha256=JHixGl6KibK8GUF13GeBjvWMYsFHRDSXixSo0xMSJFM,5437
92
92
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
93
93
  utilities/zoneinfo.py,sha256=tvcgu3QzDxe2suTexi2QzRGpin7VK1TjHa0JYYxT69I,1862
94
- dycw_utilities-0.131.6.dist-info/METADATA,sha256=zhPwLa5dVaZ2tcdTMMoh-HOc348fcu3Q5_pgsCsb40A,1584
95
- dycw_utilities-0.131.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
- dycw_utilities-0.131.6.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
97
- dycw_utilities-0.131.6.dist-info/RECORD,,
94
+ dycw_utilities-0.131.8.dist-info/METADATA,sha256=R5VRnHIlEDPgRLMdPF6PWrQ7VwJmzeWBUNpSVIrPTqA,1584
95
+ dycw_utilities-0.131.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
+ dycw_utilities-0.131.8.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
97
+ dycw_utilities-0.131.8.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.131.6"
3
+ __version__ = "0.131.8"
utilities/asyncio.py CHANGED
@@ -43,6 +43,7 @@ from typing import (
43
43
  )
44
44
 
45
45
  from typing_extensions import deprecated
46
+ from whenever import TimeDelta
46
47
 
47
48
  from utilities.dataclasses import replace_non_sentinel
48
49
  from utilities.datetime import (
@@ -961,11 +962,14 @@ def put_items_nowait(items: Iterable[_T], queue: Queue[_T], /) -> None:
961
962
  ##
962
963
 
963
964
 
964
- async def sleep_dur(*, duration: Duration | None = None) -> None:
965
+ async def sleep_dur(*, duration: Duration | TimeDelta | None = None) -> None:
965
966
  """Sleep which accepts durations."""
966
967
  if duration is None:
967
968
  return
968
- await sleep(datetime_duration_to_float(duration))
969
+ if isinstance(duration, TimeDelta):
970
+ await sleep(duration.in_seconds())
971
+ else:
972
+ await sleep(datetime_duration_to_float(duration))
969
973
 
970
974
 
971
975
  ##
utilities/hypothesis.py CHANGED
@@ -24,6 +24,7 @@ from typing import (
24
24
  override,
25
25
  )
26
26
 
27
+ import hypothesis.strategies
27
28
  from hypothesis import HealthCheck, Phase, Verbosity, assume, settings
28
29
  from hypothesis.errors import InvalidArgument
29
30
  from hypothesis.strategies import (
@@ -47,7 +48,7 @@ from hypothesis.strategies import (
47
48
  uuids,
48
49
  )
49
50
  from hypothesis.utils.conventions import not_set
50
- from whenever import Date, DateDelta
51
+ from whenever import Date, DateDelta, PlainDateTime, Time, TimeDelta
51
52
 
52
53
  from utilities.datetime import (
53
54
  DATETIME_MAX_NAIVE,
@@ -89,6 +90,20 @@ from utilities.platform import IS_WINDOWS
89
90
  from utilities.sentinel import Sentinel, sentinel
90
91
  from utilities.tempfile import TEMP_DIR, TemporaryDirectory
91
92
  from utilities.version import Version
93
+ from utilities.whenever2 import (
94
+ DATE_DELTA_MAX,
95
+ DATE_DELTA_MIN,
96
+ DATE_DELTA_PARSABLE_MAX,
97
+ DATE_DELTA_PARSABLE_MIN,
98
+ DATE_MAX,
99
+ DATE_MIN,
100
+ PLAIN_DATE_TIME_MAX,
101
+ PLAIN_DATE_TIME_MIN,
102
+ TIME_DELTA_MAX,
103
+ TIME_DELTA_MIN,
104
+ TIME_MAX,
105
+ TIME_MIN,
106
+ )
92
107
  from utilities.zoneinfo import UTC, ensure_time_zone
93
108
 
94
109
  if TYPE_CHECKING:
@@ -97,7 +112,7 @@ if TYPE_CHECKING:
97
112
 
98
113
  from hypothesis.database import ExampleDatabase
99
114
  from numpy.random import RandomState
100
- from whenever import PlainDateTime, ZonedDateTime
115
+ from whenever import ZonedDateTime
101
116
 
102
117
  from utilities.numpy import NDArrayB, NDArrayF, NDArrayI, NDArrayO
103
118
  from utilities.types import Duration, Number, RoundMode, TimeZoneLike
@@ -170,13 +185,6 @@ def date_deltas_whenever(
170
185
  parsable: MaybeSearchStrategy[bool] = False,
171
186
  ) -> DateDelta:
172
187
  """Strategy for generating date deltas."""
173
- from utilities.whenever2 import (
174
- DATE_DELTA_MAX,
175
- DATE_DELTA_MIN,
176
- DATE_DELTA_PARSABLE_MAX,
177
- DATE_DELTA_PARSABLE_MIN,
178
- )
179
-
180
188
  min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
181
189
  match min_value_:
182
190
  case None:
@@ -307,8 +315,6 @@ def dates_whenever(
307
315
  max_value: MaybeSearchStrategy[Date | None] = None,
308
316
  ) -> Date:
309
317
  """Strategy for generating dates."""
310
- from utilities.whenever2 import DATE_MAX, DATE_MIN
311
-
312
318
  min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
313
319
  match min_value_:
314
320
  case None:
@@ -1069,10 +1075,6 @@ def plain_datetimes_whenever(
1069
1075
  max_value: MaybeSearchStrategy[PlainDateTime | None] = None,
1070
1076
  ) -> PlainDateTime:
1071
1077
  """Strategy for generating plain datetimes."""
1072
- from whenever import PlainDateTime
1073
-
1074
- from utilities.whenever2 import PLAIN_DATE_TIME_MAX, PLAIN_DATE_TIME_MIN
1075
-
1076
1078
  min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
1077
1079
  match min_value_:
1078
1080
  case None:
@@ -1405,6 +1407,41 @@ def text_printable(
1405
1407
  ##
1406
1408
 
1407
1409
 
1410
+ @composite
1411
+ def time_deltas_whenever(
1412
+ draw: DrawFn,
1413
+ /,
1414
+ *,
1415
+ min_value: MaybeSearchStrategy[TimeDelta | None] = None,
1416
+ max_value: MaybeSearchStrategy[TimeDelta | None] = None,
1417
+ ) -> TimeDelta:
1418
+ """Strategy for generating time deltas."""
1419
+ min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
1420
+ match min_value_:
1421
+ case None:
1422
+ min_value_ = TIME_DELTA_MIN
1423
+ case TimeDelta():
1424
+ ...
1425
+ case _ as never:
1426
+ assert_never(never)
1427
+ match max_value_:
1428
+ case None:
1429
+ max_value_ = TIME_DELTA_MAX
1430
+ case TimeDelta():
1431
+ ...
1432
+ case _ as never:
1433
+ assert_never(never)
1434
+ py_time = draw(
1435
+ hypothesis.strategies.timedeltas(
1436
+ min_value=min_value_.py_timedelta(), max_value=max_value_.py_timedelta()
1437
+ )
1438
+ )
1439
+ return TimeDelta.from_py_timedelta(py_time)
1440
+
1441
+
1442
+ ##
1443
+
1444
+
1408
1445
  @composite
1409
1446
  def timedeltas_2w(
1410
1447
  draw: DrawFn,
@@ -1431,6 +1468,41 @@ def timedeltas_2w(
1431
1468
  ##
1432
1469
 
1433
1470
 
1471
+ @composite
1472
+ def times_whenever(
1473
+ draw: DrawFn,
1474
+ /,
1475
+ *,
1476
+ min_value: MaybeSearchStrategy[Time | None] = None,
1477
+ max_value: MaybeSearchStrategy[Time | None] = None,
1478
+ ) -> Time:
1479
+ """Strategy for generating times."""
1480
+ min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
1481
+ match min_value_:
1482
+ case None:
1483
+ min_value_ = TIME_MIN
1484
+ case Time():
1485
+ ...
1486
+ case _ as never:
1487
+ assert_never(never)
1488
+ match max_value_:
1489
+ case None:
1490
+ max_value_ = TIME_MAX
1491
+ case Time():
1492
+ ...
1493
+ case _ as never:
1494
+ assert_never(never)
1495
+ py_time = draw(
1496
+ hypothesis.strategies.times(
1497
+ min_value=min_value_.py_time(), max_value=max_value_.py_time()
1498
+ )
1499
+ )
1500
+ return Time.from_py_time(py_time)
1501
+
1502
+
1503
+ ##
1504
+
1505
+
1434
1506
  def triples(
1435
1507
  strategy: SearchStrategy[_T],
1436
1508
  /,
@@ -1651,7 +1723,9 @@ __all__ = [
1651
1723
  "text_clean",
1652
1724
  "text_digits",
1653
1725
  "text_printable",
1726
+ "time_deltas_whenever",
1654
1727
  "timedeltas_2w",
1728
+ "times_whenever",
1655
1729
  "triples",
1656
1730
  "uint32s",
1657
1731
  "uint64s",
utilities/timer.py CHANGED
@@ -1,14 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
- import datetime as dt
4
3
  from operator import add, eq, ge, gt, le, lt, mul, ne, sub, truediv
5
- from timeit import default_timer
6
- from typing import TYPE_CHECKING, Any, Self, overload, override
4
+ from typing import TYPE_CHECKING, Any, Self, override
5
+
6
+ from utilities.whenever2 import get_now_local
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from collections.abc import Callable
10
10
 
11
- from utilities.types import Number
11
+ from whenever import TimeDelta, ZonedDateTime
12
12
 
13
13
 
14
14
  class Timer:
@@ -16,116 +16,82 @@ class Timer:
16
16
 
17
17
  def __init__(self) -> None:
18
18
  super().__init__()
19
- self._start = default_timer()
20
- self._end: float | None = None
19
+ self._start: ZonedDateTime = get_now_local()
20
+ self._end: ZonedDateTime | None = None
21
21
 
22
22
  # arithmetic
23
23
 
24
- def __add__(self, other: Any) -> dt.timedelta:
25
- if isinstance(other, int | float):
26
- return dt.timedelta(seconds=self._apply_op(add, other))
27
- if isinstance(other, dt.timedelta | Timer):
28
- return self._apply_op(add, other)
29
- return NotImplemented
24
+ def __add__(self, other: Any) -> TimeDelta:
25
+ return self._apply_op(add, other)
30
26
 
31
27
  def __float__(self) -> float:
32
- end_use = default_timer() if (end := self._end) is None else end
33
- return end_use - self._start
28
+ return self.timedelta.in_seconds()
29
+
30
+ def __sub__(self, other: Any) -> TimeDelta:
31
+ return self._apply_op(sub, other)
34
32
 
35
- def __sub__(self, other: Any) -> dt.timedelta:
36
- if isinstance(other, int | float):
37
- return dt.timedelta(seconds=self._apply_op(sub, other))
38
- if isinstance(other, dt.timedelta | Timer):
39
- return self._apply_op(sub, other)
40
- return NotImplemented
41
-
42
- def __mul__(self, other: Any) -> dt.timedelta:
43
- if isinstance(other, int | float):
44
- return dt.timedelta(seconds=self._apply_op(mul, other))
45
- return NotImplemented
46
-
47
- @overload
48
- def __truediv__(self, other: Number) -> dt.timedelta: ...
49
- @overload
50
- def __truediv__(self, other: dt.timedelta | Timer) -> float: ...
51
- def __truediv__(self, other: Any) -> dt.timedelta | float:
52
- if isinstance(other, int | float):
53
- return dt.timedelta(seconds=self._apply_op(truediv, other))
54
- if isinstance(other, dt.timedelta | Timer):
55
- return self._apply_op(truediv, other)
56
- return NotImplemented
33
+ def __mul__(self, other: Any) -> TimeDelta:
34
+ return self._apply_op(mul, other)
35
+
36
+ def __truediv__(self, other: Any) -> TimeDelta:
37
+ return self._apply_op(truediv, other)
57
38
 
58
39
  # context manager
59
40
 
60
41
  def __enter__(self) -> Self:
61
- self._start = default_timer()
42
+ self._start = get_now_local()
62
43
  return self
63
44
 
64
45
  def __exit__(self, *_: object) -> bool:
65
- self._end = default_timer()
46
+ self._end = get_now_local()
66
47
  return False
67
48
 
68
49
  # repr
69
50
 
70
51
  @override
71
52
  def __repr__(self) -> str:
72
- return str(self.timedelta)
53
+ return self.timedelta.format_common_iso()
73
54
 
74
55
  @override
75
56
  def __str__(self) -> str:
76
- return str(self.timedelta)
57
+ return self.timedelta.format_common_iso()
77
58
 
78
59
  # comparison
79
60
 
80
61
  @override
81
62
  def __eq__(self, other: object) -> bool:
82
- if isinstance(other, int | float | dt.timedelta | Timer):
83
- return self._apply_op(eq, other)
84
- return False
63
+ return self._apply_op(eq, other)
85
64
 
86
65
  def __ge__(self, other: Any) -> bool:
87
- if isinstance(other, int | float | dt.timedelta | Timer):
88
- return self._apply_op(ge, other)
89
- return NotImplemented
66
+ return self._apply_op(ge, other)
90
67
 
91
68
  def __gt__(self, other: Any) -> bool:
92
- if isinstance(other, int | float | dt.timedelta | Timer):
93
- return self._apply_op(gt, other)
94
- return NotImplemented
69
+ return self._apply_op(gt, other)
95
70
 
96
71
  def __le__(self, other: Any) -> bool:
97
- if isinstance(other, int | float | dt.timedelta | Timer):
98
- return self._apply_op(le, other)
99
- return NotImplemented
72
+ return self._apply_op(le, other)
100
73
 
101
74
  def __lt__(self, other: Any) -> bool:
102
- if isinstance(other, int | float | dt.timedelta | Timer):
103
- return self._apply_op(lt, other)
104
- return NotImplemented
75
+ return self._apply_op(lt, other)
105
76
 
106
77
  @override
107
78
  def __ne__(self, other: object) -> bool:
108
- if isinstance(other, int | float | dt.timedelta | Timer):
109
- return self._apply_op(ne, other)
110
- return True
79
+ return self._apply_op(ne, other)
111
80
 
112
81
  # properties
113
82
 
114
83
  @property
115
- def timedelta(self) -> dt.timedelta:
84
+ def timedelta(self) -> TimeDelta:
116
85
  """The elapsed time, as a `timedelta` object."""
117
- return dt.timedelta(seconds=float(self))
86
+ end_use = get_now_local() if (end := self._end) is None else end
87
+ return end_use - self._start
118
88
 
119
89
  # private
120
90
 
121
91
  def _apply_op(self, op: Callable[[Any, Any], Any], other: Any, /) -> Any:
122
- if isinstance(other, int | float):
123
- return op(float(self), other)
124
92
  if isinstance(other, Timer):
125
93
  return op(self.timedelta, other.timedelta)
126
- if isinstance(other, dt.timedelta):
127
- return op(self.timedelta, other)
128
- return NotImplemented # pragma: no cover
94
+ return op(self.timedelta, other)
129
95
 
130
96
 
131
97
  __all__ = ["Timer"]
utilities/whenever2.py CHANGED
@@ -53,7 +53,7 @@ DATE_DELTA_PARSABLE_MAX = DateDelta(days=999999)
53
53
  ## common constants
54
54
 
55
55
 
56
- ZERO_TIME = Time()
56
+ ZERO_TIME = TimeDelta()
57
57
  MICROSECOND = TimeDelta(microseconds=1)
58
58
  MILLISECOND = TimeDelta(milliseconds=1)
59
59
  SECOND = TimeDelta(seconds=1)