dycw-utilities 0.117.1__py3-none-any.whl → 0.119.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.
utilities/whenever.py CHANGED
@@ -5,9 +5,15 @@ import re
5
5
  from contextlib import suppress
6
6
  from dataclasses import dataclass
7
7
  from typing import TYPE_CHECKING, override
8
- from zoneinfo import ZoneInfo
9
8
 
10
- from whenever import Date, DateTimeDelta, LocalDateTime, Time, ZonedDateTime
9
+ from whenever import (
10
+ Date,
11
+ DateTimeDelta,
12
+ PlainDateTime,
13
+ Time,
14
+ TimeZoneNotFoundError,
15
+ ZonedDateTime,
16
+ )
11
17
 
12
18
  from utilities.datetime import (
13
19
  _MICROSECONDS_PER_DAY,
@@ -37,7 +43,7 @@ if TYPE_CHECKING:
37
43
  )
38
44
 
39
45
 
40
- MAX_SERIALIZABLE_TIMEDELTA = dt.timedelta(days=3659635, microseconds=-1)
46
+ MAX_SERIALIZABLE_TIMEDELTA = dt.timedelta(days=3652060, microseconds=-1)
41
47
  MIN_SERIALIZABLE_TIMEDELTA = -MAX_SERIALIZABLE_TIMEDELTA
42
48
 
43
49
 
@@ -48,19 +54,33 @@ def check_valid_zoned_datetime(datetime: dt.datetime, /) -> None:
48
54
  """Check if a zoned datetime is valid."""
49
55
  time_zone = ensure_time_zone(datetime) # skipif-ci-and-windows
50
56
  datetime2 = datetime.replace(tzinfo=time_zone) # skipif-ci-and-windows
51
- result = ( # skipif-ci-and-windows
52
- ZonedDateTime.from_py_datetime(datetime2)
53
- .to_tz(get_time_zone_name(UTC))
54
- .to_tz(get_time_zone_name(time_zone))
55
- .py_datetime()
56
- )
57
+ try: # skipif-ci-and-windows
58
+ result = (
59
+ ZonedDateTime.from_py_datetime(datetime2)
60
+ .to_tz(get_time_zone_name(UTC))
61
+ .to_tz(get_time_zone_name(time_zone))
62
+ .py_datetime()
63
+ )
64
+ except TimeZoneNotFoundError: # pragma: no cover
65
+ raise _CheckValidZonedDateTimeInvalidTimeZoneError(datetime=datetime) from None
57
66
  if result != datetime2: # skipif-ci-and-windows
58
- raise CheckValidZonedDateimeError(datetime=datetime, result=result)
67
+ raise _CheckValidZonedDateTimeUnequalError(datetime=datetime, result=result)
59
68
 
60
69
 
61
70
  @dataclass(kw_only=True, slots=True)
62
- class CheckValidZonedDateimeError(Exception):
71
+ class CheckValidZonedDateTimeError(Exception):
63
72
  datetime: dt.datetime
73
+
74
+
75
+ @dataclass(kw_only=True, slots=True)
76
+ class _CheckValidZonedDateTimeInvalidTimeZoneError(CheckValidZonedDateTimeError):
77
+ @override
78
+ def __str__(self) -> str:
79
+ return f"Invalid timezone; got {self.datetime.tzinfo}" # pragma: no cover
80
+
81
+
82
+ @dataclass(kw_only=True, slots=True)
83
+ class _CheckValidZonedDateTimeUnequalError(CheckValidZonedDateTimeError):
64
84
  result: dt.datetime
65
85
 
66
86
  @override
@@ -138,23 +158,23 @@ class EnsureDurationError(Exception):
138
158
  ##
139
159
 
140
160
 
141
- def ensure_local_datetime(datetime: DateTimeLike, /) -> dt.datetime:
142
- """Ensure the object is a local datetime."""
161
+ def ensure_plain_datetime(datetime: DateTimeLike, /) -> dt.datetime:
162
+ """Ensure the object is a plain datetime."""
143
163
  if isinstance(datetime, dt.datetime):
144
164
  return datetime
145
165
  try:
146
- return parse_local_datetime(datetime)
147
- except ParseLocalDateTimeError as error:
148
- raise EnsureLocalDateTimeError(datetime=error.datetime) from None
166
+ return parse_plain_datetime(datetime)
167
+ except ParsePlainDateTimeError as error:
168
+ raise EnsurePlainDateTimeError(datetime=error.datetime) from None
149
169
 
150
170
 
151
171
  @dataclass(kw_only=True, slots=True)
152
- class EnsureLocalDateTimeError(Exception):
172
+ class EnsurePlainDateTimeError(Exception):
153
173
  datetime: str
154
174
 
155
175
  @override
156
176
  def __str__(self) -> str:
157
- return f"Unable to ensure local datetime; got {self.datetime!r}"
177
+ return f"Unable to ensure plain datetime; got {self.datetime!r}"
158
178
 
159
179
 
160
180
  ##
@@ -242,7 +262,6 @@ class EnsureZonedDateTimeError(Exception):
242
262
  ##
243
263
 
244
264
 
245
- _PARSE_DATE_YYYYMMDD_REGEX = re.compile(r"^(\d{4})(\d{2})(\d{2})$")
246
265
  _PARSE_DATE_YYMMDD_REGEX = re.compile(r"^(\d{2})(\d{2})(\d{2})$")
247
266
 
248
267
 
@@ -250,19 +269,14 @@ def parse_date(date: str, /) -> dt.date:
250
269
  """Parse a string into a date."""
251
270
  try:
252
271
  w_date = Date.parse_common_iso(date)
253
- except ValueError:
254
- pass
255
- else:
256
- return w_date.py_date()
257
- try:
258
- ((year, month, day),) = _PARSE_DATE_YYYYMMDD_REGEX.findall(date)
259
272
  except ValueError:
260
273
  try:
261
274
  ((year2, month, day),) = _PARSE_DATE_YYMMDD_REGEX.findall(date)
262
275
  except ValueError:
263
276
  raise ParseDateError(date=date) from None
264
277
  year = parse_two_digit_year(year2)
265
- return dt.date(year=int(year), month=int(month), day=int(day))
278
+ return dt.date(year=int(year), month=int(month), day=int(day))
279
+ return w_date.py_date()
266
280
 
267
281
 
268
282
  @dataclass(kw_only=True, slots=True)
@@ -279,8 +293,8 @@ class ParseDateError(Exception):
279
293
 
280
294
  def parse_datetime(datetime: str, /) -> dt.datetime:
281
295
  """Parse a string into a datetime."""
282
- with suppress(ParseLocalDateTimeError):
283
- return parse_local_datetime(datetime)
296
+ with suppress(ParsePlainDateTimeError):
297
+ return parse_plain_datetime(datetime)
284
298
  with suppress(ParseZonedDateTimeError):
285
299
  return parse_zoned_datetime(datetime)
286
300
  raise ParseDateTimeError(datetime=datetime) from None
@@ -320,48 +334,22 @@ class ParseDurationError(Exception):
320
334
  ##
321
335
 
322
336
 
323
- _PARSE_LOCAL_DATETIME_REGEX = re.compile(
324
- r"^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})\.?(\d{6})?$"
325
- )
326
-
327
-
328
- def parse_local_datetime(datetime: str, /) -> dt.datetime:
329
- """Parse a string into a local datetime."""
330
- try:
331
- ldt = LocalDateTime.parse_common_iso(datetime)
332
- except ValueError:
333
- pass
334
- else:
335
- return ldt.py_datetime()
337
+ def parse_plain_datetime(datetime: str, /) -> dt.datetime:
338
+ """Parse a string into a plain datetime."""
336
339
  try:
337
- ((year, month, day, hour, minute, second, microsecond),) = (
338
- _PARSE_LOCAL_DATETIME_REGEX.findall(datetime)
339
- )
340
- except ValueError:
341
- raise ParseLocalDateTimeError(datetime=datetime) from None
342
- try:
343
- microsecond_use = int(microsecond)
340
+ ldt = PlainDateTime.parse_common_iso(datetime)
344
341
  except ValueError:
345
- microsecond_use = 0
346
- return dt.datetime(
347
- year=int(year),
348
- month=int(month),
349
- day=int(day),
350
- hour=int(hour),
351
- minute=int(minute),
352
- second=int(second),
353
- microsecond=microsecond_use,
354
- tzinfo=UTC,
355
- ).replace(tzinfo=None)
342
+ raise ParsePlainDateTimeError(datetime=datetime) from None
343
+ return ldt.py_datetime()
356
344
 
357
345
 
358
346
  @dataclass(kw_only=True, slots=True)
359
- class ParseLocalDateTimeError(Exception):
347
+ class ParsePlainDateTimeError(Exception):
360
348
  datetime: str
361
349
 
362
350
  @override
363
351
  def __str__(self) -> str:
364
- return f"Unable to parse local datetime; got {self.datetime!r}"
352
+ return f"Unable to parse plain datetime; got {self.datetime!r}"
365
353
 
366
354
 
367
355
  ##
@@ -435,39 +423,13 @@ class _ParseTimedeltaNanosecondError(ParseTimedeltaError):
435
423
  ##
436
424
 
437
425
 
438
- _PARSE_ZONED_DATETIME_REGEX = re.compile(
439
- r"^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})\.?(\d{6})?\[([\w\+\-/]+)\]$"
440
- )
441
-
442
-
443
426
  def parse_zoned_datetime(datetime: str, /) -> dt.datetime:
444
427
  """Parse a string into a zoned datetime."""
445
428
  try:
446
429
  zdt = ZonedDateTime.parse_common_iso(datetime)
447
- except ValueError:
448
- pass
449
- else:
450
- return zdt.py_datetime()
451
- try:
452
- ((year, month, day, hour, minute, second, microsecond, timezone),) = (
453
- _PARSE_ZONED_DATETIME_REGEX.findall(datetime)
454
- )
455
430
  except ValueError:
456
431
  raise ParseZonedDateTimeError(datetime=datetime) from None
457
- try: # skipif-ci-and-windows
458
- microsecond_use = int(microsecond)
459
- except ValueError: # skipif-ci-and-windows
460
- microsecond_use = 0
461
- return dt.datetime( # skipif-ci-and-windows
462
- year=int(year),
463
- month=int(month),
464
- day=int(day),
465
- hour=int(hour),
466
- minute=int(minute),
467
- second=int(second),
468
- microsecond=microsecond_use,
469
- tzinfo=ZoneInfo(timezone),
470
- )
432
+ return zdt.py_datetime()
471
433
 
472
434
 
473
435
  @dataclass(kw_only=True, slots=True)
@@ -494,8 +456,8 @@ def serialize_date(date: dt.date, /) -> str:
494
456
  def serialize_datetime(datetime: dt.datetime, /) -> str:
495
457
  """Serialize a datetime."""
496
458
  try:
497
- return serialize_local_datetime(datetime)
498
- except SerializeLocalDateTimeError:
459
+ return serialize_plain_datetime(datetime)
460
+ except SerializePlainDateTimeError:
499
461
  return serialize_zoned_datetime(datetime)
500
462
 
501
463
 
@@ -524,22 +486,22 @@ class SerializeDurationError(Exception):
524
486
  ##
525
487
 
526
488
 
527
- def serialize_local_datetime(datetime: dt.datetime, /) -> str:
528
- """Serialize a local datetime."""
489
+ def serialize_plain_datetime(datetime: dt.datetime, /) -> str:
490
+ """Serialize a plain datetime."""
529
491
  try:
530
- ldt = LocalDateTime.from_py_datetime(datetime)
492
+ pdt = PlainDateTime.from_py_datetime(datetime)
531
493
  except ValueError:
532
- raise SerializeLocalDateTimeError(datetime=datetime) from None
533
- return ldt.format_common_iso()
494
+ raise SerializePlainDateTimeError(datetime=datetime) from None
495
+ return pdt.format_common_iso()
534
496
 
535
497
 
536
498
  @dataclass(kw_only=True, slots=True)
537
- class SerializeLocalDateTimeError(Exception):
499
+ class SerializePlainDateTimeError(Exception):
538
500
  datetime: dt.datetime
539
501
 
540
502
  @override
541
503
  def __str__(self) -> str:
542
- return f"Unable to serialize local datetime; got {self.datetime}"
504
+ return f"Unable to serialize plain datetime; got {self.datetime}"
543
505
 
544
506
 
545
507
  ##
@@ -630,43 +592,43 @@ class _ToDateTimeDeltaError(Exception):
630
592
  __all__ = [
631
593
  "MAX_SERIALIZABLE_TIMEDELTA",
632
594
  "MIN_SERIALIZABLE_TIMEDELTA",
633
- "CheckValidZonedDateimeError",
595
+ "CheckValidZonedDateTimeError",
634
596
  "EnsureDateError",
635
597
  "EnsureDateTimeError",
636
- "EnsureLocalDateTimeError",
598
+ "EnsurePlainDateTimeError",
637
599
  "EnsureTimeError",
638
600
  "EnsureTimedeltaError",
639
601
  "EnsureZonedDateTimeError",
640
602
  "ParseDateError",
641
603
  "ParseDateTimeError",
642
604
  "ParseDurationError",
643
- "ParseLocalDateTimeError",
605
+ "ParsePlainDateTimeError",
644
606
  "ParseTimeError",
645
607
  "ParseTimedeltaError",
646
608
  "ParseZonedDateTimeError",
647
609
  "SerializeDurationError",
648
- "SerializeLocalDateTimeError",
610
+ "SerializePlainDateTimeError",
649
611
  "SerializeTimeDeltaError",
650
612
  "SerializeZonedDateTimeError",
651
613
  "check_valid_zoned_datetime",
652
614
  "ensure_date",
653
615
  "ensure_datetime",
654
616
  "ensure_duration",
655
- "ensure_local_datetime",
617
+ "ensure_plain_datetime",
656
618
  "ensure_time",
657
619
  "ensure_timedelta",
658
620
  "ensure_zoned_datetime",
659
621
  "parse_date",
660
622
  "parse_datetime",
661
623
  "parse_duration",
662
- "parse_local_datetime",
624
+ "parse_plain_datetime",
663
625
  "parse_time",
664
626
  "parse_timedelta",
665
627
  "parse_zoned_datetime",
666
628
  "serialize_date",
667
629
  "serialize_datetime",
668
630
  "serialize_duration",
669
- "serialize_local_datetime",
631
+ "serialize_plain_datetime",
670
632
  "serialize_time",
671
633
  "serialize_timedelta",
672
634
  "serialize_zoned_datetime",
utilities/zoneinfo.py CHANGED
@@ -32,7 +32,7 @@ def ensure_time_zone(obj: TimeZoneLike, /) -> ZoneInfo:
32
32
  raise _EnsureTimeZoneInvalidTZInfoError(time_zone=obj)
33
33
  case dt.datetime() as datetime:
34
34
  if datetime.tzinfo is None:
35
- raise _EnsureTimeZoneLocalDateTimeError(datetime=datetime)
35
+ raise _EnsureTimeZonePlainDateTimeError(datetime=datetime)
36
36
  return ensure_time_zone(datetime.tzinfo)
37
37
  case _ as never:
38
38
  assert_never(never)
@@ -52,12 +52,12 @@ class _EnsureTimeZoneInvalidTZInfoError(EnsureTimeZoneError):
52
52
 
53
53
 
54
54
  @dataclass(kw_only=True, slots=True)
55
- class _EnsureTimeZoneLocalDateTimeError(EnsureTimeZoneError):
55
+ class _EnsureTimeZonePlainDateTimeError(EnsureTimeZoneError):
56
56
  datetime: dt.datetime
57
57
 
58
58
  @override
59
59
  def __str__(self) -> str:
60
- return f"Local datetime: {self.datetime}"
60
+ return f"Plain datetime: {self.datetime}"
61
61
 
62
62
 
63
63
  ##