dycw-utilities 0.166.2__py3-none-any.whl → 0.166.4__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,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.166.2
3
+ Version: 0.166.4
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
7
7
  Requires-Dist: atomicwrites<1.5,>=1.4.1
8
- Requires-Dist: typing-extensions<4.15,>=4.14.0
8
+ Requires-Dist: typing-extensions<4.16,>=4.15.0
9
9
  Requires-Dist: tzlocal<5.4,>=5.3.1
10
10
  Requires-Dist: whenever<0.9,>=0.8.8
11
11
  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.139,>=6.138.2; extra == 'test'
15
+ Requires-Dist: hypothesis<6.139,>=6.138.6; extra == 'test'
16
16
  Requires-Dist: pytest-asyncio<1.2,>=1.1.0; extra == 'test'
17
17
  Requires-Dist: pytest-cov<6.3,>=6.2.1; extra == 'test'
18
18
  Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=NNNZPLvpz8NHxcszE2dbVPYUi7cTPpL0VlUzD3PFpEU,60
1
+ utilities/__init__.py,sha256=s-Uh--xTi8lR5pU36QdYxFXLv1whLxgsm_xW8WJ9kEI,60
2
2
  utilities/aeventkit.py,sha256=ddoleSwW9zdc2tjX5Ge0pMKtYwV_JMxhHYOxnWX2AGM,12609
3
3
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
4
4
  utilities/asyncio.py,sha256=PUedzQ5deqlSECQ33sam9cRzI9TnygHz3FdOqWJWPTM,15288
@@ -75,21 +75,21 @@ utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
75
75
  utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
76
76
  utilities/traceback.py,sha256=b1nSvlyrGmI1MyZLkkoLVET3DQBSGt9qqIlAAQbyjEw,9629
77
77
  utilities/typed_settings.py,sha256=SFWqS3lAzV7IfNRwqFcTk0YynTcQ7BmrcW2mr_KUnos,4466
78
- utilities/types.py,sha256=oeH-hEC3-67Eja4nLz-Nj9WvK6Z9-3T1zobO_XJpuVg,18735
78
+ utilities/types.py,sha256=IlRrCtPdLkGYVfpe-QIg2qNUgBr8OJNN7BhTKxnhh-M,18817
79
79
  utilities/typing.py,sha256=QYoCIc71e_u5W-kBeiNzrD-GXxpLtMOGc9PqgZjMXeE,25274
80
80
  utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
81
81
  utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
82
82
  utilities/uuid.py,sha256=nQZs6tFX4mqtc2Ku3KqjloYCqwpTKeTj8eKwQwh3FQI,1572
83
83
  utilities/version.py,sha256=ipBj5-WYY_nelp2uwFlApfWWCzTLzPwpovUi9x_OBMs,5085
84
84
  utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
85
- utilities/whenever.py,sha256=aeeas2SsA6Uq__tmm2kiYQZaOE_TklPsWCD_JGS3czs,57916
85
+ utilities/whenever.py,sha256=0N5JcZU9cPyIrkTN3wqdcR86PsmIKVlLI1yU1aEbIgk,59198
86
86
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
87
87
  utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
88
88
  utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
89
89
  utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
90
90
  utilities/pytest_plugins/pytest_regressions.py,sha256=9v8kAXDM2ycIXJBimoiF4EgrwbUvxTycFWJiGR_GHhM,1466
91
- dycw_utilities-0.166.2.dist-info/METADATA,sha256=eQxPlntL_GXTG8DmFDjXmdVY4Rpyl7euahHf_yW3Rk8,1696
92
- dycw_utilities-0.166.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- dycw_utilities-0.166.2.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
- dycw_utilities-0.166.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.166.2.dist-info/RECORD,,
91
+ dycw_utilities-0.166.4.dist-info/METADATA,sha256=iwjEa8xty7iVF7FfYcYGIwaflQWKn2XFMfUrvUFHxPk,1696
92
+ dycw_utilities-0.166.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ dycw_utilities-0.166.4.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
+ dycw_utilities-0.166.4.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.166.4.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.166.2"
3
+ __version__ = "0.166.4"
utilities/types.py CHANGED
@@ -255,6 +255,7 @@ type DateTimeRoundMode = Literal[
255
255
  ]
256
256
  type Delta = DateDelta | TimeDelta | DateTimeDelta
257
257
  type MaybeCallableDateLike = MaybeCallable[DateLike]
258
+ type MaybeCallableTimeLike = MaybeCallable[TimeLike]
258
259
  type MaybeCallableZonedDateTimeLike = MaybeCallable[ZonedDateTimeLike]
259
260
  type MonthDayLike = MaybeStr[MonthDay]
260
261
  type PlainDateTimeLike = MaybeStr[PlainDateTime]
@@ -308,6 +309,7 @@ __all__ = [
308
309
  "MaybeCallableDateLike",
309
310
  "MaybeCallablePathLike",
310
311
  "MaybeCallableStr",
312
+ "MaybeCallableTimeLike",
311
313
  "MaybeCallableUUIDLike",
312
314
  "MaybeCallableZonedDateTimeLike",
313
315
  "MaybeCollection",
utilities/whenever.py CHANGED
@@ -46,6 +46,7 @@ if TYPE_CHECKING:
46
46
  DateTimeRoundMode,
47
47
  Delta,
48
48
  MaybeCallableDateLike,
49
+ MaybeCallableTimeLike,
49
50
  MaybeCallableZonedDateTimeLike,
50
51
  TimeOrDateTimeDelta,
51
52
  TimeZoneLike,
@@ -368,7 +369,7 @@ NOW_UTC = get_now(UTC)
368
369
 
369
370
 
370
371
  def get_now_local() -> ZonedDateTime:
371
- """Get the current local date-time."""
372
+ """Get the current zoned date-time in the local time-zone."""
372
373
  return get_now(LOCAL_TIME_ZONE)
373
374
 
374
375
 
@@ -376,7 +377,7 @@ NOW_LOCAL = get_now_local()
376
377
 
377
378
 
378
379
  def get_now_plain(time_zone: TimeZoneLike = UTC, /) -> PlainDateTime:
379
- """Get the current date-time as a plain date-time."""
380
+ """Get the current plain date-time."""
380
381
  return get_now(time_zone).to_plain()
381
382
 
382
383
 
@@ -384,7 +385,7 @@ NOW_PLAIN = get_now_plain()
384
385
 
385
386
 
386
387
  def get_now_local_plain() -> PlainDateTime:
387
- """Get the current local date-time as a plain date-time."""
388
+ """Get the current plain date-time in the local time-zone."""
388
389
  return get_now_local().to_plain()
389
390
 
390
391
 
@@ -394,6 +395,25 @@ NOW_LOCAL_PLAIN = get_now_local_plain()
394
395
  ##
395
396
 
396
397
 
398
+ def get_time(time_zone: TimeZoneLike = UTC, /) -> Time:
399
+ """Get the current time."""
400
+ return get_now(time_zone).time()
401
+
402
+
403
+ TIME_UTC = get_time(UTC)
404
+
405
+
406
+ def get_time_local() -> Time:
407
+ """Get the current time in the local time-zone."""
408
+ return get_time(LOCAL_TIME_ZONE)
409
+
410
+
411
+ TIME_LOCAL = get_time_local()
412
+
413
+
414
+ ##
415
+
416
+
397
417
  def get_today(time_zone: TimeZoneLike = UTC, /) -> Date:
398
418
  """Get the current, timezone-aware local date."""
399
419
  return get_now(time_zone).date()
@@ -1378,6 +1398,95 @@ class ToPyTimeDeltaError(Exception):
1378
1398
  ##
1379
1399
 
1380
1400
 
1401
+ def to_seconds(delta: Delta, /) -> int:
1402
+ """Compute the number of seconds in a delta."""
1403
+ match delta:
1404
+ case DateDelta():
1405
+ try:
1406
+ days = to_days(delta)
1407
+ except _ToDaysMonthsError as error:
1408
+ raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1409
+ return 24 * 60 * 60 * days
1410
+ case TimeDelta():
1411
+ nanos = to_nanoseconds(delta)
1412
+ seconds, remainder = divmod(nanos, int(1e9))
1413
+ if remainder != 0:
1414
+ raise _ToSecondsNanosecondsError(delta=delta, nanoseconds=remainder)
1415
+ return seconds
1416
+ case DateTimeDelta():
1417
+ try:
1418
+ return to_seconds(delta.date_part()) + to_seconds(delta.time_part())
1419
+ except _ToSecondsMonthsError as error:
1420
+ raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1421
+ except _ToSecondsNanosecondsError as error:
1422
+ raise _ToSecondsNanosecondsError(
1423
+ delta=delta, nanoseconds=error.nanoseconds
1424
+ ) from None
1425
+ case never:
1426
+ assert_never(never)
1427
+
1428
+
1429
+ @dataclass(kw_only=True, slots=True)
1430
+ class ToSecondsError(Exception): ...
1431
+
1432
+
1433
+ @dataclass(kw_only=True, slots=True)
1434
+ class _ToSecondsMonthsError(ToSecondsError):
1435
+ delta: DateOrDateTimeDelta
1436
+ months: int
1437
+
1438
+ @override
1439
+ def __str__(self) -> str:
1440
+ return f"Delta must not contain months; got {self.months}"
1441
+
1442
+
1443
+ @dataclass(kw_only=True, slots=True)
1444
+ class _ToSecondsNanosecondsError(ToSecondsError):
1445
+ delta: TimeOrDateTimeDelta
1446
+ nanoseconds: int
1447
+
1448
+ @override
1449
+ def __str__(self) -> str:
1450
+ return f"Delta must not contain extra nanoseconds; got {self.nanoseconds}"
1451
+
1452
+
1453
+ ##
1454
+
1455
+
1456
+ @overload
1457
+ def to_time(time: Sentinel, /, *, time_zone: TimeZoneLike = UTC) -> Sentinel: ...
1458
+ @overload
1459
+ def to_time(
1460
+ time: MaybeCallableTimeLike | None | dt.time = get_time,
1461
+ /,
1462
+ *,
1463
+ time_zone: TimeZoneLike = UTC,
1464
+ ) -> Time: ...
1465
+ def to_time(
1466
+ time: MaybeCallableTimeLike | dt.time | None | Sentinel = get_time,
1467
+ /,
1468
+ *,
1469
+ time_zone: TimeZoneLike = UTC,
1470
+ ) -> Time | Sentinel:
1471
+ """Convert to a time."""
1472
+ match time:
1473
+ case Time() | Sentinel():
1474
+ return time
1475
+ case None:
1476
+ return get_time(time_zone)
1477
+ case str():
1478
+ return Time.parse_common_iso(time)
1479
+ case dt.time():
1480
+ return Time.from_py_time(time)
1481
+ case Callable() as func:
1482
+ return to_time(func(), time_zone=time_zone)
1483
+ case never:
1484
+ assert_never(never)
1485
+
1486
+
1487
+ ##
1488
+
1489
+
1381
1490
  def to_time_delta(nanos: int, /) -> TimeDelta:
1382
1491
  """Construct a time delta."""
1383
1492
  components = _to_time_delta_components(nanos)
@@ -1456,61 +1565,6 @@ def _to_time_delta_components(nanos: int, /) -> _TimeDeltaComponents:
1456
1565
  ##
1457
1566
 
1458
1567
 
1459
- def to_seconds(delta: Delta, /) -> int:
1460
- """Compute the number of seconds in a delta."""
1461
- match delta:
1462
- case DateDelta():
1463
- try:
1464
- days = to_days(delta)
1465
- except _ToDaysMonthsError as error:
1466
- raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1467
- return 24 * 60 * 60 * days
1468
- case TimeDelta():
1469
- nanos = to_nanoseconds(delta)
1470
- seconds, remainder = divmod(nanos, int(1e9))
1471
- if remainder != 0:
1472
- raise _ToSecondsNanosecondsError(delta=delta, nanoseconds=remainder)
1473
- return seconds
1474
- case DateTimeDelta():
1475
- try:
1476
- return to_seconds(delta.date_part()) + to_seconds(delta.time_part())
1477
- except _ToSecondsMonthsError as error:
1478
- raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1479
- except _ToSecondsNanosecondsError as error:
1480
- raise _ToSecondsNanosecondsError(
1481
- delta=delta, nanoseconds=error.nanoseconds
1482
- ) from None
1483
- case never:
1484
- assert_never(never)
1485
-
1486
-
1487
- @dataclass(kw_only=True, slots=True)
1488
- class ToSecondsError(Exception): ...
1489
-
1490
-
1491
- @dataclass(kw_only=True, slots=True)
1492
- class _ToSecondsMonthsError(ToSecondsError):
1493
- delta: DateOrDateTimeDelta
1494
- months: int
1495
-
1496
- @override
1497
- def __str__(self) -> str:
1498
- return f"Delta must not contain months; got {self.months}"
1499
-
1500
-
1501
- @dataclass(kw_only=True, slots=True)
1502
- class _ToSecondsNanosecondsError(ToSecondsError):
1503
- delta: TimeOrDateTimeDelta
1504
- nanoseconds: int
1505
-
1506
- @override
1507
- def __str__(self) -> str:
1508
- return f"Delta must not contain extra nanoseconds; got {self.nanoseconds}"
1509
-
1510
-
1511
- ##
1512
-
1513
-
1514
1568
  def to_weeks(delta: Delta, /) -> int:
1515
1569
  """Compute the number of weeks in a delta."""
1516
1570
  try:
@@ -1935,6 +1989,8 @@ __all__ = [
1935
1989
  "SECOND",
1936
1990
  "TIME_DELTA_MAX",
1937
1991
  "TIME_DELTA_MIN",
1992
+ "TIME_LOCAL",
1993
+ "TIME_UTC",
1938
1994
  "TODAY_LOCAL",
1939
1995
  "TODAY_UTC",
1940
1996
  "WEEK",
@@ -1973,6 +2029,8 @@ __all__ = [
1973
2029
  "get_now_local",
1974
2030
  "get_now_local_plain",
1975
2031
  "get_now_plain",
2032
+ "get_time",
2033
+ "get_time_local",
1976
2034
  "get_today",
1977
2035
  "get_today_local",
1978
2036
  "mean_datetime",
@@ -1991,6 +2049,7 @@ __all__ = [
1991
2049
  "to_py_date_or_date_time",
1992
2050
  "to_py_time_delta",
1993
2051
  "to_seconds",
2052
+ "to_time",
1994
2053
  "to_weeks",
1995
2054
  "to_years",
1996
2055
  "to_zoned_date_time",