none-shall-parse 0.6.1__tar.gz → 0.6.3__tar.gz

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.3
2
2
  Name: none-shall-parse
3
- Version: 0.6.1
3
+ Version: 0.6.3
4
4
  Summary: Trinity Shared Python utilities.
5
5
  Author: Andries Niemandt, Jan Badenhorst
6
6
  Author-email: Andries Niemandt <andries.niemandt@trintel.co.za>, Jan Badenhorst <jan@trintel.co.za>
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "none-shall-parse"
7
- version = "0.6.1"
7
+ version = "0.6.3"
8
8
  description = "Trinity Shared Python utilities."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -10,28 +10,48 @@ translates to "none". Combined this with our parsing intentions
10
10
  to create a name which nods to the Black Knight in Monty Python's Holy Grail.
11
11
  https://www.youtube.com/watch?v=zKhEw7nD9C4
12
12
  """
13
+
13
14
  from __future__ import annotations
14
15
  from .dates import (
15
- DateUtilsError, assert_week_start_date_is_valid,
16
+ DateUtilsError,
17
+ assert_week_start_date_is_valid,
16
18
  assert_month_start_date_is_valid,
17
- get_datetime_now, za_now, utc_now,
19
+ get_datetime_now,
20
+ za_now,
21
+ utc_now,
18
22
  za_ordinal_year_day_now,
19
- za_ordinal_year_day_tomorrow, utc_epoch_start,
20
- now_offset_n_minutes, now_offset_n_hours,
21
- now_offset_n_days, now_offset_n_months, get_datetime_tomorrow,
23
+ za_ordinal_year_day_tomorrow,
24
+ utc_epoch_start,
25
+ now_offset_n_minutes,
26
+ now_offset_n_hours,
27
+ now_offset_n_days,
28
+ now_offset_n_months,
29
+ get_datetime_tomorrow,
22
30
  get_datetime_yesterday,
23
31
  get_utc_datetime_offset_n_days,
24
- epoch_to_datetime, epoch_to_utc_datetime,
32
+ epoch_to_datetime,
33
+ epoch_to_utc_datetime,
25
34
  is_office_hours_in_timezone,
26
35
  get_datetime_from_ordinal_and_sentinel,
27
- day_span, week_span, month_span, arb_span,
28
- calendar_month_start_end, unix_timestamp,
36
+ day_span,
37
+ week_span,
38
+ month_span,
39
+ arb_span,
40
+ calendar_month_start_end,
41
+ unix_timestamp,
29
42
  sentinel_date_and_ordinal_to_date,
30
- seconds_to_end_of_month, standard_tz_timestring,
31
- get_notice_end_date, dt_to_za_time_string,
32
- months_ago_selection, is_aware, make_aware,
33
- unaware_to_utc_aware, timer_decorator, ZA_TZ,
34
- UTC_TZ, keys_for_span_func,
43
+ seconds_to_end_of_month,
44
+ standard_tz_timestring,
45
+ get_notice_end_date,
46
+ dt_to_za_time_string,
47
+ months_ago_selection,
48
+ is_aware,
49
+ make_aware,
50
+ unaware_to_utc_aware,
51
+ timer_decorator,
52
+ ZA_TZ,
53
+ UTC_TZ,
54
+ keys_for_span_func,
35
55
  )
36
56
  from .imeis import (
37
57
  get_luhn_digit,
@@ -83,26 +103,45 @@ __email__ = "andries.niemandt@trintel.co.za, jan@trintel.co.za"
83
103
  __license__ = "MIT"
84
104
 
85
105
  __all__ = (
86
- "DateUtilsError", "assert_week_start_date_is_valid",
106
+ "DateUtilsError",
107
+ "assert_week_start_date_is_valid",
87
108
  "assert_month_start_date_is_valid",
88
- "get_datetime_now", "za_now", "utc_now",
109
+ "get_datetime_now",
110
+ "za_now",
111
+ "utc_now",
89
112
  "za_ordinal_year_day_now",
90
- "za_ordinal_year_day_tomorrow", "utc_epoch_start",
91
- "now_offset_n_minutes", "now_offset_n_hours",
92
- "now_offset_n_days", "now_offset_n_months", "get_datetime_tomorrow",
113
+ "za_ordinal_year_day_tomorrow",
114
+ "utc_epoch_start",
115
+ "now_offset_n_minutes",
116
+ "now_offset_n_hours",
117
+ "now_offset_n_days",
118
+ "now_offset_n_months",
119
+ "get_datetime_tomorrow",
93
120
  "get_datetime_yesterday",
94
121
  "get_utc_datetime_offset_n_days",
95
- "epoch_to_datetime", "epoch_to_utc_datetime",
122
+ "epoch_to_datetime",
123
+ "epoch_to_utc_datetime",
96
124
  "is_office_hours_in_timezone",
97
125
  "get_datetime_from_ordinal_and_sentinel",
98
- "day_span", "week_span", "month_span", "arb_span",
99
- "calendar_month_start_end", "unix_timestamp",
126
+ "day_span",
127
+ "week_span",
128
+ "month_span",
129
+ "arb_span",
130
+ "calendar_month_start_end",
131
+ "unix_timestamp",
100
132
  "sentinel_date_and_ordinal_to_date",
101
- "seconds_to_end_of_month", "standard_tz_timestring",
102
- "get_notice_end_date", "dt_to_za_time_string",
103
- "months_ago_selection", "is_aware", "make_aware",
104
- "unaware_to_utc_aware", "timer_decorator", "ZA_TZ",
105
- "UTC_TZ", "keys_for_span_func",
133
+ "seconds_to_end_of_month",
134
+ "standard_tz_timestring",
135
+ "get_notice_end_date",
136
+ "dt_to_za_time_string",
137
+ "months_ago_selection",
138
+ "is_aware",
139
+ "make_aware",
140
+ "unaware_to_utc_aware",
141
+ "timer_decorator",
142
+ "ZA_TZ",
143
+ "UTC_TZ",
144
+ "keys_for_span_func",
106
145
  "get_luhn_digit",
107
146
  "is_valid_luhn",
108
147
  "is_valid_imei",
@@ -136,4 +175,4 @@ __all__ = (
136
175
  "DateTimeLike",
137
176
  "DateLike",
138
177
  "DateTimeOrDateLike",
139
- )
178
+ )
@@ -10,8 +10,8 @@ from pendulum import DateTime, Date
10
10
  from pendulum import local_timezone
11
11
  from pendulum.tz.exceptions import InvalidTimezone
12
12
 
13
- ZA_TZ = 'Africa/Johannesburg'
14
- UTC_TZ = 'UTC'
13
+ ZA_TZ = "Africa/Johannesburg"
14
+ UTC_TZ = "UTC"
15
15
 
16
16
 
17
17
  class DateUtilsError(Exception):
@@ -48,13 +48,17 @@ def get_datetime_now(naive: bool = False, tz: str | None = None) -> DateTime:
48
48
  naive (bool): If True, returns a naive DateTime object without timezone information.
49
49
  Defaults to True.
50
50
  tz (Optional[str]): The timezone to use if a timezone-aware DateTime is requested.
51
- If not provided and naive is False, the default system timezone
52
- is used.
51
+ If not provided and naive is False, defaults to ZA_TZ.
53
52
 
54
53
  Returns:
55
54
  pendulum.DateTime: The current date and time based on the specified parameters.
56
55
  """
57
- return pendulum.now().naive() if naive else pendulum.now(tz=tz)
56
+ if naive:
57
+ return pendulum.now().naive()
58
+ else:
59
+ # Default to ZA_TZ if no timezone is specified for aware datetime
60
+ timezone = tz if tz is not None else ZA_TZ
61
+ return pendulum.now(tz=timezone)
58
62
 
59
63
 
60
64
  def za_now() -> DateTime:
@@ -120,8 +124,9 @@ def utc_epoch_start() -> DateTime:
120
124
  return pendulum.from_timestamp(0)
121
125
 
122
126
 
123
- def _now_offset_n_units(n: int, units: str, naive: bool = False,
124
- tz: str | None = None) -> DateTime:
127
+ def _now_offset_n_units(
128
+ n: int, units: str, naive: bool = False, tz: str | None = None
129
+ ) -> DateTime:
125
130
  """
126
131
  Calculate a DateTime object offset by a specified number of time units.
127
132
 
@@ -141,22 +146,24 @@ def _now_offset_n_units(n: int, units: str, naive: bool = False,
141
146
  DateTime: The calculated DateTime object, optionally timezone-aware or naive.
142
147
  """
143
148
  kwargs = {units: n}
144
- return pendulum.now().add(**kwargs).naive() if naive else pendulum.now(tz).add(
145
- **kwargs)
149
+ return (
150
+ pendulum.now().add(**kwargs).naive()
151
+ if naive
152
+ else pendulum.now(tz).add(**kwargs)
153
+ )
146
154
 
147
155
 
148
- def now_offset_n_minutes(n: int, naive: bool = False,
149
- tz: str | None = None) -> DateTime:
156
+ def now_offset_n_minutes(
157
+ n: int, naive: bool = False, tz: str | None = None
158
+ ) -> DateTime:
150
159
  return _now_offset_n_units(n, units="minutes", naive=naive, tz=tz)
151
160
 
152
161
 
153
- def now_offset_n_hours(n: int, naive: bool = False,
154
- tz: str | None = None) -> DateTime:
162
+ def now_offset_n_hours(n: int, naive: bool = False, tz: str | None = None) -> DateTime:
155
163
  return _now_offset_n_units(n, units="hours", naive=naive, tz=tz)
156
164
 
157
165
 
158
- def now_offset_n_days(n: int, naive: bool = False,
159
- tz: str | None = None) -> DateTime:
166
+ def now_offset_n_days(n: int, naive: bool = False, tz: str | None = None) -> DateTime:
160
167
  return _now_offset_n_units(n, units="days", naive=naive, tz=tz)
161
168
 
162
169
 
@@ -164,14 +171,12 @@ def now_offset_n_months(n: int, naive: bool = False, tz: str | None = None) -> D
164
171
  return _now_offset_n_units(n, units="months", naive=naive, tz=tz)
165
172
 
166
173
 
167
- def get_datetime_tomorrow(naive: bool = False,
168
- tz: str | None = None) -> DateTime:
174
+ def get_datetime_tomorrow(naive: bool = False, tz: str | None = None) -> DateTime:
169
175
  """Get tomorrow's DateTime"""
170
176
  return now_offset_n_days(1, naive=naive, tz=tz)
171
177
 
172
178
 
173
- def get_datetime_yesterday(naive: bool = False,
174
- tz: str | None = None) -> DateTime:
179
+ def get_datetime_yesterday(naive: bool = False, tz: str | None = None) -> DateTime:
175
180
  """Get yesterday's DateTime"""
176
181
  return now_offset_n_days(-1, naive=naive, tz=tz)
177
182
 
@@ -181,8 +186,9 @@ def get_utc_datetime_offset_n_days(n: int = 0) -> DateTime:
181
186
  return pendulum.now(UTC_TZ).add(days=n)
182
187
 
183
188
 
184
- def epoch_to_datetime(epoch_int: int | float, naive: bool = False,
185
- tz: str | None = None) -> DateTime:
189
+ def epoch_to_datetime(
190
+ epoch_int: int | float, naive: bool = False, tz: str | None = None
191
+ ) -> DateTime:
186
192
  """
187
193
  Converts an epoch timestamp to a DateTime object.
188
194
 
@@ -231,7 +237,9 @@ def epoch_to_utc_datetime(epoch_int: int | float | str) -> DateTime:
231
237
  return pendulum.from_timestamp(int(epoch_int), tz=UTC_TZ)
232
238
 
233
239
 
234
- def is_office_hours_in_timezone(epoch_int: int | float | str, tz: str | None = None) -> bool:
240
+ def is_office_hours_in_timezone(
241
+ epoch_int: int | float | str, tz: str | None = None
242
+ ) -> bool:
235
243
  """
236
244
  Determines if a given epoch timestamp falls within office hours for a
237
245
  specific timezone.
@@ -263,7 +271,8 @@ def is_office_hours_in_timezone(epoch_int: int | float | str, tz: str | None = N
263
271
 
264
272
 
265
273
  def get_datetime_from_ordinal_and_sentinel(
266
- sentinel: DateTimeLike | None = None) -> Callable[[int], DateTime]:
274
+ sentinel: DateTimeLike | None = None,
275
+ ) -> Callable[[int], DateTime]:
267
276
  """
268
277
  Given an ordinal year day, and a sentinel datetime, get the closest past
269
278
  datetime to the sentinel that had the given ordinal year day.
@@ -324,8 +333,8 @@ def day_span(pts: DateTimeLike) -> Tuple[DateTime, DateTime]:
324
333
  pdt = pendulum.instance(pts)
325
334
 
326
335
  # Use Pendulum's clean API
327
- begin = pdt.start_of('day')
328
- end = pdt.add(days=1).start_of('day')
336
+ begin = pdt.start_of("day")
337
+ end = pdt.add(days=1).start_of("day")
329
338
 
330
339
  if naive:
331
340
  return begin.naive(), end.naive()
@@ -362,7 +371,7 @@ def week_span(wso: int) -> Callable[[DateTimeLike], Tuple[DateTime, DateTime]]:
362
371
  current_weekday = pdt.weekday() + 1 # Pendulum uses 0-6, we want 1-7
363
372
  days_back = (current_weekday - wso) % 7
364
373
 
365
- begin = pdt.start_of('day').subtract(days=days_back)
374
+ begin = pdt.start_of("day").subtract(days=days_back)
366
375
  end = begin.add(days=7)
367
376
 
368
377
  if naive:
@@ -401,10 +410,10 @@ def month_span(mso: int) -> Callable[[DateTimeLike], Tuple[DateTime, DateTime]]:
401
410
 
402
411
  if current_day >= mso:
403
412
  # We're in the current month period
404
- begin = pdt.start_of('day').replace(day=mso)
413
+ begin = pdt.start_of("day").replace(day=mso)
405
414
  else:
406
415
  # We're in the previous month period
407
- begin = pdt.start_of('day').subtract(months=1).replace(day=mso)
416
+ begin = pdt.start_of("day").subtract(months=1).replace(day=mso)
408
417
 
409
418
  # End is mso of next month from `begin`
410
419
  end = begin.add(months=1)
@@ -417,8 +426,9 @@ def month_span(mso: int) -> Callable[[DateTimeLike], Tuple[DateTime, DateTime]]:
417
426
  return find_dates
418
427
 
419
428
 
420
- def arb_span(dates: Sequence[str | DateTimeOrDateLike], naive: bool = False) -> Callable[
421
- [Any], Tuple[DateTime, DateTime]]:
429
+ def arb_span(
430
+ dates: Sequence[str | DateTimeOrDateLike], naive: bool = False
431
+ ) -> Callable[[Any], Tuple[DateTime, DateTime]]:
422
432
  """
423
433
  Parses two given dates and returns a callable function that provides the date range
424
434
  as a tuple of datetime objects. The function ensures the date range is valid and
@@ -447,19 +457,25 @@ def arb_span(dates: Sequence[str | DateTimeOrDateLike], naive: bool = False) ->
447
457
  parsed = pendulum.parse(date)
448
458
 
449
459
  # If it's a date-only string (no time/timezone info), treat as naive
450
- if 'T' not in date and ' ' not in date:
460
+ if "T" not in date and " " not in date:
451
461
  parsed = parsed.naive()
452
462
 
453
- parsed_dates.append(parsed.start_of('day'))
463
+ parsed_dates.append(parsed.start_of("day"))
454
464
  else:
455
465
  # It's already a datetime-like object
456
466
  if isinstance(date, datetime):
457
467
  # datetime objects have tzinfo, hour, minute, etc.
458
468
  if date.tzinfo is None:
459
469
  # Input is naive, keep it naive using pendulum.naive()
460
- parsed = pendulum.naive(date.year, date.month, date.day,
461
- date.hour, date.minute, date.second,
462
- date.microsecond)
470
+ parsed = pendulum.naive(
471
+ date.year,
472
+ date.month,
473
+ date.day,
474
+ date.hour,
475
+ date.minute,
476
+ date.second,
477
+ date.microsecond,
478
+ )
463
479
  else:
464
480
  # Input is timezone-aware, preserve it
465
481
  parsed = pendulum.instance(date)
@@ -467,7 +483,7 @@ def arb_span(dates: Sequence[str | DateTimeOrDateLike], naive: bool = False) ->
467
483
  # date objects (no time component, no tzinfo) - treat as naive
468
484
  parsed = pendulum.naive(date.year, date.month, date.day)
469
485
 
470
- parsed_dates.append(parsed.start_of('day'))
486
+ parsed_dates.append(parsed.start_of("day"))
471
487
 
472
488
  a, b = parsed_dates
473
489
 
@@ -497,8 +513,8 @@ def arb_span(dates: Sequence[str | DateTimeOrDateLike], naive: bool = False) ->
497
513
 
498
514
 
499
515
  def unroll_span_func(
500
- f: Callable[[DateTimeLike], Tuple[DateTime, DateTime]],
501
- cover: DateTimeLike | None = None,
516
+ f: Callable[[DateTimeLike], Tuple[DateTime, DateTime]],
517
+ cover: DateTimeLike | None = None,
502
518
  ) -> Tuple[List[DateTime], List[int], List[str], DateTime, DateTime]:
503
519
  """
504
520
  Generate keys for a date range based on a provided function.
@@ -554,7 +570,7 @@ def unroll_span_func(
554
570
  if dt <= current_date_sentinel and dt < end:
555
571
  date_range.append(dt)
556
572
  ord_days.append(dt.day_of_year)
557
- iso_date_strings.append(dt.format('YYYY-MM-DD'))
573
+ iso_date_strings.append(dt.format("YYYY-MM-DD"))
558
574
 
559
575
  return date_range, ord_days, iso_date_strings, start, end
560
576
 
@@ -563,10 +579,10 @@ def unroll_span_func(
563
579
 
564
580
 
565
581
  def keys_for_span_func(
566
- f: Callable[[DateTimeLike], Tuple[DateTime, DateTime]],
567
- cover: DateTimeLike | None = None,
568
- key_in_format: str = "ODIN_{}",
569
- key_out_format: str = "ODOUT_{}",
582
+ f: Callable[[DateTimeLike], Tuple[DateTime, DateTime]],
583
+ cover: DateTimeLike | None = None,
584
+ key_in_format: str = "ODIN_{}",
585
+ key_out_format: str = "ODOUT_{}",
570
586
  ):
571
587
  """
572
588
  Generate keys for a date range based on a provided function.
@@ -586,14 +602,17 @@ def keys_for_span_func(
586
602
  Raises:
587
603
  DateUtilsError: If the date range cannot be processed.
588
604
  """
589
- date_range, ord_days, iso_date_strings, start, end = unroll_span_func(f=f, cover=cover)
605
+ date_range, ord_days, iso_date_strings, start, end = unroll_span_func(
606
+ f=f, cover=cover
607
+ )
590
608
  keys_in = [key_in_format.format(d) for d in ord_days]
591
609
  keys_out = [key_out_format.format(d) for d in ord_days]
592
610
  return keys_in, keys_out, start, end
593
611
 
594
612
 
595
- def calendar_month_start_end(date_in_month: DateTimeLike | None = None) -> Tuple[
596
- DateTime, DateTime]:
613
+ def calendar_month_start_end(
614
+ date_in_month: DateTimeLike | None = None,
615
+ ) -> Tuple[DateTime, DateTime]:
597
616
  naive = date_in_month.tzinfo is None
598
617
 
599
618
  if date_in_month is None:
@@ -601,7 +620,7 @@ def calendar_month_start_end(date_in_month: DateTimeLike | None = None) -> Tuple
601
620
 
602
621
  pdt = pendulum.instance(date_in_month)
603
622
 
604
- start = pdt.start_of('month')
623
+ start = pdt.start_of("month")
605
624
  end = start.add(months=1)
606
625
 
607
626
  if naive:
@@ -620,8 +639,9 @@ def unix_timestamp() -> int:
620
639
  return round(time.time())
621
640
 
622
641
 
623
- def sentinel_date_and_ordinal_to_date(sentinel_date: DateTimeLike | date,
624
- ordinal: int | float | str) -> date:
642
+ def sentinel_date_and_ordinal_to_date(
643
+ sentinel_date: DateTimeLike | date, ordinal: int | float | str
644
+ ) -> date:
625
645
  """Convert sentinel date and ordinal day to actual date"""
626
646
  year = sentinel_date.year
627
647
  int_ordinal = int(ordinal)
@@ -638,7 +658,7 @@ def sentinel_date_and_ordinal_to_date(sentinel_date: DateTimeLike | date,
638
658
  def seconds_to_end_of_month() -> int:
639
659
  """Calculate seconds remaining until the end of the current month"""
640
660
  now = pendulum.now(UTC_TZ)
641
- end_of_month = now.end_of('month')
661
+ end_of_month = now.end_of("month")
642
662
  return int((end_of_month - now).total_seconds())
643
663
 
644
664
 
@@ -667,24 +687,42 @@ def get_notice_end_date(given_date: DateTimeLike | date | Date | None = None) ->
667
687
  given_date = given_date.date()
668
688
  elif not isinstance(given_date, date):
669
689
  raise ValueError(
670
- "Given date must be a datetime.date or datetime.datetime object")
690
+ "Given date must be a datetime.date or datetime.datetime object"
691
+ )
671
692
 
672
693
  pdt = pendulum.instance(given_date)
673
694
  if given_date.day <= 15:
674
695
  # End of current month
675
- end_date = pdt.add(months=1).start_of('month')
696
+ end_date = pdt.add(months=1).start_of("month")
676
697
  else:
677
698
  # End of next month
678
- end_date = pdt.add(months=2).start_of('month')
699
+ end_date = pdt.add(months=2).start_of("month")
679
700
 
680
701
  if isinstance(end_date, DateTime):
681
702
  return end_date.date()
682
703
  return end_date
683
704
 
684
705
 
685
- def dt_to_za_time_string(v: DateTimeLike) -> str:
686
- """Convert DateTime to South Africa time string"""
687
- # Convert to Pendulum
706
+ def dt_to_za_time_string(v: DateTimeOrDateLike | float | None) -> str | None:
707
+ """Convert DateTime or Date to South Africa time string.
708
+
709
+ For datetime objects: returns "YYYY-MM-DD HH:MM:SS" in ZA timezone.
710
+ For date objects: returns "YYYY-MM-DD" (no time component).
711
+ For None: returns None.
712
+ For float values (NaN): returns None.
713
+ """
714
+ if v is None:
715
+ return None
716
+
717
+ # Handle float values (NaN from pandas NULL database values)
718
+ if isinstance(v, float):
719
+ return None
720
+
721
+ # Handle date objects (no time component)
722
+ if isinstance(v, date) and not isinstance(v, datetime):
723
+ return v.strftime("%Y-%m-%d")
724
+
725
+ # Convert datetime to Pendulum
688
726
  naive = v.tzinfo is None
689
727
  if naive:
690
728
  pdt = pendulum.instance(v, tz=ZA_TZ)
@@ -697,10 +735,7 @@ def months_ago_selection() -> List[Tuple[int, str]]:
697
735
  """Generate list of (index, "Month-Year") tuples for last 12 months"""
698
736
  today = pendulum.today()
699
737
 
700
- return [
701
- (i, today.subtract(months=i).strftime("%B-%Y"))
702
- for i in range(12)
703
- ]
738
+ return [(i, today.subtract(months=i).strftime("%B-%Y")) for i in range(12)]
704
739
 
705
740
 
706
741
  def is_aware(dt: DateTimeLike | Date | date) -> bool:
@@ -708,7 +743,9 @@ def is_aware(dt: DateTimeLike | Date | date) -> bool:
708
743
  return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
709
744
 
710
745
 
711
- def make_aware(dt: DateTimeLike | date | Date | None, tz: str = None) -> DateTime | Date | None:
746
+ def make_aware(
747
+ dt: DateTimeLike | date | Date | None, tz: str = None
748
+ ) -> DateTime | Date | None:
712
749
  """
713
750
  Convert a naive DateTime to a timezone-aware DateTime using Pendulum.
714
751
 
@@ -743,7 +780,9 @@ def make_aware(dt: DateTimeLike | date | Date | None, tz: str = None) -> DateTim
743
780
  raise DateUtilsError(f"Invalid timezone: {tz}") from e
744
781
 
745
782
 
746
- def unaware_to_utc_aware(dt: DateTimeLike | date | Date | None) -> DateTime | Date | None:
783
+ def unaware_to_utc_aware(
784
+ dt: DateTimeLike | date | Date | None,
785
+ ) -> DateTime | Date | None:
747
786
  """Convert naive DateTime to UTC-aware DateTime using Pendulum."""
748
787
  if not isinstance(dt, (datetime, type(None))):
749
788
  raise TypeError(f"Expected datetime or None, got {type(dt)}")
@@ -1,4 +1,3 @@
1
-
2
1
  LUHN_DOUBLES = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
3
2
 
4
3
 
@@ -1,4 +1,3 @@
1
- import collections
2
1
  from typing import Iterable, Generator, Any, List
3
2
 
4
3
  from .types import T