none-shall-parse 0.4.2__py3-none-any.whl → 0.4.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.
- none_shall_parse/__init__.py +8 -2
- none_shall_parse/dates.py +100 -99
- none_shall_parse/strings.py +19 -0
- none_shall_parse/types.py +9 -0
- {none_shall_parse-0.4.2.dist-info → none_shall_parse-0.4.4.dist-info}/METADATA +1 -1
- none_shall_parse-0.4.4.dist-info/RECORD +10 -0
- none_shall_parse-0.4.2.dist-info/RECORD +0 -10
- {none_shall_parse-0.4.2.dist-info → none_shall_parse-0.4.4.dist-info}/WHEEL +0 -0
none_shall_parse/__init__.py
CHANGED
|
@@ -72,7 +72,10 @@ from .strings import (
|
|
|
72
72
|
)
|
|
73
73
|
from .types import (
|
|
74
74
|
StringLike,
|
|
75
|
-
ChoicesType
|
|
75
|
+
ChoicesType,
|
|
76
|
+
DateTimeLike,
|
|
77
|
+
DateLike,
|
|
78
|
+
DateTimeOrDateLike,
|
|
76
79
|
)
|
|
77
80
|
|
|
78
81
|
__author__ = "Andries Niemandt, Jan Badenhorst"
|
|
@@ -129,5 +132,8 @@ __all__ = (
|
|
|
129
132
|
"calc_hash",
|
|
130
133
|
"generate_random_password",
|
|
131
134
|
"StringLike",
|
|
132
|
-
"ChoicesType"
|
|
135
|
+
"ChoicesType",
|
|
136
|
+
"DateTimeLike",
|
|
137
|
+
"DateLike",
|
|
138
|
+
"DateTimeOrDateLike",
|
|
133
139
|
)
|
none_shall_parse/dates.py
CHANGED
|
@@ -3,8 +3,10 @@ import logging
|
|
|
3
3
|
import time
|
|
4
4
|
from datetime import date, datetime
|
|
5
5
|
from typing import Callable, Any, Tuple, Sequence, List
|
|
6
|
+
from .types import DateTimeLike
|
|
6
7
|
|
|
7
8
|
import pendulum
|
|
9
|
+
from pendulum import DateTime, Date
|
|
8
10
|
from pendulum import local_timezone
|
|
9
11
|
from pendulum.tz.exceptions import InvalidTimezone
|
|
10
12
|
|
|
@@ -24,38 +26,38 @@ class DateUtilsError(Exception):
|
|
|
24
26
|
self.message = message
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
def assert_week_start_date_is_valid(wso):
|
|
29
|
+
def assert_week_start_date_is_valid(wso: int) -> None:
|
|
28
30
|
if wso < 1 or wso > 7:
|
|
29
31
|
raise DateUtilsError("Weeks can only start on days between 1 and 7")
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
def assert_month_start_date_is_valid(mso):
|
|
34
|
+
def assert_month_start_date_is_valid(mso: int) -> None:
|
|
33
35
|
if mso > 28 or mso < 1:
|
|
34
36
|
raise DateUtilsError("Months can only start on days between 1 and 28")
|
|
35
37
|
|
|
36
38
|
|
|
37
|
-
def get_datetime_now(naive: bool = False, tz: str | None = None) ->
|
|
39
|
+
def get_datetime_now(naive: bool = False, tz: str | None = None) -> DateTime:
|
|
38
40
|
"""
|
|
39
41
|
Get the current date and time.
|
|
40
42
|
|
|
41
43
|
This function retrieves the current date and time using the pendulum library. It can
|
|
42
|
-
return the
|
|
44
|
+
return the DateTime in either a naive or timezone-aware format, depending on the
|
|
43
45
|
parameters provided.
|
|
44
46
|
|
|
45
47
|
Args:
|
|
46
|
-
naive (bool): If True, returns a naive
|
|
48
|
+
naive (bool): If True, returns a naive DateTime object without timezone information.
|
|
47
49
|
Defaults to True.
|
|
48
|
-
tz (Optional[str]): The timezone to use if a timezone-aware
|
|
50
|
+
tz (Optional[str]): The timezone to use if a timezone-aware DateTime is requested.
|
|
49
51
|
If not provided and naive is False, the default system timezone
|
|
50
52
|
is used.
|
|
51
53
|
|
|
52
54
|
Returns:
|
|
53
|
-
|
|
55
|
+
pendulum.DateTime: The current date and time based on the specified parameters.
|
|
54
56
|
"""
|
|
55
57
|
return pendulum.now().naive() if naive else pendulum.now(tz=tz)
|
|
56
58
|
|
|
57
59
|
|
|
58
|
-
def za_now() ->
|
|
60
|
+
def za_now() -> DateTime:
|
|
59
61
|
"""
|
|
60
62
|
Returns the current date and time in the South African timezone.
|
|
61
63
|
|
|
@@ -64,7 +66,7 @@ def za_now() -> datetime:
|
|
|
64
66
|
time localization.
|
|
65
67
|
|
|
66
68
|
Returns:
|
|
67
|
-
|
|
69
|
+
pendulum.DateTime: The current date and time in the South African timezone.
|
|
68
70
|
"""
|
|
69
71
|
return get_datetime_now(naive=False, tz=ZA_TZ)
|
|
70
72
|
|
|
@@ -95,39 +97,39 @@ def za_ordinal_year_day_tomorrow() -> int:
|
|
|
95
97
|
return pendulum.now(ZA_TZ).add(days=1).day_of_year
|
|
96
98
|
|
|
97
99
|
|
|
98
|
-
def utc_epoch_start() ->
|
|
100
|
+
def utc_epoch_start() -> DateTime:
|
|
99
101
|
"""
|
|
100
|
-
Gets the UTC epoch start time as a
|
|
102
|
+
Gets the UTC epoch start time as a DateTime object.
|
|
101
103
|
|
|
102
104
|
This function calculates the start of the UNIX epoch (January 1, 1970)
|
|
103
|
-
in UTC as a
|
|
105
|
+
in UTC as a DateTime object. It leverages the `pendulum` library for
|
|
104
106
|
handling the time calculation with the specified UTC timezone.
|
|
105
107
|
|
|
106
108
|
Returns:
|
|
107
|
-
|
|
109
|
+
pendulum.DateTime: A pendulum DateTime object representing the start of the UTC epoch.
|
|
108
110
|
"""
|
|
109
111
|
return pendulum.from_timestamp(0)
|
|
110
112
|
|
|
111
113
|
|
|
112
114
|
def _now_offset_n_units(n: int, units: str, naive: bool = False,
|
|
113
|
-
tz: str | None = None) ->
|
|
115
|
+
tz: str | None = None) -> DateTime:
|
|
114
116
|
"""
|
|
115
|
-
Calculate a
|
|
117
|
+
Calculate a DateTime object offset by a specified number of time units.
|
|
116
118
|
|
|
117
|
-
This function allows you to calculate a
|
|
119
|
+
This function allows you to calculate a DateTime offset by a given number of units
|
|
118
120
|
(minutes, hours, days, etc.) from the current time. You can also specify the timezone
|
|
119
|
-
and whether the returned
|
|
121
|
+
and whether the returned DateTime should be naive or timezone-aware.
|
|
120
122
|
|
|
121
123
|
Parameters:
|
|
122
124
|
n (int): The number of units to offset the current time by.
|
|
123
125
|
units (str): The type of time unit to offset by.
|
|
124
|
-
naive (bool): Whether to return a naive
|
|
126
|
+
naive (bool): Whether to return a naive DateTime (without timezone information).
|
|
125
127
|
Defaults to False.
|
|
126
|
-
tz (Optional[str]): The timezone of the resulting
|
|
128
|
+
tz (Optional[str]): The timezone of the resulting DateTime. If not provided,
|
|
127
129
|
the system's local timezone is used.
|
|
128
130
|
|
|
129
131
|
Returns:
|
|
130
|
-
|
|
132
|
+
DateTime: The calculated DateTime object, optionally timezone-aware or naive.
|
|
131
133
|
"""
|
|
132
134
|
kwargs = {units: n}
|
|
133
135
|
return pendulum.now().add(**kwargs).naive() if naive else pendulum.now(tz).add(
|
|
@@ -135,58 +137,58 @@ def _now_offset_n_units(n: int, units: str, naive: bool = False,
|
|
|
135
137
|
|
|
136
138
|
|
|
137
139
|
def now_offset_n_minutes(n: int, naive: bool = False,
|
|
138
|
-
tz: str | None = None) ->
|
|
140
|
+
tz: str | None = None) -> DateTime:
|
|
139
141
|
return _now_offset_n_units(n, units="minutes", naive=naive, tz=tz)
|
|
140
142
|
|
|
141
143
|
|
|
142
144
|
def now_offset_n_hours(n: int, naive: bool = False,
|
|
143
|
-
tz: str | None = None) ->
|
|
145
|
+
tz: str | None = None) -> DateTime:
|
|
144
146
|
return _now_offset_n_units(n, units="hours", naive=naive, tz=tz)
|
|
145
147
|
|
|
146
148
|
|
|
147
149
|
def now_offset_n_days(n: int, naive: bool = False,
|
|
148
|
-
tz: str | None = None) ->
|
|
150
|
+
tz: str | None = None) -> DateTime:
|
|
149
151
|
return _now_offset_n_units(n, units="days", naive=naive, tz=tz)
|
|
150
152
|
|
|
151
153
|
|
|
152
154
|
def get_datetime_tomorrow(naive: bool = False,
|
|
153
|
-
tz: str | None = None) ->
|
|
154
|
-
"""Get tomorrow's
|
|
155
|
+
tz: str | None = None) -> DateTime:
|
|
156
|
+
"""Get tomorrow's DateTime"""
|
|
155
157
|
return now_offset_n_days(1, naive=naive, tz=tz)
|
|
156
158
|
|
|
157
159
|
|
|
158
160
|
def get_datetime_yesterday(naive: bool = False,
|
|
159
|
-
tz: str | None = None) ->
|
|
160
|
-
"""Get yesterday's
|
|
161
|
+
tz: str | None = None) -> DateTime:
|
|
162
|
+
"""Get yesterday's DateTime"""
|
|
161
163
|
return now_offset_n_days(-1, naive=naive, tz=tz)
|
|
162
164
|
|
|
163
165
|
|
|
164
|
-
def get_utc_datetime_offset_n_days(n: int = 0) ->
|
|
165
|
-
"""Get UTC
|
|
166
|
+
def get_utc_datetime_offset_n_days(n: int = 0) -> DateTime:
|
|
167
|
+
"""Get UTC DateTime n with an offset of n days"""
|
|
166
168
|
return pendulum.now(UTC_TZ).add(days=n)
|
|
167
169
|
|
|
168
170
|
|
|
169
171
|
def epoch_to_datetime(epoch_int: int | float, naive: bool = False,
|
|
170
|
-
tz: str | None = None) ->
|
|
172
|
+
tz: str | None = None) -> DateTime:
|
|
171
173
|
"""
|
|
172
|
-
Converts an epoch timestamp to a
|
|
174
|
+
Converts an epoch timestamp to a DateTime object.
|
|
173
175
|
|
|
174
176
|
This function takes an input epoch timestamp and converts it into a
|
|
175
|
-
|
|
176
|
-
to either naive or timezone-aware
|
|
177
|
+
DateTime object using the Pendulum library. It supports conversion
|
|
178
|
+
to either naive or timezone-aware DateTime objects based on the
|
|
177
179
|
parameters provided.
|
|
178
180
|
|
|
179
181
|
Parameters:
|
|
180
|
-
epoch_int (int | float): The epoch timestamp to convert to a
|
|
182
|
+
epoch_int (int | float): The epoch timestamp to convert to a DateTime
|
|
181
183
|
object. It can be provided as an integer or float value.
|
|
182
|
-
naive (bool): If True, the resulting
|
|
184
|
+
naive (bool): If True, the resulting DateTime object will be naive
|
|
183
185
|
(without timezone information). Defaults to False.
|
|
184
|
-
tz (Optional[str]): The timezone in which the resulting
|
|
186
|
+
tz (Optional[str]): The timezone in which the resulting DateTime object
|
|
185
187
|
should be created. If not provided, the system's default timezone
|
|
186
188
|
will be used.
|
|
187
189
|
|
|
188
190
|
Returns:
|
|
189
|
-
|
|
191
|
+
DateTime: A DateTime object representing the converted epoch timestamp.
|
|
190
192
|
"""
|
|
191
193
|
|
|
192
194
|
# We force the timezone to the user's local timezone if none was supplied
|
|
@@ -200,18 +202,18 @@ def epoch_to_datetime(epoch_int: int | float, naive: bool = False,
|
|
|
200
202
|
return pendulum.from_timestamp(int(epoch_int), tz=tz)
|
|
201
203
|
|
|
202
204
|
|
|
203
|
-
def epoch_to_utc_datetime(epoch_int: int | float | str) ->
|
|
205
|
+
def epoch_to_utc_datetime(epoch_int: int | float | str) -> DateTime:
|
|
204
206
|
"""
|
|
205
|
-
Converts an epoch timestamp to a UTC
|
|
207
|
+
Converts an epoch timestamp to a UTC DateTime object.
|
|
206
208
|
|
|
207
209
|
This function takes an integer or float representing an epoch timestamp,
|
|
208
|
-
and converts it to a
|
|
210
|
+
and converts it to a DateTime object in UTC timezone using Pendulum.
|
|
209
211
|
|
|
210
212
|
Parameters:
|
|
211
213
|
epoch_int: An epoch timestamp represented as an integer or float.
|
|
212
214
|
|
|
213
215
|
Returns:
|
|
214
|
-
A
|
|
216
|
+
A DateTime object in UTC corresponding to the provided epoch timestamp.
|
|
215
217
|
"""
|
|
216
218
|
return pendulum.from_timestamp(int(epoch_int), tz=UTC_TZ)
|
|
217
219
|
|
|
@@ -223,7 +225,7 @@ def is_office_hours_in_timezone(epoch_int: int | float | str, tz: str | None = N
|
|
|
223
225
|
|
|
224
226
|
Office hours are considered to be between 08:00 and 17:00 (8 AM to 5 PM) in
|
|
225
227
|
the specified timezone. The function converts the provided epoch timestamp into
|
|
226
|
-
a
|
|
228
|
+
a DateTime object according to the given timezone and checks whether the time falls
|
|
227
229
|
within the defined office hours.
|
|
228
230
|
|
|
229
231
|
Parameters:
|
|
@@ -248,7 +250,7 @@ def is_office_hours_in_timezone(epoch_int: int | float | str, tz: str | None = N
|
|
|
248
250
|
|
|
249
251
|
|
|
250
252
|
def get_datetime_from_ordinal_and_sentinel(
|
|
251
|
-
sentinel:
|
|
253
|
+
sentinel: DateTimeLike | None = None) -> Callable[[int], DateTime]:
|
|
252
254
|
"""
|
|
253
255
|
Given an ordinal year day, and a sentinel datetime, get the closest past
|
|
254
256
|
datetime to the sentinel that had the given ordinal year day.
|
|
@@ -258,19 +260,20 @@ def get_datetime_from_ordinal_and_sentinel(
|
|
|
258
260
|
"""
|
|
259
261
|
# Check timezone awareness
|
|
260
262
|
naive = sentinel.tzinfo is None
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
sentinel = pendulum.instance(sentinel)
|
|
264
|
+
if naive:
|
|
265
|
+
sentinel = sentinel.naive()
|
|
266
|
+
sentinel_doy = sentinel.day_of_year
|
|
267
|
+
sentinel_year = sentinel.year
|
|
265
268
|
|
|
266
269
|
if naive:
|
|
267
270
|
this_year = pendulum.naive(sentinel_year, 1, 1)
|
|
268
271
|
last_year = pendulum.naive(sentinel_year - 1, 1, 1)
|
|
269
272
|
else:
|
|
270
|
-
this_year = pendulum.datetime(sentinel_year, 1, 1, tz=
|
|
271
|
-
last_year = pendulum.datetime(sentinel_year - 1, 1, 1, tz=
|
|
273
|
+
this_year = pendulum.datetime(sentinel_year, 1, 1, tz=sentinel.timezone)
|
|
274
|
+
last_year = pendulum.datetime(sentinel_year - 1, 1, 1, tz=sentinel.timezone)
|
|
272
275
|
|
|
273
|
-
def f(ordinal: int) ->
|
|
276
|
+
def f(ordinal: int) -> DateTime:
|
|
274
277
|
dt = this_year if ordinal <= sentinel_doy else last_year
|
|
275
278
|
|
|
276
279
|
# Handle leap year edge case
|
|
@@ -278,7 +281,7 @@ def get_datetime_from_ordinal_and_sentinel(
|
|
|
278
281
|
if naive:
|
|
279
282
|
return pendulum.naive(1970, 1, 1)
|
|
280
283
|
else:
|
|
281
|
-
return pendulum.datetime(1970, 1, 1, tz=
|
|
284
|
+
return pendulum.datetime(1970, 1, 1, tz=sentinel.timezone)
|
|
282
285
|
|
|
283
286
|
result = dt.add(days=ordinal - 1)
|
|
284
287
|
return result
|
|
@@ -287,7 +290,7 @@ def get_datetime_from_ordinal_and_sentinel(
|
|
|
287
290
|
|
|
288
291
|
|
|
289
292
|
# ------------------------------------------------------------------[ Span Functions ]--
|
|
290
|
-
def day_span(pts:
|
|
293
|
+
def day_span(pts: DateTimeLike) -> Tuple[DateTime, DateTime]:
|
|
291
294
|
"""
|
|
292
295
|
Returns the beginning and end of the day passed in.
|
|
293
296
|
begin is inclusive and end is exclusive.
|
|
@@ -300,13 +303,11 @@ def day_span(pts: datetime) -> Tuple[datetime, datetime]:
|
|
|
300
303
|
dt = datetime(2023, 12, 25, 14, 30, 45)
|
|
301
304
|
|
|
302
305
|
start, end = day_span(dt)
|
|
303
|
-
print(type(start)) # <class '
|
|
306
|
+
print(type(start)) # <class 'DateTime.DateTime'>
|
|
304
307
|
|
|
305
308
|
"""
|
|
306
309
|
# Check if input is naive or aware
|
|
307
310
|
naive = pts.tzinfo is None
|
|
308
|
-
|
|
309
|
-
# Convert to Pendulum for easier manipulation
|
|
310
311
|
pdt = pendulum.instance(pts)
|
|
311
312
|
|
|
312
313
|
# Use Pendulum's clean API
|
|
@@ -319,7 +320,7 @@ def day_span(pts: datetime) -> Tuple[datetime, datetime]:
|
|
|
319
320
|
return begin, end
|
|
320
321
|
|
|
321
322
|
|
|
322
|
-
def week_span(wso: int) -> Callable[[
|
|
323
|
+
def week_span(wso: int) -> Callable[[DateTimeLike], Tuple[DateTime, DateTime]]:
|
|
323
324
|
"""
|
|
324
325
|
Given an integer between 1 and 7, return a function that will give the
|
|
325
326
|
start and end dates of the week.
|
|
@@ -339,7 +340,7 @@ def week_span(wso: int) -> Callable[[datetime], Tuple[datetime, datetime]]:
|
|
|
339
340
|
"""
|
|
340
341
|
assert_week_start_date_is_valid(wso)
|
|
341
342
|
|
|
342
|
-
def find_dates(pts:
|
|
343
|
+
def find_dates(pts: DateTimeLike) -> Tuple[DateTime, DateTime]:
|
|
343
344
|
# Check if input is naive or aware
|
|
344
345
|
naive = pts.tzinfo is None
|
|
345
346
|
pdt = pendulum.instance(pts)
|
|
@@ -359,7 +360,7 @@ def week_span(wso: int) -> Callable[[datetime], Tuple[datetime, datetime]]:
|
|
|
359
360
|
return find_dates
|
|
360
361
|
|
|
361
362
|
|
|
362
|
-
def month_span(mso: int) -> Callable[[
|
|
363
|
+
def month_span(mso: int) -> Callable[[DateTimeLike], Tuple[DateTime, DateTime]]:
|
|
363
364
|
"""
|
|
364
365
|
Given an integer between 1 and 28, return a function that will give the
|
|
365
366
|
start and end dates of the custom month period.
|
|
@@ -379,7 +380,7 @@ def month_span(mso: int) -> Callable[[datetime], Tuple[datetime, datetime]]:
|
|
|
379
380
|
"""
|
|
380
381
|
assert_month_start_date_is_valid(mso)
|
|
381
382
|
|
|
382
|
-
def find_dates(pts:
|
|
383
|
+
def find_dates(pts: DateTimeLike) -> Tuple[DateTime, DateTime]:
|
|
383
384
|
# Convert to Pendulum
|
|
384
385
|
naive = pts.tzinfo is None
|
|
385
386
|
pdt = pendulum.instance(pts)
|
|
@@ -403,22 +404,22 @@ def month_span(mso: int) -> Callable[[datetime], Tuple[datetime, datetime]]:
|
|
|
403
404
|
return find_dates
|
|
404
405
|
|
|
405
406
|
|
|
406
|
-
def arb_span(dates: Sequence[str |
|
|
407
|
-
[Any], Tuple[
|
|
407
|
+
def arb_span(dates: Sequence[str | DateTimeLike], naive: bool = False) -> Callable[
|
|
408
|
+
[Any], Tuple[DateTime, DateTime]]:
|
|
408
409
|
"""
|
|
409
410
|
Parses two given dates and returns a callable function that provides the date range
|
|
410
411
|
as a tuple of datetime objects. The function ensures the date range is valid and
|
|
411
412
|
always returns the earlier date as the start and the later date as the end.
|
|
412
413
|
|
|
413
414
|
Parameters:
|
|
414
|
-
dates (Sequence[str |
|
|
415
|
+
dates (Sequence[str | DateTimeLike]): A sequence containing exactly two dates where
|
|
415
416
|
each date is either a string or a datetime object.
|
|
416
417
|
naive (bool): Optional flag. If True, the returned datetime objects will not
|
|
417
418
|
have timezone information (naive datetime). Defaults to False.
|
|
418
419
|
|
|
419
420
|
Returns:
|
|
420
|
-
Callable[[Any], Tuple[
|
|
421
|
-
returns a tuple of
|
|
421
|
+
Callable[[Any], Tuple[DateTime, DateTime]]: A function that, when invoked,
|
|
422
|
+
returns a tuple of DateTime objects (start, end) representing the date range.
|
|
422
423
|
|
|
423
424
|
Raises:
|
|
424
425
|
DateUtilsError: If the provided dates are invalid, identical, or there's an error
|
|
@@ -466,9 +467,9 @@ def arb_span(dates: Sequence[str | datetime], naive: bool = False) -> Callable[
|
|
|
466
467
|
except Exception as ex:
|
|
467
468
|
raise DateUtilsError(f"Error parsing dates: {ex}")
|
|
468
469
|
|
|
469
|
-
def find_dates(*args) -> Tuple[
|
|
470
|
+
def find_dates(*args) -> Tuple[DateTime, DateTime]:
|
|
470
471
|
"""
|
|
471
|
-
:return: tuple of
|
|
472
|
+
:return: tuple of DateTime objects (start, end)
|
|
472
473
|
"""
|
|
473
474
|
if naive:
|
|
474
475
|
return begin.naive(), end.naive()
|
|
@@ -478,9 +479,9 @@ def arb_span(dates: Sequence[str | datetime], naive: bool = False) -> Callable[
|
|
|
478
479
|
|
|
479
480
|
|
|
480
481
|
def unroll_span_func(
|
|
481
|
-
f: Callable[[
|
|
482
|
-
cover:
|
|
483
|
-
) -> Tuple[List[
|
|
482
|
+
f: Callable[[DateTimeLike], Tuple[DateTime, DateTime]],
|
|
483
|
+
cover: DateTimeLike | None = None,
|
|
484
|
+
) -> Tuple[List[DateTime], List[int], List[str], DateTime, DateTime]:
|
|
484
485
|
"""
|
|
485
486
|
Generate keys for a date range based on a provided function.
|
|
486
487
|
|
|
@@ -490,14 +491,14 @@ def unroll_span_func(
|
|
|
490
491
|
|
|
491
492
|
Args:
|
|
492
493
|
f: Function that takes a base date and returns a tuple of start and end dates.
|
|
493
|
-
cover: Base
|
|
494
|
+
cover: Base datetime for computing the range. Defaults to the current date if None.
|
|
494
495
|
|
|
495
496
|
Returns:
|
|
496
497
|
A tuple containing:
|
|
497
|
-
- List of
|
|
498
|
+
- List of DateTime objects.
|
|
498
499
|
- List of ordinal day integers.
|
|
499
|
-
- Start date of the range (as
|
|
500
|
-
- End date of the range (as
|
|
500
|
+
- Start date of the range (as DateTime).
|
|
501
|
+
- End date of the range (as DateTime).
|
|
501
502
|
If ord_ints_only is True, returns (ordinal_days, start, end, iso_dates).
|
|
502
503
|
|
|
503
504
|
Raises:
|
|
@@ -507,15 +508,13 @@ def unroll_span_func(
|
|
|
507
508
|
naive = cover.tzinfo is None
|
|
508
509
|
try:
|
|
509
510
|
start, end = f(cover)
|
|
511
|
+
start = pendulum.instance(start)
|
|
512
|
+
start = start.naive() if naive else start
|
|
513
|
+
end = pendulum.instance(end)
|
|
514
|
+
end = end.naive() if naive else end
|
|
510
515
|
except Exception as e:
|
|
511
516
|
raise DateUtilsError(f"Function f failed to compute date range: {str(e)}")
|
|
512
517
|
|
|
513
|
-
# Make sure we can use pendulum with these dates
|
|
514
|
-
start = pendulum.instance(start) if isinstance(start, datetime) else start
|
|
515
|
-
start = start.naive() if naive else start
|
|
516
|
-
end = pendulum.instance(end) if isinstance(end, datetime) else end
|
|
517
|
-
end = end.naive() if naive else end
|
|
518
|
-
|
|
519
518
|
try:
|
|
520
519
|
# Generate date range using pendulum.interval
|
|
521
520
|
# The absolute kwarg ensures that we do not have to care about dates passed
|
|
@@ -536,8 +535,8 @@ def unroll_span_func(
|
|
|
536
535
|
|
|
537
536
|
|
|
538
537
|
def keys_for_span_func(
|
|
539
|
-
f: Callable[[
|
|
540
|
-
cover:
|
|
538
|
+
f: Callable[[DateTimeLike], Tuple[DateTime, DateTime]],
|
|
539
|
+
cover: DateTimeLike | None = None,
|
|
541
540
|
key_in_format: str = "ODIN_{}",
|
|
542
541
|
key_out_format: str = "ODOUT_{}",
|
|
543
542
|
):
|
|
@@ -553,8 +552,8 @@ def keys_for_span_func(
|
|
|
553
552
|
Returns:
|
|
554
553
|
- List of input keys (empty if key_in_format is None).
|
|
555
554
|
- List of output keys (empty if key_out_format is None).
|
|
556
|
-
- Start date of the range (as
|
|
557
|
-
- End date of the range (as
|
|
555
|
+
- Start date of the range (as DateTime).
|
|
556
|
+
- End date of the range (as DateTime).
|
|
558
557
|
|
|
559
558
|
Raises:
|
|
560
559
|
DateUtilsError: If the date range cannot be processed.
|
|
@@ -565,8 +564,8 @@ def keys_for_span_func(
|
|
|
565
564
|
return keys_in, keys_out, start, end
|
|
566
565
|
|
|
567
566
|
|
|
568
|
-
def calendar_month_start_end(date_in_month:
|
|
569
|
-
|
|
567
|
+
def calendar_month_start_end(date_in_month: DateTimeLike | None = None) -> Tuple[
|
|
568
|
+
DateTime, DateTime]:
|
|
570
569
|
naive = date_in_month.tzinfo is None
|
|
571
570
|
|
|
572
571
|
if date_in_month is None:
|
|
@@ -593,7 +592,7 @@ def unix_timestamp() -> int:
|
|
|
593
592
|
return round(time.time())
|
|
594
593
|
|
|
595
594
|
|
|
596
|
-
def sentinel_date_and_ordinal_to_date(sentinel_date:
|
|
595
|
+
def sentinel_date_and_ordinal_to_date(sentinel_date: DateTimeLike | date,
|
|
597
596
|
ordinal: int | float | str) -> date:
|
|
598
597
|
"""Convert sentinel date and ordinal day to actual date"""
|
|
599
598
|
year = sentinel_date.year
|
|
@@ -620,13 +619,13 @@ def standard_tz_timestring(ts: int | float, tz: str = ZA_TZ) -> str:
|
|
|
620
619
|
Format timestamp as: 2022-02-22 15:28:10 (SAST)
|
|
621
620
|
:param ts: Seconds since epoch
|
|
622
621
|
:param tz: Timezone string
|
|
623
|
-
:return: Formatted
|
|
622
|
+
:return: Formatted date time string
|
|
624
623
|
"""
|
|
625
624
|
dt = pendulum.from_timestamp(int(ts), tz=tz)
|
|
626
625
|
return dt.strftime("%Y-%m-%d %H:%M:%S (%Z)")
|
|
627
626
|
|
|
628
627
|
|
|
629
|
-
def get_notice_end_date(given_date:
|
|
628
|
+
def get_notice_end_date(given_date: DateTimeLike | date | Date | None = None) -> Date:
|
|
630
629
|
"""
|
|
631
630
|
A notice end date is the end of the month of the given date if the given date
|
|
632
631
|
is before or on the 15th. If the given date is after the 15th, the notice period
|
|
@@ -650,11 +649,13 @@ def get_notice_end_date(given_date: datetime | date | None = None) -> date:
|
|
|
650
649
|
# End of next month
|
|
651
650
|
end_date = pdt.add(months=2).start_of('month')
|
|
652
651
|
|
|
652
|
+
if isinstance(end_date, DateTime):
|
|
653
|
+
return end_date.date()
|
|
653
654
|
return end_date
|
|
654
655
|
|
|
655
656
|
|
|
656
|
-
def dt_to_za_time_string(v:
|
|
657
|
-
"""Convert
|
|
657
|
+
def dt_to_za_time_string(v: DateTimeLike) -> str:
|
|
658
|
+
"""Convert DateTime to South Africa time string"""
|
|
658
659
|
# Convert to Pendulum
|
|
659
660
|
naive = v.tzinfo is None
|
|
660
661
|
if naive:
|
|
@@ -674,24 +675,24 @@ def months_ago_selection() -> List[Tuple[int, str]]:
|
|
|
674
675
|
]
|
|
675
676
|
|
|
676
677
|
|
|
677
|
-
def is_aware(dt:
|
|
678
|
-
"""Check if a
|
|
678
|
+
def is_aware(dt: DateTimeLike | Date | date) -> bool:
|
|
679
|
+
"""Check if a DateTime object is timezone-aware."""
|
|
679
680
|
return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
|
|
680
681
|
|
|
681
682
|
|
|
682
|
-
def make_aware(dt:
|
|
683
|
+
def make_aware(dt: DateTimeLike | date | Date | None, tz: str = None) -> DateTime | Date | None:
|
|
683
684
|
"""
|
|
684
|
-
Convert a naive
|
|
685
|
+
Convert a naive DateTime to a timezone-aware DateTime using Pendulum.
|
|
685
686
|
|
|
686
687
|
Args:
|
|
687
|
-
dt: The
|
|
688
|
+
dt: The DateTime object to convert. If None, returns None.
|
|
688
689
|
tz: The timezone to apply (default: The user's default timezone).).
|
|
689
690
|
|
|
690
691
|
Returns:
|
|
691
|
-
A timezone-aware
|
|
692
|
+
A timezone-aware DateTime object.
|
|
692
693
|
|
|
693
694
|
Raises:
|
|
694
|
-
TypeError: If dt is not a
|
|
695
|
+
TypeError: If dt is not a DateTime object or None.
|
|
695
696
|
ValueError: If dt is already timezone-aware.
|
|
696
697
|
DateUtilsError: If the timezone string is invalid.
|
|
697
698
|
"""
|
|
@@ -714,8 +715,8 @@ def make_aware(dt: datetime | None, tz: str = None) -> datetime | None:
|
|
|
714
715
|
raise DateUtilsError(f"Invalid timezone: {tz}") from e
|
|
715
716
|
|
|
716
717
|
|
|
717
|
-
def unaware_to_utc_aware(dt:
|
|
718
|
-
"""Convert naive
|
|
718
|
+
def unaware_to_utc_aware(dt: DateTimeLike | date | Date | None) -> DateTime | Date | None:
|
|
719
|
+
"""Convert naive DateTime to UTC-aware DateTime using Pendulum."""
|
|
719
720
|
if not isinstance(dt, (datetime, type(None))):
|
|
720
721
|
raise TypeError(f"Expected datetime or None, got {type(dt)}")
|
|
721
722
|
|
none_shall_parse/strings.py
CHANGED
|
@@ -246,3 +246,22 @@ def generate_random_password(n: int = 10) -> str:
|
|
|
246
246
|
):
|
|
247
247
|
break
|
|
248
248
|
return password
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def generate_crypto_password(n: int = 32) -> str:
|
|
252
|
+
"""
|
|
253
|
+
Generates a cryptographically secure password string.
|
|
254
|
+
|
|
255
|
+
This function uses the `secrets` module to generate a cryptographically
|
|
256
|
+
secure random string with a specified length. The default length of
|
|
257
|
+
the password is 32 characters.
|
|
258
|
+
|
|
259
|
+
Parameters:
|
|
260
|
+
n: int, optional
|
|
261
|
+
Length of the password string. Defaults to 32.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
str
|
|
265
|
+
A cryptographically secure randomly generated password string.
|
|
266
|
+
"""
|
|
267
|
+
return secrets.token_urlsafe(n)
|
none_shall_parse/types.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
from datetime import datetime, date
|
|
1
2
|
from typing import Protocol, Sequence, Tuple, Union, TypeVar
|
|
2
3
|
|
|
4
|
+
from pendulum import DateTime, Date
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
class StringLike(Protocol):
|
|
5
8
|
"""
|
|
@@ -29,4 +32,10 @@ class StringLike(Protocol):
|
|
|
29
32
|
|
|
30
33
|
ChoicesType = Sequence[Tuple[Union[int, str], StringLike]]
|
|
31
34
|
|
|
35
|
+
DateLike = Union[Date, date]
|
|
36
|
+
|
|
37
|
+
DateTimeLike = Union[DateTime, datetime]
|
|
38
|
+
|
|
39
|
+
DateTimeOrDateLike = Union[DateTimeLike, DateLike]
|
|
40
|
+
|
|
32
41
|
T = TypeVar("T")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: none-shall-parse
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
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>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
none_shall_parse/__init__.py,sha256=CTi08pRGuTem3KhOAKP_hO1oBfMzEHZymDhn4jIH0tU,3833
|
|
2
|
+
none_shall_parse/dates.py,sha256=DRgVVAFUOHj42nIiXuMYrwOtCEsf6qz1eU0y8eP6q9o,26661
|
|
3
|
+
none_shall_parse/imeis.py,sha256=20pONoUhLKomZxAJegqSSjG72hZjYs60r8IcaRt-15M,6770
|
|
4
|
+
none_shall_parse/lists.py,sha256=buAahex2iOYXZIcGOFfE9y9BYgBgvo3RilIiv1BALJ8,1706
|
|
5
|
+
none_shall_parse/parse.py,sha256=77bXZAtwFksRwuZ9Ax0lPxEjFpyjkQBqRa5mBc1WkF4,6843
|
|
6
|
+
none_shall_parse/strings.py,sha256=F7491CJAHJjL7vdEGwoH_4S6PjaovYUS_yzVGJ-bYIE,8463
|
|
7
|
+
none_shall_parse/types.py,sha256=WAgILMtW2_fm9MBpUuQvq68yXYBNd3rnSoQk70ibOd4,1320
|
|
8
|
+
none_shall_parse-0.4.4.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
|
|
9
|
+
none_shall_parse-0.4.4.dist-info/METADATA,sha256=-Pw5_aWiUij5rWPwdfs9_pheW1H3XMgbwZtEUZ4-R_k,1701
|
|
10
|
+
none_shall_parse-0.4.4.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
none_shall_parse/__init__.py,sha256=H0klyzI4jgdeIfMfHZ68Uf8a6-d4bQ_SxNYDJdRuwq8,3713
|
|
2
|
-
none_shall_parse/dates.py,sha256=aoOlpzHynnO8HpMQxQteY1XunHPR6KzbZQgq9121JDE,26461
|
|
3
|
-
none_shall_parse/imeis.py,sha256=20pONoUhLKomZxAJegqSSjG72hZjYs60r8IcaRt-15M,6770
|
|
4
|
-
none_shall_parse/lists.py,sha256=buAahex2iOYXZIcGOFfE9y9BYgBgvo3RilIiv1BALJ8,1706
|
|
5
|
-
none_shall_parse/parse.py,sha256=77bXZAtwFksRwuZ9Ax0lPxEjFpyjkQBqRa5mBc1WkF4,6843
|
|
6
|
-
none_shall_parse/strings.py,sha256=Eqrl8Sb-wOzjTu1_bbO-ALljlDKVa-1LcpcACqOmZuE,7931
|
|
7
|
-
none_shall_parse/types.py,sha256=PsljcR1UyyZZizm50wgyZPRNaeYvInSQoPS3i0RLgKo,1123
|
|
8
|
-
none_shall_parse-0.4.2.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
|
|
9
|
-
none_shall_parse-0.4.2.dist-info/METADATA,sha256=qZHJQtePY3isk7DF4smvxsoftlG5kZyrDlXsa88dLJw,1701
|
|
10
|
-
none_shall_parse-0.4.2.dist-info/RECORD,,
|
|
File without changes
|