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.
Files changed (49) hide show
  1. encommon/config/__init__.py +3 -3
  2. encommon/config/config.py +28 -2
  3. encommon/config/files.py +3 -3
  4. encommon/config/logger.py +37 -6
  5. encommon/config/params.py +24 -4
  6. encommon/config/paths.py +2 -2
  7. encommon/config/test/test_logger.py +3 -0
  8. encommon/config/test/{test_common.py → test_utils.py} +3 -3
  9. encommon/config/{common.py → utils.py} +1 -10
  10. encommon/conftest.py +4 -4
  11. encommon/crypts/crypts.py +23 -22
  12. encommon/crypts/params.py +15 -2
  13. encommon/crypts/test/test_crypts.py +8 -20
  14. encommon/times/__init__.py +14 -2
  15. encommon/times/common.py +0 -127
  16. encommon/times/params.py +155 -0
  17. encommon/times/parse.py +5 -5
  18. encommon/times/test/test_params.py +64 -0
  19. encommon/times/test/test_parse.py +1 -1
  20. encommon/times/test/test_timer.py +86 -0
  21. encommon/times/test/test_timers.py +87 -36
  22. encommon/times/test/{test_common.py → test_utils.py} +3 -3
  23. encommon/times/test/test_window.py +101 -51
  24. encommon/times/test/test_windows.py +264 -0
  25. encommon/times/timer.py +147 -0
  26. encommon/times/timers.py +207 -133
  27. encommon/times/times.py +6 -6
  28. encommon/times/utils.py +148 -0
  29. encommon/times/window.py +124 -85
  30. encommon/times/windows.py +459 -0
  31. encommon/types/__init__.py +6 -0
  32. encommon/types/notate.py +319 -0
  33. encommon/types/test/__init__.py +37 -0
  34. encommon/types/test/test_dicts.py +23 -28
  35. encommon/types/test/test_notate.py +217 -0
  36. encommon/utils/__init__.py +2 -2
  37. encommon/utils/common.py +0 -39
  38. encommon/utils/files.py +71 -0
  39. encommon/utils/paths.py +1 -1
  40. encommon/utils/sample.py +2 -2
  41. encommon/utils/test/{test_common.py → test_files.py} +2 -2
  42. encommon/utils/test/test_paths.py +2 -1
  43. encommon/version.txt +1 -1
  44. {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/METADATA +1 -1
  45. encommon-0.11.0.dist-info/RECORD +73 -0
  46. encommon-0.9.0.dist-info/RECORD +0 -63
  47. {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/LICENSE +0 -0
  48. {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/WHEEL +0 -0
  49. {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]
@@ -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']