dycw-utilities 0.151.8__py3-none-any.whl → 0.151.10__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.151.8
3
+ Version: 0.151.10
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,6 +1,6 @@
1
- utilities/__init__.py,sha256=4kiNe54mu65BdlIWO3fy88xeEWBui4WvuRPhgdV-gOA,60
1
+ utilities/__init__.py,sha256=ohf_5FPJbFDOjflrHr5JwHamf7937DDMR15Y5Jsb2-U,61
2
2
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
3
- utilities/asyncio.py,sha256=2m2a2C-Qgc6OHTTHL332-t66A7xDITt_SORT7a1DJWo,16792
3
+ utilities/asyncio.py,sha256=r75HVwm6QoCOz7bEe3_KO47G4_IIhNCYcPDrJTi4i_4,16777
4
4
  utilities/atomicwrites.py,sha256=tPo6r-Rypd9u99u66B9z86YBPpnLrlHtwox_8Z7T34Y,5790
5
5
  utilities/atools.py,sha256=6neeCcgXxK2dlsc0xp15Za7nSucbCgFtAJepGI_-WXU,2549
6
6
  utilities/cachetools.py,sha256=v1-9sXHLdOLiwmkq6NB0OUbxeKBuVVN6wmAWefWoaHI,2744
@@ -23,7 +23,7 @@ utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
23
23
  utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
24
24
  utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
25
25
  utilities/http.py,sha256=TsavEfHlRtlLaeV21Z6KZh0qbPw-kvD1zsQdZ7Kep5Q,977
26
- utilities/hypothesis.py,sha256=muEtgWd8ZR7z4Iv-demKK3dBJY6dC26FYIzNcDd0ViE,40267
26
+ utilities/hypothesis.py,sha256=m44niSfuzuhgn7IQ1UOwUGgiu68xz4a6LHxB0IE6fNE,40341
27
27
  utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
28
28
  utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
29
29
  utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
@@ -32,7 +32,7 @@ utilities/json.py,sha256=-WcGtSsCr9Y42wHZzAMnfvU6ihAfVftylFfRUORaDFo,2102
32
32
  utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
33
33
  utilities/libcst.py,sha256=TKgKN4bNmtBNEE-TUfhTyd1BrTncfsl_7tTuhpesGYY,5585
34
34
  utilities/lightweight_charts.py,sha256=YM3ojBvJxuCSUBu_KrhFBmaMCvRPvupKC3qkm-UVZq4,2751
35
- utilities/logging.py,sha256=6Rv6Mt7peHWPZ-wYNUvXQt67QXCOpVXdnkgT88XKiKQ,19416
35
+ utilities/logging.py,sha256=TnbdmDAZ9DGEkSl7VBhlh5mu_6AbRtefoIHZuFC1_sA,19406
36
36
  utilities/math.py,sha256=7ve4RxX3g-FGGVnWV0K9bBeGnKUEjnTbH13VxdvFtGE,26847
37
37
  utilities/memory_profiler.py,sha256=XzN56jDCa5aqXS_DxEjb_K4L6aIWh_5zyKi6OhcIxw0,853
38
38
  utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
@@ -44,7 +44,7 @@ utilities/orjson.py,sha256=Gzxn-s55pGFKV8DdsYXpp-Gr3r-5KdacYUd_GHMBogM,40088
44
44
  utilities/os.py,sha256=mFvjydySvjtSXpk7tLStUJcndauAoujxUUmj_CO7LWY,3778
45
45
  utilities/parse.py,sha256=JcJn5yXKhIWXBCwgBdPsyu7Hvcuw6kyEdqvaebCaI9k,17951
46
46
  utilities/pathlib.py,sha256=77wT9naY2Nnrbar8nJiIYd2r3MfabMQM9VguuuivrdQ,8481
47
- utilities/period.py,sha256=LMN6gIo4QpkXpYnuXMItWzNqjkb6R47FHV1B-5Rndc0,10117
47
+ utilities/period.py,sha256=SpgccCm1vsM5ESHj26upVHRERxELzri8No9XU60H_H8,12201
48
48
  utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
49
49
  utilities/platform.py,sha256=pTn7gw6N4T6LdKrf0virwarof_mze9WtoQlrGMzhGVI,2798
50
50
  utilities/polars.py,sha256=x4x3i08ldcDyKVEa8rcyAyacHKjok30K2v79yhoIn2Y,73243
@@ -59,14 +59,14 @@ utilities/pytest.py,sha256=xR-xG5aTfU9U7Qcb8Lle8uhLP1V0zc8EqZFfU0F8zfg,7899
59
59
  utilities/pytest_regressions.py,sha256=ocjHTtfOeiGfQAKIei8pKNd61sxN9dawrJJ9gPt2wzA,4097
60
60
  utilities/random.py,sha256=YWYzWxQDeyJRiuHGnO1OxF6dDucpq7qc1tH_ealwCRg,4130
61
61
  utilities/re.py,sha256=S4h-DLL6ScMPqjboZ_uQ1BVTJajrqV06r_81D--_HCE,4573
62
- utilities/redis.py,sha256=SyC1TZdQBsQLe7nevX6x-y0CgEFulQ76H1fA_dFfuks,28419
62
+ utilities/redis.py,sha256=lNVQWHN5j1Sf8A8CoUxG6kU27ZDStrjw3JXqGscqD6I,28404
63
63
  utilities/reprlib.py,sha256=ssYTcBW-TeRh3fhCJv57sopTZHF5FrPyyUg9yp5XBlo,3953
64
64
  utilities/scipy.py,sha256=wZJM7fEgBAkLSYYvSmsg5ac-QuwAI0BGqHVetw1_Hb0,947
65
65
  utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
66
66
  utilities/shelve.py,sha256=4OzjQI6kGuUbJciqf535rwnao-_IBv66gsT6tRGiUt0,759
67
67
  utilities/slack_sdk.py,sha256=ppFBvKgfg5IRWiIoKPtpTyzBtBF4XmwEvU3I5wLJikM,2140
68
68
  utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
69
- utilities/sqlalchemy.py,sha256=QbCFKefrkkqL23iDF5WdOKRfISMj6c-SyrI3rvBATE4,39641
69
+ utilities/sqlalchemy.py,sha256=QCRqlFUH5Iz9jkiR0IUvb5btx_ijdbYX48rlXxQTVXA,39591
70
70
  utilities/sqlalchemy_polars.py,sha256=Mm-sShZfqqgnzTrupMQdCfSM2akrybXHXAErTs-ofM8,14244
71
71
  utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
72
72
  utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
@@ -89,8 +89,8 @@ utilities/zoneinfo.py,sha256=FBMcUQ4662Aq8SsuCL1OAhDQiyANmVjtb-C30DRrWoE,1966
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.151.8.dist-info/METADATA,sha256=_O8sp46Zj82B4X3XXMKjrRoSPcCxTj-uG_ulUBEaXKc,1696
93
- dycw_utilities-0.151.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- dycw_utilities-0.151.8.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
95
- dycw_utilities-0.151.8.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
96
- dycw_utilities-0.151.8.dist-info/RECORD,,
92
+ dycw_utilities-0.151.10.dist-info/METADATA,sha256=67Rkmup754-j6tJJPOspiNytoZEOdhzhva8-hnef3Mc,1697
93
+ dycw_utilities-0.151.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ dycw_utilities-0.151.10.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
95
+ dycw_utilities-0.151.10.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
96
+ dycw_utilities-0.151.10.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.151.8"
3
+ __version__ = "0.151.10"
utilities/asyncio.py CHANGED
@@ -275,7 +275,7 @@ class EnhancedTaskGroup(TaskGroup):
275
275
  _ = await super().__aexit__(et, exc, tb)
276
276
  case False:
277
277
  _ = await super().__aexit__(et, exc, tb)
278
- case _ as never:
278
+ case never:
279
279
  assert_never(never)
280
280
 
281
281
  @override
@@ -312,7 +312,7 @@ class EnhancedTaskGroup(TaskGroup):
312
312
  self.create_task(make_coro(*args, **kwargs))
313
313
  for _ in range(self._max_tasks)
314
314
  ]
315
- case _ as never:
315
+ case never:
316
316
  assert_never(never)
317
317
 
318
318
  async def run_or_create_task[T](
@@ -327,7 +327,7 @@ class EnhancedTaskGroup(TaskGroup):
327
327
  return await coro
328
328
  case False:
329
329
  return self.create_task(coro, name=name, context=context)
330
- case _ as never:
330
+ case never:
331
331
  assert_never(never)
332
332
 
333
333
  def _is_debug(self) -> bool:
utilities/hypothesis.py CHANGED
@@ -180,14 +180,14 @@ def date_deltas(
180
180
  min_value_ = DATE_DELTA_MIN
181
181
  case DateDelta():
182
182
  ...
183
- case _ as never:
183
+ case never:
184
184
  assert_never(never)
185
185
  match max_value_:
186
186
  case None:
187
187
  max_value_ = DATE_DELTA_MAX
188
188
  case DateDelta():
189
189
  ...
190
- case _ as never:
190
+ case never:
191
191
  assert_never(never)
192
192
  min_days = to_days(min_value_)
193
193
  max_days = to_days(max_value_)
@@ -217,14 +217,14 @@ def date_time_deltas(
217
217
  min_value_ = DATE_TIME_DELTA_MIN
218
218
  case DateTimeDelta():
219
219
  ...
220
- case _ as never:
220
+ case never:
221
221
  assert_never(never)
222
222
  match max_value_:
223
223
  case None:
224
224
  max_value_ = DATE_TIME_DELTA_MAX
225
225
  case DateTimeDelta():
226
226
  ...
227
- case _ as never:
227
+ case never:
228
228
  assert_never(never)
229
229
  min_nanos, max_nanos = map(to_nanoseconds, [min_value_, max_value_])
230
230
  if draw2(draw, parsable):
@@ -253,14 +253,14 @@ def dates(
253
253
  min_value_ = Date.MIN
254
254
  case Date():
255
255
  ...
256
- case _ as never:
256
+ case never:
257
257
  assert_never(never)
258
258
  match max_value_:
259
259
  case None:
260
260
  max_value_ = Date.MAX
261
261
  case Date():
262
262
  ...
263
- case _ as never:
263
+ case never:
264
264
  assert_never(never)
265
265
  if draw2(draw, two_digit):
266
266
  min_value_ = max(min_value_, DATE_TWO_DIGIT_YEAR_MIN)
@@ -343,7 +343,7 @@ def draw2[T](
343
343
  raise _Draw2InputResolvedToSentinelError
344
344
  case _, _, _:
345
345
  return value
346
- case _ as never:
346
+ case never:
347
347
  assert_never(never)
348
348
 
349
349
 
@@ -672,14 +672,14 @@ def month_days(
672
672
  min_value_ = MonthDay.MIN
673
673
  case MonthDay():
674
674
  ...
675
- case _ as never:
675
+ case never:
676
676
  assert_never(never)
677
677
  match max_value_:
678
678
  case None:
679
679
  max_value_ = MonthDay.MAX
680
680
  case MonthDay():
681
681
  ...
682
- case _ as never:
682
+ case never:
683
683
  assert_never(never)
684
684
  min_date, max_date = [m.in_year(2000) for m in [min_value_, max_value_]]
685
685
  date = draw(dates(min_value=min_date, max_value=max_date))
@@ -794,14 +794,14 @@ def plain_datetimes(
794
794
  min_value_ = PlainDateTime.MIN
795
795
  case PlainDateTime():
796
796
  ...
797
- case _ as never:
797
+ case never:
798
798
  assert_never(never)
799
799
  match max_value_:
800
800
  case None:
801
801
  max_value_ = PlainDateTime.MAX
802
802
  case PlainDateTime():
803
803
  ...
804
- case _ as never:
804
+ case never:
805
805
  assert_never(never)
806
806
  py_datetime = draw(
807
807
  datetimes(
@@ -887,7 +887,7 @@ def setup_hypothesis_profiles(
887
887
  return 100
888
888
  case Profile.ci:
889
889
  return 1000
890
- case _ as never:
890
+ case never:
891
891
  assert_never(never)
892
892
 
893
893
  @property
@@ -897,7 +897,7 @@ def setup_hypothesis_profiles(
897
897
  return Verbosity.quiet
898
898
  case Profile.ci:
899
899
  return Verbosity.verbose
900
- case _ as never:
900
+ case never:
901
901
  assert_never(never)
902
902
 
903
903
  phases = {Phase.explicit, Phase.reuse, Phase.generate, Phase.target}
@@ -1154,14 +1154,14 @@ def time_deltas(
1154
1154
  min_value_ = TIME_DELTA_MIN
1155
1155
  case TimeDelta():
1156
1156
  ...
1157
- case _ as never:
1157
+ case never:
1158
1158
  assert_never(never)
1159
1159
  match max_value_:
1160
1160
  case None:
1161
1161
  max_value_ = TIME_DELTA_MAX
1162
1162
  case TimeDelta():
1163
1163
  ...
1164
- case _ as never:
1164
+ case never:
1165
1165
  assert_never(never)
1166
1166
  py_time = draw(
1167
1167
  hypothesis.strategies.timedeltas(
@@ -1189,14 +1189,14 @@ def times(
1189
1189
  min_value_ = Time.MIN
1190
1190
  case Time():
1191
1191
  ...
1192
- case _ as never:
1192
+ case never:
1193
1193
  assert_never(never)
1194
1194
  match max_value_:
1195
1195
  case None:
1196
1196
  max_value_ = Time.MAX
1197
1197
  case Time():
1198
1198
  ...
1199
- case _ as never:
1199
+ case never:
1200
1200
  assert_never(never)
1201
1201
  py_time = draw(
1202
1202
  hypothesis.strategies.times(
@@ -1356,14 +1356,14 @@ def year_months(
1356
1356
  min_value_ = YearMonth.MIN
1357
1357
  case YearMonth():
1358
1358
  ...
1359
- case _ as never:
1359
+ case never:
1360
1360
  assert_never(never)
1361
1361
  match max_value_:
1362
1362
  case None:
1363
1363
  max_value_ = YearMonth.MAX
1364
1364
  case YearMonth():
1365
1365
  ...
1366
- case _ as never:
1366
+ case never:
1367
1367
  assert_never(never)
1368
1368
  min_date, max_date = [m.on_day(1) for m in [min_value_, max_value_]]
1369
1369
  date = draw(dates(min_value=min_date, max_value=max_date, two_digit=two_digit))
@@ -1391,7 +1391,7 @@ def zoned_datetimes(
1391
1391
  case ZonedDateTime():
1392
1392
  with assume_does_not_raise(ValueError):
1393
1393
  min_value_ = min_value_.to_tz(time_zone_.key).to_plain()
1394
- case _ as never:
1394
+ case never:
1395
1395
  assert_never(never)
1396
1396
  match max_value_:
1397
1397
  case None | PlainDateTime():
@@ -1399,7 +1399,7 @@ def zoned_datetimes(
1399
1399
  case ZonedDateTime():
1400
1400
  with assume_does_not_raise(ValueError):
1401
1401
  max_value_ = max_value_.to_tz(time_zone_.key).to_plain()
1402
- case _ as never:
1402
+ case never:
1403
1403
  assert_never(never)
1404
1404
  plain = draw(plain_datetimes(min_value=min_value_, max_value=max_value_))
1405
1405
  with (
@@ -1415,6 +1415,11 @@ def zoned_datetimes(
1415
1415
  return zoned
1416
1416
 
1417
1417
 
1418
+ zoned_datetimes_2000 = zoned_datetimes(
1419
+ min_value=ZonedDateTime(2000, 1, 1, tz=UTC.key),
1420
+ max_value=ZonedDateTime(2000, 12, 31, tz=UTC.key),
1421
+ )
1422
+
1418
1423
  __all__ = [
1419
1424
  "Draw2Error",
1420
1425
  "MaybeSearchStrategy",
@@ -1468,4 +1473,5 @@ __all__ = [
1468
1473
  "versions",
1469
1474
  "year_months",
1470
1475
  "zoned_datetimes",
1476
+ "zoned_datetimes_2000",
1471
1477
  ]
utilities/logging.py CHANGED
@@ -144,7 +144,7 @@ def basic_config(
144
144
  color_field_styles=color_field_styles,
145
145
  )
146
146
  handler.setFormatter(formatter)
147
- case _ as never:
147
+ case never:
148
148
  assert_never(never)
149
149
 
150
150
 
@@ -275,7 +275,7 @@ def get_logger(*, logger: LoggerOrName | None = None) -> Logger:
275
275
  return logger
276
276
  case str() | None:
277
277
  return getLogger(logger)
278
- case _ as never:
278
+ case never:
279
279
  assert_never(never)
280
280
 
281
281
 
utilities/period.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import datetime as dt
3
4
  from dataclasses import dataclass
4
5
  from typing import TYPE_CHECKING, Any, Self, TypedDict, assert_never, overload, override
5
6
  from zoneinfo import ZoneInfo
@@ -16,7 +17,9 @@ if TYPE_CHECKING:
16
17
  from utilities.types import TimeZoneLike
17
18
 
18
19
 
19
- class _PeriodAsDict[T: (Date, Time, ZonedDateTime)](TypedDict):
20
+ class _PeriodAsDict[T: Date | Time | ZonedDateTime | dt.date | dt.time | dt.datetime](
21
+ TypedDict
22
+ ):
20
23
  start: T
21
24
  end: T
22
25
 
@@ -81,6 +84,25 @@ class DatePeriod:
81
84
  return f"{fc(start)}-{fc(end, fmt='%m%d')}"
82
85
  return f"{fc(start)}-{fc(end)}"
83
86
 
87
+ @classmethod
88
+ def from_dict(cls, mapping: _PeriodAsDict[Date | dt.date], /) -> Self:
89
+ """Convert the dictionary to a period."""
90
+ match mapping["start"]:
91
+ case Date() as start:
92
+ ...
93
+ case dt.date() as py_date:
94
+ start = Date.from_py_date(py_date)
95
+ case never:
96
+ assert_never(never)
97
+ match mapping["end"]:
98
+ case Date() as end:
99
+ ...
100
+ case dt.date() as py_date:
101
+ end = Date.from_py_date(py_date)
102
+ case never:
103
+ assert_never(never)
104
+ return cls(start=start, end=end)
105
+
84
106
  def replace(
85
107
  self, *, start: Date | Sentinel = sentinel, end: Date | Sentinel = sentinel
86
108
  ) -> Self:
@@ -104,12 +126,6 @@ class TimePeriod:
104
126
  cls = get_class_name(self)
105
127
  return f"{cls}({self.start}, {self.end})"
106
128
 
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
129
  def at(
114
130
  self, obj: Date | tuple[Date, Date], /, *, time_zone: TimeZoneLike = UTC
115
131
  ) -> ZonedDateTimePeriod:
@@ -123,6 +139,31 @@ class TimePeriod:
123
139
  assert_never(never)
124
140
  return DatePeriod(start, end).at((self.start, self.end), time_zone=time_zone)
125
141
 
142
+ @classmethod
143
+ def from_dict(cls, mapping: _PeriodAsDict[Time | dt.time], /) -> Self:
144
+ """Convert the dictionary to a period."""
145
+ match mapping["start"]:
146
+ case Time() as start:
147
+ ...
148
+ case dt.time() as py_time:
149
+ start = Time.from_py_time(py_time)
150
+ case never:
151
+ assert_never(never)
152
+ match mapping["end"]:
153
+ case Time() as end:
154
+ ...
155
+ case dt.time() as py_time:
156
+ end = Time.from_py_time(py_time)
157
+ case never:
158
+ assert_never(never)
159
+ return cls(start=start, end=end)
160
+
161
+ def replace(
162
+ self, *, start: Time | Sentinel = sentinel, end: Time | Sentinel = sentinel
163
+ ) -> Self:
164
+ """Replace elements of the period."""
165
+ return replace_non_sentinel(self, start=start, end=end)
166
+
126
167
  def to_dict(self) -> _PeriodAsDict[Time]:
127
168
  """Convert the period to a dictionary."""
128
169
  return _PeriodAsDict(start=self.start, end=self.end)
@@ -229,6 +270,25 @@ class ZonedDateTimePeriod:
229
270
  return f"{fc(start.to_plain())}-{fc(end, fmt='%Y%m%dT%H%M')}"
230
271
  return f"{fc(start.to_plain())}-{fc(end, fmt='%Y%m%dT%H')}"
231
272
 
273
+ @classmethod
274
+ def from_dict(cls, mapping: _PeriodAsDict[ZonedDateTime | dt.datetime], /) -> Self:
275
+ """Convert the dictionary to a period."""
276
+ match mapping["start"]:
277
+ case ZonedDateTime() as start:
278
+ ...
279
+ case dt.date() as py_datetime:
280
+ start = ZonedDateTime.from_py_datetime(py_datetime)
281
+ case never:
282
+ assert_never(never)
283
+ match mapping["end"]:
284
+ case ZonedDateTime() as end:
285
+ ...
286
+ case dt.date() as py_datetime:
287
+ end = ZonedDateTime.from_py_datetime(py_datetime)
288
+ case never:
289
+ assert_never(never)
290
+ return cls(start=start, end=end)
291
+
232
292
  def replace(
233
293
  self,
234
294
  *,
@@ -258,7 +318,7 @@ class PeriodError(Exception): ...
258
318
 
259
319
 
260
320
  @dataclass(kw_only=True, slots=True)
261
- class _PeriodInvalidError[T: (Date, ZonedDateTime)](PeriodError):
321
+ class _PeriodInvalidError[T: Date | ZonedDateTime](PeriodError):
262
322
  start: T
263
323
  end: T
264
324
 
utilities/redis.py CHANGED
@@ -386,7 +386,7 @@ class RedisKey[T]:
386
386
  match result: # skipif-ci-and-not-linux
387
387
  case 0 | 1 as value:
388
388
  return bool(value)
389
- case _ as never:
389
+ case never:
390
390
  assert_never(never)
391
391
 
392
392
  async def get(self, redis: Redis, /) -> T:
@@ -561,7 +561,7 @@ async def publish[T](
561
561
  raise PublishError(data=data)
562
562
  case _, Callable():
563
563
  data_use = serializer(data)
564
- case _ as never:
564
+ case never:
565
565
  assert_never(never)
566
566
  async with timeout_td(timeout): # skipif-ci-and-not-linux
567
567
  response = await redis.publish(channel, data_use) # skipif-ci-and-not-linux
@@ -710,7 +710,7 @@ async def subscribe[T](
710
710
  def transform(message: _RedisMessage, /) -> T:
711
711
  return deserialize(message["data"])
712
712
 
713
- case _ as never:
713
+ case never:
714
714
  assert_never(never)
715
715
 
716
716
  task = create_task( # skipif-ci-and-not-linux
utilities/sqlalchemy.py CHANGED
@@ -166,7 +166,7 @@ async def check_engine(
166
166
  query = "select * from all_objects"
167
167
  case "sqlite":
168
168
  query = "select * from sqlite_master where type='table'"
169
- case _ as never:
169
+ case never:
170
170
  assert_never(never)
171
171
  statement = text(query)
172
172
  async with yield_connection(engine, timeout=timeout, error=error) as conn:
@@ -312,7 +312,7 @@ def create_engine(
312
312
  return sqlalchemy.create_engine(url, poolclass=poolclass)
313
313
  case True:
314
314
  return sqlalchemy.ext.asyncio.create_async_engine(url, poolclass=poolclass)
315
- case _ as never:
315
+ case never:
316
316
  assert_never(never)
317
317
 
318
318
 
@@ -339,7 +339,7 @@ async def ensure_tables_created(
339
339
  match = "ORA-00955: name is already used by an existing object"
340
340
  case "sqlite":
341
341
  match = "table .* already exists"
342
- case _ as never:
342
+ case never:
343
343
  assert_never(never)
344
344
  async with yield_connection(engine, timeout=timeout, error=error) as conn:
345
345
  for table in tables:
@@ -368,7 +368,7 @@ async def ensure_tables_dropped(
368
368
  match = "ORA-00942: table or view does not exist"
369
369
  case "sqlite":
370
370
  match = "no such table"
371
- case _ as never:
371
+ case never:
372
372
  assert_never(never)
373
373
  async with yield_connection(engine, timeout=timeout, error=error) as conn:
374
374
  for table in tables:
@@ -493,7 +493,7 @@ def get_chunk_size(
493
493
  case int() as num_cols:
494
494
  size = floor(chunk_size_frac * max_params / num_cols)
495
495
  return max(size, 1)
496
- case _ as never:
496
+ case never:
497
497
  assert_never(never)
498
498
 
499
499
 
@@ -777,7 +777,7 @@ def _normalize_upsert_item(
777
777
  yield _NormalizedItem(mapping=values, table=norm.table)
778
778
  case "all":
779
779
  yield from normalized
780
- case _ as never:
780
+ case never:
781
781
  assert_never(never)
782
782
 
783
783
 
@@ -890,7 +890,7 @@ def _upsert_items_build(
890
890
  insert = sqlite_insert
891
891
  case "mssql" | "mysql" | "oracle" as dialect: # pragma: no cover
892
892
  raise NotImplementedError(dialect)
893
- case _ as never:
893
+ case never:
894
894
  assert_never(never)
895
895
  ins = insert(table).values(values)
896
896
  primary_key = cast("Any", table.primary_key)
@@ -912,7 +912,7 @@ def _upsert_items_apply_on_conflict_do_update(
912
912
  columns = merge_sets(*values)
913
913
  case "all":
914
914
  columns = {c.name for c in insert.excluded}
915
- case _ as never:
915
+ case never:
916
916
  assert_never(never)
917
917
  set_ = {c: getattr(insert.excluded, c) for c in columns}
918
918
  match insert:
@@ -920,7 +920,7 @@ def _upsert_items_apply_on_conflict_do_update(
920
920
  return insert.on_conflict_do_update(constraint=primary_key, set_=set_)
921
921
  case sqlite_Insert():
922
922
  return insert.on_conflict_do_update(index_elements=primary_key, set_=set_)
923
- case _ as never:
923
+ case never:
924
924
  assert_never(never)
925
925
 
926
926
 
@@ -1029,7 +1029,7 @@ def _get_dialect_max_params(
1029
1029
  ):
1030
1030
  dialect = _get_dialect(engine_or_conn)
1031
1031
  return _get_dialect_max_params(dialect)
1032
- case _ as never:
1032
+ case never:
1033
1033
  assert_never(never)
1034
1034
 
1035
1035