encommon 0.10.0__py3-none-any.whl → 0.11.1__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.
- encommon/config/__init__.py +3 -3
- encommon/config/config.py +19 -7
- encommon/config/files.py +3 -3
- encommon/config/logger.py +39 -7
- encommon/config/params.py +21 -1
- encommon/config/paths.py +2 -2
- encommon/config/test/test_logger.py +4 -1
- encommon/config/test/{test_common.py → test_utils.py} +3 -3
- encommon/config/{common.py → utils.py} +1 -10
- encommon/conftest.py +2 -1
- encommon/crypts/crypts.py +68 -18
- encommon/crypts/params.py +14 -1
- encommon/crypts/test/test_crypts.py +56 -13
- encommon/times/__init__.py +14 -2
- encommon/times/common.py +0 -127
- encommon/times/params.py +155 -0
- encommon/times/parse.py +5 -5
- encommon/times/test/test_params.py +64 -0
- encommon/times/test/test_parse.py +1 -1
- encommon/times/test/test_timer.py +86 -0
- encommon/times/test/test_timers.py +81 -41
- encommon/times/test/{test_common.py → test_utils.py} +3 -3
- encommon/times/test/test_window.py +101 -51
- encommon/times/test/test_windows.py +250 -0
- encommon/times/timer.py +147 -0
- encommon/times/timers.py +217 -130
- encommon/times/times.py +6 -6
- encommon/times/utils.py +148 -0
- encommon/times/window.py +124 -85
- encommon/times/windows.py +472 -0
- encommon/types/notate.py +0 -2
- encommon/utils/__init__.py +2 -2
- encommon/utils/common.py +0 -39
- encommon/utils/files.py +71 -0
- encommon/utils/paths.py +1 -1
- encommon/utils/sample.py +2 -2
- encommon/utils/test/{test_common.py → test_files.py} +2 -2
- encommon/utils/test/test_paths.py +2 -1
- encommon/version.txt +1 -1
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/METADATA +1 -1
- encommon-0.11.1.dist-info/RECORD +73 -0
- encommon-0.10.0.dist-info/RECORD +0 -65
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/LICENSE +0 -0
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/WHEEL +0 -0
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/top_level.txt +0 -0
encommon/times/timers.py
CHANGED
@@ -7,82 +7,98 @@ is permitted, for more information consult the project license file.
|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
+
from copy import deepcopy
|
10
11
|
from sqlite3 import Connection
|
11
12
|
from sqlite3 import connect as SQLite
|
12
13
|
from typing import Optional
|
14
|
+
from typing import TYPE_CHECKING
|
13
15
|
|
14
|
-
from .common import NUMERIC
|
15
16
|
from .common import PARSABLE
|
17
|
+
from .timer import Timer
|
16
18
|
from .times import Times
|
17
19
|
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from .params import TimerParams
|
22
|
+
from .params import TimersParams
|
23
|
+
|
18
24
|
|
19
25
|
|
20
26
|
CACHE_TABLE = (
|
21
27
|
"""
|
22
28
|
create table if not exists
|
23
29
|
{0} (
|
30
|
+
"group" text not null,
|
24
31
|
"unique" text not null,
|
25
32
|
"update" text not null,
|
26
|
-
primary key (
|
33
|
+
primary key (
|
34
|
+
"group", "unique"));
|
27
35
|
""") # noqa: LIT003
|
28
36
|
|
29
37
|
|
30
38
|
|
31
|
-
|
32
|
-
_CACHED = dict[str, Times]
|
39
|
+
TIMERS = dict[str, Timer]
|
33
40
|
|
34
41
|
|
35
42
|
|
36
43
|
class Timers:
|
37
44
|
"""
|
38
|
-
Track timers on unique key
|
45
|
+
Track timers on unique key determining when to proceed.
|
39
46
|
|
40
47
|
.. warning::
|
41
48
|
This class will use an in-memory database for cache,
|
42
49
|
unless a cache file is explicity defined.
|
43
50
|
|
44
51
|
.. testsetup::
|
52
|
+
>>> from .params import TimerParams
|
53
|
+
>>> from .params import TimersParams
|
45
54
|
>>> from time import sleep
|
46
55
|
|
47
56
|
Example
|
48
57
|
-------
|
49
|
-
>>>
|
58
|
+
>>> source = {'one': TimerParams(timer=1)}
|
59
|
+
>>> params = TimersParams(timers=source)
|
60
|
+
>>> timers = Timers(params)
|
50
61
|
>>> timers.ready('one')
|
51
62
|
False
|
52
63
|
>>> sleep(1)
|
53
64
|
>>> timers.ready('one')
|
54
65
|
True
|
55
66
|
|
56
|
-
:param
|
57
|
-
:param file: Optional path to SQLite database
|
58
|
-
|
59
|
-
:param table: Optional override default table name.
|
67
|
+
:param params: Parameters for instantiating the instance.
|
68
|
+
:param file: Optional path to file for SQLite database,
|
69
|
+
allowing for state retention between the executions.
|
70
|
+
:param table: Optional override for default table name.
|
71
|
+
:param group: Optional override for default group name.
|
60
72
|
"""
|
61
73
|
|
62
|
-
|
74
|
+
__params: 'TimersParams'
|
75
|
+
|
63
76
|
__sqlite: Connection
|
64
77
|
__file: str
|
65
78
|
__table: str
|
66
|
-
|
79
|
+
__group: str
|
80
|
+
|
81
|
+
__timers: TIMERS
|
67
82
|
|
68
83
|
|
69
84
|
def __init__(
|
70
85
|
self,
|
71
|
-
|
86
|
+
params: Optional['TimersParams'] = None,
|
87
|
+
*,
|
72
88
|
file: str = ':memory:',
|
73
89
|
table: str = 'timers',
|
90
|
+
group: str = 'default',
|
74
91
|
) -> None:
|
75
92
|
"""
|
76
93
|
Initialize instance for class using provided parameters.
|
77
94
|
"""
|
78
95
|
|
96
|
+
from .params import TimersParams
|
79
97
|
|
80
|
-
|
98
|
+
if params is None:
|
99
|
+
params = TimersParams()
|
81
100
|
|
82
|
-
|
83
|
-
|
84
|
-
for key, value in items:
|
85
|
-
timers[key] = float(value)
|
101
|
+
self.__params = deepcopy(params)
|
86
102
|
|
87
103
|
|
88
104
|
sqlite = SQLite(file)
|
@@ -93,113 +109,71 @@ class Timers:
|
|
93
109
|
|
94
110
|
sqlite.commit()
|
95
111
|
|
96
|
-
|
97
|
-
cached: _CACHED = {}
|
98
|
-
|
99
|
-
for timer in timers:
|
100
|
-
cached[timer] = Times()
|
101
|
-
|
102
|
-
|
103
|
-
self.__config = timers
|
104
112
|
self.__sqlite = sqlite
|
105
113
|
self.__file = file
|
106
114
|
self.__table = table
|
107
|
-
self.
|
115
|
+
self.__group = group
|
116
|
+
|
108
117
|
|
118
|
+
self.__timers = {}
|
109
119
|
|
110
|
-
self.
|
111
|
-
self.save_cache()
|
120
|
+
self.load_children()
|
112
121
|
|
113
122
|
|
114
|
-
|
123
|
+
@property
|
124
|
+
def params(
|
115
125
|
self,
|
116
|
-
) ->
|
126
|
+
) -> 'TimersParams':
|
117
127
|
"""
|
118
|
-
|
119
|
-
"""
|
120
|
-
|
121
|
-
cached = self.__sqlite
|
122
|
-
table = self.__table
|
123
|
-
cachem = self.__cache
|
124
|
-
|
125
|
-
cursor = cached.execute(
|
126
|
-
f'select * from {table}'
|
127
|
-
' order by "unique" asc')
|
128
|
+
Return the Pydantic model containing the configuration.
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
for record in records:
|
132
|
-
|
133
|
-
unique = record[0]
|
134
|
-
update = record[1]
|
135
|
-
|
136
|
-
times = Times(update)
|
130
|
+
:returns: Pydantic model containing the configuration.
|
131
|
+
"""
|
137
132
|
|
138
|
-
|
133
|
+
return self.__params
|
139
134
|
|
140
135
|
|
141
|
-
|
136
|
+
@property
|
137
|
+
def sqlite(
|
142
138
|
self,
|
143
|
-
) ->
|
144
|
-
"""
|
145
|
-
Save the timers cache from the attribute into database.
|
139
|
+
) -> Connection:
|
146
140
|
"""
|
141
|
+
Return the value for the attribute from class instance.
|
147
142
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
cached = self.__sqlite
|
153
|
-
table = self.__table
|
154
|
-
cachem = self.__cache
|
155
|
-
|
156
|
-
|
157
|
-
items = cachem.items()
|
158
|
-
|
159
|
-
for key, value in items:
|
160
|
-
|
161
|
-
append = (key, str(value))
|
162
|
-
|
163
|
-
inserts.append(append)
|
164
|
-
|
165
|
-
|
166
|
-
cached.executemany(
|
167
|
-
(f'replace into {table}'
|
168
|
-
' ("unique", "update")'
|
169
|
-
' values (?, ?)'),
|
170
|
-
tuple(sorted(inserts)))
|
143
|
+
:returns: Value for the attribute from class instance.
|
144
|
+
"""
|
171
145
|
|
172
|
-
|
146
|
+
return self.__sqlite
|
173
147
|
|
174
148
|
|
175
149
|
@property
|
176
|
-
def
|
150
|
+
def file(
|
177
151
|
self,
|
178
|
-
) ->
|
152
|
+
) -> str:
|
179
153
|
"""
|
180
154
|
Return the value for the attribute from class instance.
|
181
155
|
|
182
156
|
:returns: Value for the attribute from class instance.
|
183
157
|
"""
|
184
158
|
|
185
|
-
return
|
159
|
+
return self.__file
|
186
160
|
|
187
161
|
|
188
162
|
@property
|
189
|
-
def
|
163
|
+
def table(
|
190
164
|
self,
|
191
|
-
) ->
|
165
|
+
) -> str:
|
192
166
|
"""
|
193
167
|
Return the value for the attribute from class instance.
|
194
168
|
|
195
169
|
:returns: Value for the attribute from class instance.
|
196
170
|
"""
|
197
171
|
|
198
|
-
return self.
|
172
|
+
return self.__table
|
199
173
|
|
200
174
|
|
201
175
|
@property
|
202
|
-
def
|
176
|
+
def group(
|
203
177
|
self,
|
204
178
|
) -> str:
|
205
179
|
"""
|
@@ -208,33 +182,130 @@ class Timers:
|
|
208
182
|
:returns: Value for the attribute from class instance.
|
209
183
|
"""
|
210
184
|
|
211
|
-
return self.
|
185
|
+
return self.__group
|
212
186
|
|
213
187
|
|
214
188
|
@property
|
215
|
-
def
|
189
|
+
def children(
|
216
190
|
self,
|
217
|
-
) -> str:
|
191
|
+
) -> dict[str, Timer]:
|
218
192
|
"""
|
219
193
|
Return the value for the attribute from class instance.
|
220
194
|
|
221
195
|
:returns: Value for the attribute from class instance.
|
222
196
|
"""
|
223
197
|
|
224
|
-
return self.
|
198
|
+
return dict(self.__timers)
|
225
199
|
|
226
200
|
|
227
|
-
|
228
|
-
def cache(
|
201
|
+
def load_children(
|
229
202
|
self,
|
230
|
-
) ->
|
203
|
+
) -> None:
|
204
|
+
"""
|
205
|
+
Construct the children instances for the primary class.
|
231
206
|
"""
|
232
|
-
Return the value for the attribute from class instance.
|
233
207
|
|
234
|
-
|
208
|
+
params = self.__params
|
209
|
+
timers = self.__timers
|
210
|
+
|
211
|
+
sqlite = self.__sqlite
|
212
|
+
table = self.__table
|
213
|
+
group = self.__group
|
214
|
+
|
215
|
+
|
216
|
+
config = params.timers
|
217
|
+
|
218
|
+
|
219
|
+
cursor = sqlite.execute(
|
220
|
+
f"""
|
221
|
+
select * from {table}
|
222
|
+
where "group"="{group}"
|
223
|
+
order by "unique" asc
|
224
|
+
""") # noqa: LIT003
|
225
|
+
|
226
|
+
records = cursor.fetchall()
|
227
|
+
|
228
|
+
for record in records:
|
229
|
+
|
230
|
+
unique = record[1]
|
231
|
+
update = record[2]
|
232
|
+
|
233
|
+
if unique not in config:
|
234
|
+
continue
|
235
|
+
|
236
|
+
_config = config[unique]
|
237
|
+
|
238
|
+
_config.start = update
|
239
|
+
|
240
|
+
|
241
|
+
items = config.items()
|
242
|
+
|
243
|
+
for key, value in items:
|
244
|
+
|
245
|
+
if key in timers:
|
246
|
+
|
247
|
+
timer = timers[key]
|
248
|
+
|
249
|
+
timer.update(
|
250
|
+
value.start)
|
251
|
+
|
252
|
+
continue
|
253
|
+
|
254
|
+
timer = Timer(
|
255
|
+
value.timer,
|
256
|
+
start=value.start)
|
257
|
+
|
258
|
+
timers[key] = timer
|
259
|
+
|
260
|
+
|
261
|
+
self.__timers = timers
|
262
|
+
|
263
|
+
|
264
|
+
def save_children(
|
265
|
+
self,
|
266
|
+
) -> None:
|
267
|
+
"""
|
268
|
+
Save the child caches from the attribute into database.
|
235
269
|
"""
|
236
270
|
|
237
|
-
|
271
|
+
timers = self.__timers
|
272
|
+
|
273
|
+
sqlite = self.__sqlite
|
274
|
+
table = self.__table
|
275
|
+
group = self.__group
|
276
|
+
|
277
|
+
|
278
|
+
insert = tuple[
|
279
|
+
str, # group
|
280
|
+
str, # unique
|
281
|
+
str] # update
|
282
|
+
|
283
|
+
inserts: list[insert] = []
|
284
|
+
|
285
|
+
items = timers.items()
|
286
|
+
|
287
|
+
for unique, timer in items:
|
288
|
+
|
289
|
+
append = (
|
290
|
+
group, unique,
|
291
|
+
Times('now').subsec)
|
292
|
+
|
293
|
+
inserts.append(append)
|
294
|
+
|
295
|
+
|
296
|
+
statement = (
|
297
|
+
f"""
|
298
|
+
replace into {table}
|
299
|
+
("group", "unique",
|
300
|
+
"update")
|
301
|
+
values (?, ?, ?)
|
302
|
+
""") # noqa: LIT003
|
303
|
+
|
304
|
+
sqlite.executemany(
|
305
|
+
statement,
|
306
|
+
tuple(sorted(inserts)))
|
307
|
+
|
308
|
+
sqlite.commit()
|
238
309
|
|
239
310
|
|
240
311
|
def ready(
|
@@ -245,74 +316,90 @@ class Timers:
|
|
245
316
|
"""
|
246
317
|
Determine whether or not the appropriate time has passed.
|
247
318
|
|
248
|
-
|
249
|
-
For performance reasons, this method will not notice
|
250
|
-
changes within the database unless refreshed first.
|
251
|
-
|
252
|
-
:param unique: Which timer configuration from reference.
|
319
|
+
:param unique: Unique identifier for the related child.
|
253
320
|
:param update: Determines whether or not time is updated.
|
321
|
+
:returns: Boolean indicating whether enough time passed.
|
254
322
|
"""
|
255
323
|
|
256
|
-
|
257
|
-
caches = self.__cache
|
324
|
+
timers = self.__timers
|
258
325
|
|
259
|
-
if unique not in
|
326
|
+
if unique not in timers:
|
260
327
|
raise ValueError('unique')
|
261
328
|
|
262
|
-
|
263
|
-
timer = config[unique]
|
329
|
+
timer = timers[unique]
|
264
330
|
|
265
|
-
ready =
|
331
|
+
ready = timer.ready(update)
|
266
332
|
|
267
|
-
if ready
|
268
|
-
self.
|
333
|
+
if ready is True:
|
334
|
+
self.save_children()
|
269
335
|
|
270
336
|
return ready
|
271
337
|
|
272
338
|
|
339
|
+
def create(
|
340
|
+
self,
|
341
|
+
unique: str,
|
342
|
+
params: 'TimerParams',
|
343
|
+
) -> Timer:
|
344
|
+
"""
|
345
|
+
Create a new timer using the provided input parameters.
|
346
|
+
|
347
|
+
:param unique: Unique identifier for the related child.
|
348
|
+
:param params: Parameters for instantiating the instance.
|
349
|
+
:returns: Newly constructed instance of related class.
|
350
|
+
"""
|
351
|
+
|
352
|
+
timers = self.params.timers
|
353
|
+
|
354
|
+
if unique in timers:
|
355
|
+
raise ValueError('unique')
|
356
|
+
|
357
|
+
timers[unique] = params
|
358
|
+
|
359
|
+
self.load_children()
|
360
|
+
|
361
|
+
self.save_children()
|
362
|
+
|
363
|
+
return self.children[unique]
|
364
|
+
|
365
|
+
|
273
366
|
def update(
|
274
367
|
self,
|
275
368
|
unique: str,
|
276
|
-
|
369
|
+
value: Optional[PARSABLE] = None,
|
277
370
|
) -> None:
|
278
371
|
"""
|
279
|
-
Update the
|
372
|
+
Update the timer from the provided parasable time value.
|
280
373
|
|
281
|
-
:param unique:
|
282
|
-
:param
|
374
|
+
:param unique: Unique identifier for the related child.
|
375
|
+
:param value: Override the time updated for timer value.
|
283
376
|
"""
|
284
377
|
|
285
|
-
|
378
|
+
timers = self.__timers
|
286
379
|
|
287
|
-
if unique not in
|
380
|
+
if unique not in timers:
|
288
381
|
raise ValueError('unique')
|
289
382
|
|
290
|
-
|
383
|
+
timer = timers[unique]
|
291
384
|
|
292
|
-
self.
|
385
|
+
self.save_children()
|
293
386
|
|
387
|
+
return timer.update(value)
|
294
388
|
|
295
|
-
|
389
|
+
|
390
|
+
def delete(
|
296
391
|
self,
|
297
392
|
unique: str,
|
298
|
-
minimum: int | float,
|
299
|
-
started: Optional[PARSABLE] = None,
|
300
393
|
) -> None:
|
301
394
|
"""
|
302
|
-
|
395
|
+
Delete the timer from the internal dictionary reference.
|
303
396
|
|
304
|
-
:param unique:
|
305
|
-
:param minimum: Determine minimum seconds that must pass.
|
306
|
-
:param started: Determine when time starts for the timer.
|
397
|
+
:param unique: Unique identifier for the related child.
|
307
398
|
"""
|
308
399
|
|
309
|
-
|
310
|
-
caches = self.__cache
|
400
|
+
timers = self.__timers
|
311
401
|
|
312
|
-
if unique in
|
402
|
+
if unique not in timers:
|
313
403
|
raise ValueError('unique')
|
314
404
|
|
315
|
-
|
316
|
-
caches[unique] = Times(started)
|
317
|
-
|
318
|
-
self.save_cache()
|
405
|
+
del timers[unique]
|
encommon/times/times.py
CHANGED
@@ -16,10 +16,10 @@ from .common import PARSABLE
|
|
16
16
|
from .common import STAMP_HUMAN
|
17
17
|
from .common import STAMP_SIMPLE
|
18
18
|
from .common import STAMP_SUBSEC
|
19
|
-
from .common import findtz
|
20
|
-
from .common import strftime
|
21
19
|
from .parse import parse_time
|
22
20
|
from .parse import since_time
|
21
|
+
from .utils import findtz
|
22
|
+
from .utils import strftime
|
23
23
|
|
24
24
|
|
25
25
|
|
@@ -348,9 +348,9 @@ class Times:
|
|
348
348
|
self,
|
349
349
|
) -> float:
|
350
350
|
"""
|
351
|
-
Determine the time in seconds
|
351
|
+
Determine the time in seconds occurring since instance.
|
352
352
|
|
353
|
-
:returns: Time in seconds
|
353
|
+
:returns: Time in seconds occurring since the instance.
|
354
354
|
"""
|
355
355
|
|
356
356
|
return since_time(self.__source)
|
@@ -361,9 +361,9 @@ class Times:
|
|
361
361
|
self,
|
362
362
|
) -> float:
|
363
363
|
"""
|
364
|
-
Determine the time in seconds
|
364
|
+
Determine the time in seconds occurring since instance.
|
365
365
|
|
366
|
-
:returns: Time in seconds
|
366
|
+
:returns: Time in seconds occurring since the instance.
|
367
367
|
"""
|
368
368
|
|
369
369
|
return since_time(self.__source)
|
encommon/times/utils.py
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
"""
|
2
|
+
Functions and routines associated with Enasis Network Common Library.
|
3
|
+
|
4
|
+
This file is part of Enasis Network software eco-system. Distribution
|
5
|
+
is permitted, for more information consult the project license file.
|
6
|
+
"""
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
from contextlib import suppress
|
11
|
+
from datetime import datetime
|
12
|
+
from datetime import timezone
|
13
|
+
from datetime import tzinfo
|
14
|
+
from typing import Any
|
15
|
+
from typing import Optional
|
16
|
+
|
17
|
+
from dateutil.tz import gettz
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
def findtz(
|
22
|
+
tzname: Optional[str] = None,
|
23
|
+
) -> tzinfo:
|
24
|
+
"""
|
25
|
+
Return the located timezone object for the provided name.
|
26
|
+
|
27
|
+
Example
|
28
|
+
-------
|
29
|
+
>>> findtz('US/Central')
|
30
|
+
tzfile('/usr/share/zoneinfo/US/Central')
|
31
|
+
|
32
|
+
:param tzname: Name of the timezone associated to source.
|
33
|
+
:returns: Located timezone object for the provided name.
|
34
|
+
"""
|
35
|
+
|
36
|
+
if tzname is None:
|
37
|
+
return timezone.utc
|
38
|
+
|
39
|
+
tzinfo = gettz(tzname)
|
40
|
+
|
41
|
+
if tzinfo is None:
|
42
|
+
raise ValueError('tzname')
|
43
|
+
|
44
|
+
return tzinfo
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
def utcdatetime(
|
49
|
+
*args: Any,
|
50
|
+
**kwargs: Any,
|
51
|
+
) -> datetime:
|
52
|
+
"""
|
53
|
+
Return the instance of datetime within the UTC timezone.
|
54
|
+
|
55
|
+
.. warning::
|
56
|
+
If no arguments are provided, returns current time.
|
57
|
+
|
58
|
+
Example
|
59
|
+
-------
|
60
|
+
>>> utcdatetime(1970, 1, 1)
|
61
|
+
datetime.datetime(1970, 1, 1, 0...
|
62
|
+
|
63
|
+
:param args: Positional arguments passed for downstream.
|
64
|
+
:param kwargs: Keyword arguments passed for downstream.
|
65
|
+
:returns: Instance of datetime within the UTC timezone.
|
66
|
+
"""
|
67
|
+
|
68
|
+
tzinfo = timezone.utc
|
69
|
+
|
70
|
+
if not args and not kwargs:
|
71
|
+
return datetime.now(tz=tzinfo)
|
72
|
+
|
73
|
+
if 'tzinfo' not in kwargs:
|
74
|
+
kwargs['tzinfo'] = tzinfo
|
75
|
+
|
76
|
+
return (
|
77
|
+
datetime(*args, **kwargs)
|
78
|
+
.astimezone(timezone.utc))
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
def strptime(
|
83
|
+
source: str,
|
84
|
+
formats: str | list[str],
|
85
|
+
) -> datetime:
|
86
|
+
"""
|
87
|
+
Parse provided time value with various supported formats.
|
88
|
+
|
89
|
+
Example
|
90
|
+
-------
|
91
|
+
>>> strptime('2023', '%Y')
|
92
|
+
datetime.datetime(2023, 1, 1, 0...
|
93
|
+
|
94
|
+
:param source: Time in various forms that will be parsed.
|
95
|
+
:param formats: Various formats compatable with strptime.
|
96
|
+
:returns: Python datetime object containing related time.
|
97
|
+
"""
|
98
|
+
|
99
|
+
tzinfo = timezone.utc
|
100
|
+
|
101
|
+
if isinstance(formats, str):
|
102
|
+
formats = [formats]
|
103
|
+
|
104
|
+
|
105
|
+
def _strptime(
|
106
|
+
format: str,
|
107
|
+
) -> datetime:
|
108
|
+
|
109
|
+
return (
|
110
|
+
datetime
|
111
|
+
.strptime(source, format)
|
112
|
+
.astimezone(tzinfo))
|
113
|
+
|
114
|
+
|
115
|
+
for format in formats:
|
116
|
+
|
117
|
+
with suppress(ValueError):
|
118
|
+
return _strptime(format)
|
119
|
+
|
120
|
+
|
121
|
+
raise ValueError('invalid')
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
def strftime(
|
126
|
+
source: datetime,
|
127
|
+
format: str,
|
128
|
+
) -> str:
|
129
|
+
"""
|
130
|
+
Return the timestamp string for datetime object provided.
|
131
|
+
|
132
|
+
.. note::
|
133
|
+
This function is extremely pedantic and cosmetic.
|
134
|
+
|
135
|
+
Example
|
136
|
+
-------
|
137
|
+
>>> dtime = datetime(2023, 1, 1)
|
138
|
+
>>> strftime(dtime, '%Y')
|
139
|
+
'2023'
|
140
|
+
|
141
|
+
:param source: Python datetime instance containing source.
|
142
|
+
:param format: Format for the timestamp string returned.
|
143
|
+
:returns: Timestamp string for datetime object provided.
|
144
|
+
"""
|
145
|
+
|
146
|
+
return (
|
147
|
+
datetime
|
148
|
+
.strftime(source, format))
|