encommon 0.9.0__py3-none-any.whl → 0.11.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.
- encommon/config/__init__.py +3 -3
- encommon/config/config.py +28 -2
- encommon/config/files.py +3 -3
- encommon/config/logger.py +37 -6
- encommon/config/params.py +24 -4
- encommon/config/paths.py +2 -2
- encommon/config/test/test_logger.py +3 -0
- encommon/config/test/{test_common.py → test_utils.py} +3 -3
- encommon/config/{common.py → utils.py} +1 -10
- encommon/conftest.py +4 -4
- encommon/crypts/crypts.py +23 -22
- encommon/crypts/params.py +15 -2
- encommon/crypts/test/test_crypts.py +8 -20
- 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 +87 -36
- 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 +264 -0
- encommon/times/timer.py +147 -0
- encommon/times/timers.py +207 -133
- encommon/times/times.py +6 -6
- encommon/times/utils.py +148 -0
- encommon/times/window.py +124 -85
- encommon/times/windows.py +459 -0
- encommon/types/__init__.py +6 -0
- encommon/types/notate.py +319 -0
- encommon/types/test/__init__.py +37 -0
- encommon/types/test/test_dicts.py +23 -28
- encommon/types/test/test_notate.py +217 -0
- 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.9.0.dist-info → encommon-0.11.0.dist-info}/METADATA +1 -1
- encommon-0.11.0.dist-info/RECORD +73 -0
- encommon-0.9.0.dist-info/RECORD +0 -63
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/LICENSE +0 -0
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/WHEEL +0 -0
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,459 @@
|
|
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 sqlite3 import Connection
|
11
|
+
from sqlite3 import connect as SQLite
|
12
|
+
from typing import Optional
|
13
|
+
from typing import TYPE_CHECKING
|
14
|
+
|
15
|
+
from .common import PARSABLE
|
16
|
+
from .times import Times
|
17
|
+
from .window import Window
|
18
|
+
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from .params import WindowParams
|
21
|
+
from .params import WindowsParams
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
CACHE_TABLE = (
|
26
|
+
"""
|
27
|
+
create table if not exists
|
28
|
+
{0} (
|
29
|
+
"group" text not null,
|
30
|
+
"unique" text not null,
|
31
|
+
"last" text not null,
|
32
|
+
"next" text not null,
|
33
|
+
"update" text not null,
|
34
|
+
primary key (
|
35
|
+
"group", "unique"));
|
36
|
+
""") # noqa: LIT003
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
WINDOWS = dict[str, Window]
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
class Windows:
|
45
|
+
"""
|
46
|
+
Track windows on unique key determining when to proceed.
|
47
|
+
|
48
|
+
.. warning::
|
49
|
+
This class will use an in-memory database for cache,
|
50
|
+
unless a cache file is explicity defined.
|
51
|
+
|
52
|
+
.. testsetup::
|
53
|
+
>>> from .params import WindowParams
|
54
|
+
>>> from .params import WindowsParams
|
55
|
+
|
56
|
+
Example
|
57
|
+
-------
|
58
|
+
>>> source = {'one': WindowParams(window=1)}
|
59
|
+
>>> params = WindowsParams(windows=source)
|
60
|
+
>>> windows = Windows(params, '-2s', 'now')
|
61
|
+
>>> [windows.ready('one') for x in range(3)]
|
62
|
+
[True, True, False]
|
63
|
+
|
64
|
+
:param params: Parameters for instantiating the instance.
|
65
|
+
:param start: Determine the start for scheduling window.
|
66
|
+
:param stop: Determine the ending for scheduling window.
|
67
|
+
:param file: Optional path to file for SQLite database,
|
68
|
+
allowing for state retention between the executions.
|
69
|
+
:param table: Optional override for default table name.
|
70
|
+
:param group: Optional override for default group name.
|
71
|
+
"""
|
72
|
+
|
73
|
+
__params: 'WindowsParams'
|
74
|
+
|
75
|
+
__start: Times
|
76
|
+
__stop: Times
|
77
|
+
|
78
|
+
__sqlite: Connection
|
79
|
+
__file: str
|
80
|
+
__table: str
|
81
|
+
__group: str
|
82
|
+
|
83
|
+
__windows: WINDOWS
|
84
|
+
|
85
|
+
|
86
|
+
def __init__( # noqa: CFQ002
|
87
|
+
self,
|
88
|
+
params: 'WindowsParams',
|
89
|
+
start: PARSABLE = 'now',
|
90
|
+
stop: PARSABLE = '3000-01-01',
|
91
|
+
*,
|
92
|
+
file: str = ':memory:',
|
93
|
+
table: str = 'windows',
|
94
|
+
group: str = 'default',
|
95
|
+
) -> None:
|
96
|
+
"""
|
97
|
+
Initialize instance for class using provided parameters.
|
98
|
+
"""
|
99
|
+
|
100
|
+
self.__params = params
|
101
|
+
|
102
|
+
|
103
|
+
start = Times(start)
|
104
|
+
stop = Times(stop)
|
105
|
+
|
106
|
+
assert stop > start
|
107
|
+
|
108
|
+
self.__start = start
|
109
|
+
self.__stop = stop
|
110
|
+
|
111
|
+
|
112
|
+
sqlite = SQLite(file)
|
113
|
+
|
114
|
+
sqlite.execute(
|
115
|
+
CACHE_TABLE
|
116
|
+
.format(table))
|
117
|
+
|
118
|
+
sqlite.commit()
|
119
|
+
|
120
|
+
self.__sqlite = sqlite
|
121
|
+
self.__file = file
|
122
|
+
self.__table = table
|
123
|
+
self.__group = group
|
124
|
+
|
125
|
+
|
126
|
+
self.__windows = {}
|
127
|
+
|
128
|
+
self.load_children()
|
129
|
+
|
130
|
+
|
131
|
+
@property
|
132
|
+
def params(
|
133
|
+
self,
|
134
|
+
) -> 'WindowsParams':
|
135
|
+
"""
|
136
|
+
Return the Pydantic model containing the configuration.
|
137
|
+
|
138
|
+
:returns: Pydantic model containing the configuration.
|
139
|
+
"""
|
140
|
+
|
141
|
+
return self.__params
|
142
|
+
|
143
|
+
|
144
|
+
@property
|
145
|
+
def start(
|
146
|
+
self,
|
147
|
+
) -> Times:
|
148
|
+
"""
|
149
|
+
Return the value for the attribute from class instance.
|
150
|
+
|
151
|
+
:returns: Value for the attribute from class instance.
|
152
|
+
"""
|
153
|
+
|
154
|
+
return Times(self.__start)
|
155
|
+
|
156
|
+
|
157
|
+
@property
|
158
|
+
def stop(
|
159
|
+
self,
|
160
|
+
) -> Times:
|
161
|
+
"""
|
162
|
+
Return the value for the attribute from class instance.
|
163
|
+
|
164
|
+
:returns: Value for the attribute from class instance.
|
165
|
+
"""
|
166
|
+
|
167
|
+
return Times(self.__stop)
|
168
|
+
|
169
|
+
|
170
|
+
@property
|
171
|
+
def sqlite(
|
172
|
+
self,
|
173
|
+
) -> Connection:
|
174
|
+
"""
|
175
|
+
Return the value for the attribute from class instance.
|
176
|
+
|
177
|
+
:returns: Value for the attribute from class instance.
|
178
|
+
"""
|
179
|
+
|
180
|
+
return self.__sqlite
|
181
|
+
|
182
|
+
|
183
|
+
@property
|
184
|
+
def file(
|
185
|
+
self,
|
186
|
+
) -> str:
|
187
|
+
"""
|
188
|
+
Return the value for the attribute from class instance.
|
189
|
+
|
190
|
+
:returns: Value for the attribute from class instance.
|
191
|
+
"""
|
192
|
+
|
193
|
+
return self.__file
|
194
|
+
|
195
|
+
|
196
|
+
@property
|
197
|
+
def table(
|
198
|
+
self,
|
199
|
+
) -> str:
|
200
|
+
"""
|
201
|
+
Return the value for the attribute from class instance.
|
202
|
+
|
203
|
+
:returns: Value for the attribute from class instance.
|
204
|
+
"""
|
205
|
+
|
206
|
+
return self.__table
|
207
|
+
|
208
|
+
|
209
|
+
@property
|
210
|
+
def group(
|
211
|
+
self,
|
212
|
+
) -> str:
|
213
|
+
"""
|
214
|
+
Return the value for the attribute from class instance.
|
215
|
+
|
216
|
+
:returns: Value for the attribute from class instance.
|
217
|
+
"""
|
218
|
+
|
219
|
+
return self.__group
|
220
|
+
|
221
|
+
|
222
|
+
@property
|
223
|
+
def children(
|
224
|
+
self,
|
225
|
+
) -> dict[str, Window]:
|
226
|
+
"""
|
227
|
+
Return the value for the attribute from class instance.
|
228
|
+
|
229
|
+
:returns: Value for the attribute from class instance.
|
230
|
+
"""
|
231
|
+
|
232
|
+
return dict(self.__windows)
|
233
|
+
|
234
|
+
|
235
|
+
def load_children(
|
236
|
+
self,
|
237
|
+
) -> None:
|
238
|
+
"""
|
239
|
+
Construct the children instances for the primary class.
|
240
|
+
"""
|
241
|
+
|
242
|
+
params = self.__params
|
243
|
+
windows = self.__windows
|
244
|
+
|
245
|
+
start = self.__start
|
246
|
+
stop = self.__stop
|
247
|
+
|
248
|
+
sqlite = self.__sqlite
|
249
|
+
table = self.__table
|
250
|
+
group = self.__group
|
251
|
+
|
252
|
+
|
253
|
+
config = params.windows
|
254
|
+
|
255
|
+
|
256
|
+
cursor = sqlite.execute(
|
257
|
+
f"""
|
258
|
+
select * from {table}
|
259
|
+
where "group"="{group}"
|
260
|
+
order by "unique" asc
|
261
|
+
""") # noqa: LIT003
|
262
|
+
|
263
|
+
records = cursor.fetchall()
|
264
|
+
|
265
|
+
for record in records:
|
266
|
+
|
267
|
+
unique = record[1]
|
268
|
+
next = record[3]
|
269
|
+
|
270
|
+
if unique not in config:
|
271
|
+
continue
|
272
|
+
|
273
|
+
_config = config[unique]
|
274
|
+
|
275
|
+
_config.start = next
|
276
|
+
_config.anchor = next
|
277
|
+
|
278
|
+
|
279
|
+
items = config.items()
|
280
|
+
|
281
|
+
for key, value in items:
|
282
|
+
|
283
|
+
if key in windows:
|
284
|
+
|
285
|
+
window = windows[key]
|
286
|
+
|
287
|
+
window.update(
|
288
|
+
value.start)
|
289
|
+
|
290
|
+
continue
|
291
|
+
|
292
|
+
_start = (
|
293
|
+
value.start or start)
|
294
|
+
|
295
|
+
_stop = (
|
296
|
+
value.stop or stop)
|
297
|
+
|
298
|
+
if _start < start:
|
299
|
+
_start = start
|
300
|
+
|
301
|
+
if _stop > stop:
|
302
|
+
_stop = stop
|
303
|
+
|
304
|
+
_anchor = (
|
305
|
+
value.anchor or _start)
|
306
|
+
|
307
|
+
window = Window(
|
308
|
+
value.window,
|
309
|
+
start=_start,
|
310
|
+
stop=_stop,
|
311
|
+
anchor=_anchor,
|
312
|
+
delay=value.delay)
|
313
|
+
|
314
|
+
windows[key] = window
|
315
|
+
|
316
|
+
|
317
|
+
self.__windows = windows
|
318
|
+
|
319
|
+
|
320
|
+
def save_children(
|
321
|
+
self,
|
322
|
+
) -> None:
|
323
|
+
"""
|
324
|
+
Save the child caches from the attribute into database.
|
325
|
+
"""
|
326
|
+
|
327
|
+
windows = self.__windows
|
328
|
+
|
329
|
+
sqlite = self.__sqlite
|
330
|
+
table = self.__table
|
331
|
+
group = self.__group
|
332
|
+
|
333
|
+
|
334
|
+
insert = tuple[
|
335
|
+
str, # group
|
336
|
+
str, # unique
|
337
|
+
str, # last
|
338
|
+
str, # next
|
339
|
+
str] # update
|
340
|
+
|
341
|
+
inserts: list[insert] = []
|
342
|
+
|
343
|
+
items = windows.items()
|
344
|
+
|
345
|
+
for unique, window in items:
|
346
|
+
|
347
|
+
append = (
|
348
|
+
group, unique,
|
349
|
+
window.last.subsec,
|
350
|
+
window.next.subsec,
|
351
|
+
Times('now').subsec)
|
352
|
+
|
353
|
+
inserts.append(append)
|
354
|
+
|
355
|
+
|
356
|
+
statement = (
|
357
|
+
f"""
|
358
|
+
replace into {table}
|
359
|
+
("group", "unique",
|
360
|
+
"next", "last",
|
361
|
+
"update")
|
362
|
+
values (?, ?, ?, ?, ?)
|
363
|
+
""") # noqa: LIT003
|
364
|
+
|
365
|
+
sqlite.executemany(
|
366
|
+
statement,
|
367
|
+
tuple(sorted(inserts)))
|
368
|
+
|
369
|
+
sqlite.commit()
|
370
|
+
|
371
|
+
|
372
|
+
def ready(
|
373
|
+
self,
|
374
|
+
unique: str,
|
375
|
+
update: bool = True,
|
376
|
+
) -> bool:
|
377
|
+
"""
|
378
|
+
Determine whether or not the appropriate time has passed.
|
379
|
+
|
380
|
+
:param unique: Unique identifier for the related child.
|
381
|
+
:param update: Determines whether or not time is updated.
|
382
|
+
:returns: Boolean indicating whether enough time passed.
|
383
|
+
"""
|
384
|
+
|
385
|
+
windows = self.__windows
|
386
|
+
|
387
|
+
if unique not in windows:
|
388
|
+
raise ValueError('unique')
|
389
|
+
|
390
|
+
window = windows[unique]
|
391
|
+
|
392
|
+
return window.ready(update)
|
393
|
+
|
394
|
+
|
395
|
+
def create(
|
396
|
+
self,
|
397
|
+
unique: str,
|
398
|
+
params: 'WindowParams',
|
399
|
+
) -> Window:
|
400
|
+
"""
|
401
|
+
Create a new window using the provided input parameters.
|
402
|
+
|
403
|
+
:param unique: Unique identifier for the related child.
|
404
|
+
:param params: Parameters for instantiating the instance.
|
405
|
+
:returns: Newly constructed instance of related class.
|
406
|
+
"""
|
407
|
+
|
408
|
+
windows = self.params.windows
|
409
|
+
|
410
|
+
self.save_children()
|
411
|
+
|
412
|
+
if unique in windows:
|
413
|
+
raise ValueError('unique')
|
414
|
+
|
415
|
+
windows[unique] = params
|
416
|
+
|
417
|
+
self.load_children()
|
418
|
+
|
419
|
+
return self.children[unique]
|
420
|
+
|
421
|
+
|
422
|
+
def update(
|
423
|
+
self,
|
424
|
+
unique: str,
|
425
|
+
value: Optional[PARSABLE] = None,
|
426
|
+
) -> None:
|
427
|
+
"""
|
428
|
+
Update the window from the provided parasable time value.
|
429
|
+
|
430
|
+
:param unique: Unique identifier for the related child.
|
431
|
+
:param value: Override the time updated for window value.
|
432
|
+
"""
|
433
|
+
|
434
|
+
windows = self.__windows
|
435
|
+
|
436
|
+
if unique not in windows:
|
437
|
+
raise ValueError('unique')
|
438
|
+
|
439
|
+
window = windows[unique]
|
440
|
+
|
441
|
+
return window.update(value)
|
442
|
+
|
443
|
+
|
444
|
+
def delete(
|
445
|
+
self,
|
446
|
+
unique: str,
|
447
|
+
) -> None:
|
448
|
+
"""
|
449
|
+
Delete the window from the internal dictionary reference.
|
450
|
+
|
451
|
+
:param unique: Unique identifier for the related child.
|
452
|
+
"""
|
453
|
+
|
454
|
+
windows = self.__windows
|
455
|
+
|
456
|
+
if unique not in windows:
|
457
|
+
raise ValueError('unique')
|
458
|
+
|
459
|
+
del windows[unique]
|
encommon/types/__init__.py
CHANGED
@@ -10,6 +10,9 @@ is permitted, for more information consult the project license file.
|
|
10
10
|
from .dicts import merge_dicts
|
11
11
|
from .dicts import sort_dict
|
12
12
|
from .empty import Empty
|
13
|
+
from .notate import delate
|
14
|
+
from .notate import getate
|
15
|
+
from .notate import setate
|
13
16
|
from .strings import hasstr
|
14
17
|
from .strings import inrepr
|
15
18
|
from .strings import instr
|
@@ -18,10 +21,13 @@ from .strings import striplower
|
|
18
21
|
|
19
22
|
|
20
23
|
__all__ = [
|
24
|
+
'delate',
|
21
25
|
'Empty',
|
26
|
+
'getate',
|
22
27
|
'hasstr',
|
23
28
|
'inrepr',
|
24
29
|
'instr',
|
25
30
|
'merge_dicts',
|
31
|
+
'setate',
|
26
32
|
'sort_dict',
|
27
33
|
'striplower']
|