dycw-utilities 0.150.9__py3-none-any.whl → 0.150.11__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.150.9
3
+ Version: 0.150.11
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -12,7 +12,7 @@ Provides-Extra: logging
12
12
  Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'logging'
13
13
  Provides-Extra: test
14
14
  Requires-Dist: dycw-pytest-only<2.2,>=2.1.1; extra == 'test'
15
- Requires-Dist: hypothesis<6.137,>=6.136.0; extra == 'test'
15
+ Requires-Dist: hypothesis<6.137,>=6.136.1; extra == 'test'
16
16
  Requires-Dist: pudb<2025.2,>=2025.1; extra == 'test'
17
17
  Requires-Dist: pytest-asyncio<1.2,>=1.1.0; extra == 'test'
18
18
  Requires-Dist: pytest-cov<6.3,>=6.2.1; extra == 'test'
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=GsG3Q0h41dPHASCsd70D14gPFgnAp7k4Bz18oGu00SI,60
1
+ utilities/__init__.py,sha256=-W11lQr4jP-tn91Yfbt2z87iYMIXPcyPiNogVGYlrG0,61
2
2
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
3
3
  utilities/asyncio.py,sha256=2m2a2C-Qgc6OHTTHL332-t66A7xDITt_SORT7a1DJWo,16792
4
4
  utilities/atomicwrites.py,sha256=xcOWenTBRS0oat3kg7Sqe51AohNThMQ2ixPL7QCG8hw,5795
@@ -44,7 +44,7 @@ utilities/orjson.py,sha256=iJho5gCkTlT2KWSXqopvi24WCxEhM5_fiz17mbNvkGg,40113
44
44
  utilities/os.py,sha256=y25oqJoyrkdQ7aU5ShePPXKk6YTwd97x6yEx4UcRYu4,3788
45
45
  utilities/parse.py,sha256=JcJn5yXKhIWXBCwgBdPsyu7Hvcuw6kyEdqvaebCaI9k,17951
46
46
  utilities/pathlib.py,sha256=FnteXeVeMOSc6QTN7oF6UrobjOX9gXv_5tG1slg83W8,8496
47
- utilities/period.py,sha256=REuz2xaChNa5Iw69xNnbUPlUSLdUgmhOu4YEOiPeTrg,8328
47
+ utilities/period.py,sha256=hsHdAKAstfMzB2Ar5EbxjkbMff3CA-B5wtYNVZOXVXI,10127
48
48
  utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
49
49
  utilities/platform.py,sha256=Ue9LSxYvg9yUXGKuz5aZoy_qkUEXde-v6B09exgSctU,2813
50
50
  utilities/polars.py,sha256=BgiDryAVOapi41ddfJqN0wYh_sDj8BNEYtPB36LaHdo,71824
@@ -71,7 +71,7 @@ utilities/sqlalchemy_polars.py,sha256=18AoEbeNJUKF3-5hroNy9J5LQwS_QJAXbMfKc9sCht
71
71
  utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
72
72
  utilities/string.py,sha256=MB0X6UPTUc06JdAdj-PctZ238IXeCjE5dAJibNw6ZrU,587
73
73
  utilities/tempfile.py,sha256=HxB2BF28CcecDJLQ3Bx2Ej-Pb6RJc6W9ngSpB9CnP4k,2018
74
- utilities/text.py,sha256=bupgC6ILTjmcJKSUGloStzmWuj2Ke0knvVKE2mWLwAM,11619
74
+ utilities/text.py,sha256=4EOtSnfU0z09WANxjVO8Td54VNNe1sS4dWCa7VUo4HI,11794
75
75
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
76
76
  utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
77
77
  utilities/traceback.py,sha256=zofhzIedpUHrzDNiRJDVzm_wuu_tlTQvVqK4quxVlgM,9151
@@ -89,8 +89,8 @@ utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
89
89
  utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
90
90
  utilities/pytest_plugins/pytest_randomly.py,sha256=NXzCcGKbpgYouz5yehKb4jmxmi2SexKKpgF4M65bi10,414
91
91
  utilities/pytest_plugins/pytest_regressions.py,sha256=Iwhfv_OJH7UCPZCfoh7ugZ2Xjqjil-BBBsOb8sDwiGI,1471
92
- dycw_utilities-0.150.9.dist-info/METADATA,sha256=h1ki8nwAV6ET-w-Z9jFMsFrXnEezGVzts3XVeQ9kJps,1696
93
- dycw_utilities-0.150.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- dycw_utilities-0.150.9.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
95
- dycw_utilities-0.150.9.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
96
- dycw_utilities-0.150.9.dist-info/RECORD,,
92
+ dycw_utilities-0.150.11.dist-info/METADATA,sha256=i9tIQJnes-TSj9Z8tHap_MgTtlzmZuXvVAPcoG_JY-Q,1697
93
+ dycw_utilities-0.150.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ dycw_utilities-0.150.11.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
95
+ dycw_utilities-0.150.11.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
96
+ dycw_utilities-0.150.11.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.150.9"
3
+ __version__ = "0.150.11"
utilities/period.py CHANGED
@@ -1,22 +1,22 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Self, TypedDict, overload, override
4
+ from typing import TYPE_CHECKING, Any, Self, TypedDict, assert_never, overload, override
5
5
  from zoneinfo import ZoneInfo
6
6
 
7
- from whenever import Date, DateDelta, PlainDateTime, TimeDelta, ZonedDateTime
7
+ from whenever import Date, DateDelta, PlainDateTime, Time, TimeDelta, ZonedDateTime
8
8
 
9
9
  from utilities.dataclasses import replace_non_sentinel
10
10
  from utilities.functions import get_class_name
11
11
  from utilities.sentinel import Sentinel, sentinel
12
12
  from utilities.whenever import format_compact
13
- from utilities.zoneinfo import get_time_zone_name
13
+ from utilities.zoneinfo import UTC, ensure_time_zone, get_time_zone_name
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from utilities.types import TimeZoneLike
17
17
 
18
18
 
19
- class _PeriodAsDict[T: (Date, ZonedDateTime)](TypedDict):
19
+ class _PeriodAsDict[T: (Date, Time, ZonedDateTime)](TypedDict):
20
20
  start: T
21
21
  end: T
22
22
 
@@ -49,6 +49,22 @@ class DatePeriod:
49
49
  """Offset the period."""
50
50
  return self.replace(start=self.start - other, end=self.end - other)
51
51
 
52
+ def at(
53
+ self, obj: Time | tuple[Time, Time], /, *, time_zone: TimeZoneLike = UTC
54
+ ) -> ZonedDateTimePeriod:
55
+ """Combine a date with a time to create a datetime."""
56
+ match obj:
57
+ case Time() as time:
58
+ start = end = time
59
+ case Time() as start, Time() as end:
60
+ ...
61
+ case _ as never:
62
+ assert_never(never)
63
+ tz = ensure_time_zone(time_zone).key
64
+ return ZonedDateTimePeriod(
65
+ self.start.at(start).assume_tz(tz), self.end.at(end).assume_tz(tz)
66
+ )
67
+
52
68
  @property
53
69
  def delta(self) -> DateDelta:
54
70
  """The delta of the period."""
@@ -76,6 +92,42 @@ class DatePeriod:
76
92
  return _PeriodAsDict(start=self.start, end=self.end)
77
93
 
78
94
 
95
+ @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
96
+ class TimePeriod:
97
+ """A period of times."""
98
+
99
+ start: Time
100
+ end: Time
101
+
102
+ @override
103
+ def __repr__(self) -> str:
104
+ cls = get_class_name(self)
105
+ return f"{cls}({self.start}, {self.end})"
106
+
107
+ def replace(
108
+ self, *, start: Time | Sentinel = sentinel, end: Time | Sentinel = sentinel
109
+ ) -> Self:
110
+ """Replace elements of the period."""
111
+ return replace_non_sentinel(self, start=start, end=end)
112
+
113
+ def at(
114
+ self, obj: Date | tuple[Date, Date], /, *, time_zone: TimeZoneLike = UTC
115
+ ) -> ZonedDateTimePeriod:
116
+ """Combine a date with a time to create a datetime."""
117
+ match obj:
118
+ case Date() as date:
119
+ start = end = date
120
+ case Date() as start, Date() as end:
121
+ ...
122
+ case _ as never:
123
+ assert_never(never)
124
+ return DatePeriod(start, end).at((self.start, self.end), time_zone=time_zone)
125
+
126
+ def to_dict(self) -> _PeriodAsDict[Time]:
127
+ """Convert the period to a dictionary."""
128
+ return _PeriodAsDict(start=self.start, end=self.end)
129
+
130
+
79
131
  @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
80
132
  class ZonedDateTimePeriod:
81
133
  """A period of time."""
@@ -234,4 +286,4 @@ class _PeriodExactEqArgumentsError(PeriodError):
234
286
  return f"Invalid arguments; got {self.args}"
235
287
 
236
288
 
237
- __all__ = ["DatePeriod", "PeriodError", "ZonedDateTimePeriod"]
289
+ __all__ = ["DatePeriod", "PeriodError", "TimePeriod", "ZonedDateTimePeriod"]
utilities/text.py CHANGED
@@ -388,9 +388,13 @@ def _escape_separator(*, separator: str = DEFAULT_SEPARATOR) -> str:
388
388
  class secret_str(str): # noqa: N801
389
389
  """A string with an obfuscated representation."""
390
390
 
391
- __slots__ = ()
391
+ __slots__ = ("_text",)
392
392
  _REPR: ClassVar[str] = "***"
393
393
 
394
+ def __init__(self, text: str, /) -> None:
395
+ super().__init__()
396
+ self._text = text
397
+
394
398
  @override
395
399
  def __repr__(self) -> str:
396
400
  return self._REPR
@@ -399,6 +403,10 @@ class secret_str(str): # noqa: N801
399
403
  def __str__(self) -> str:
400
404
  return self._REPR
401
405
 
406
+ @property
407
+ def str(self) -> str:
408
+ return self._text
409
+
402
410
 
403
411
  ##
404
412