encommon 0.22.9__py3-none-any.whl → 0.22.11__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/times/parse.py +9 -3
- encommon/times/test/test_timers.py +25 -18
- encommon/times/test/test_windows.py +29 -21
- encommon/times/timers.py +236 -125
- encommon/times/windows.py +275 -149
- encommon/types/__init__.py +2 -0
- encommon/types/notate.py +3 -2
- encommon/types/types.py +1 -0
- encommon/version.txt +1 -1
- {encommon-0.22.9.dist-info → encommon-0.22.11.dist-info}/METADATA +1 -1
- {encommon-0.22.9.dist-info → encommon-0.22.11.dist-info}/RECORD +14 -14
- {encommon-0.22.9.dist-info → encommon-0.22.11.dist-info}/WHEEL +1 -1
- {encommon-0.22.9.dist-info → encommon-0.22.11.dist-info}/licenses/LICENSE +0 -0
- {encommon-0.22.9.dist-info → encommon-0.22.11.dist-info}/top_level.txt +0 -0
encommon/times/windows.py
CHANGED
@@ -8,8 +8,13 @@ is permitted, for more information consult the project license file.
|
|
8
8
|
|
9
9
|
|
10
10
|
from copy import deepcopy
|
11
|
+
from threading import Lock
|
12
|
+
from typing import Annotated
|
11
13
|
from typing import Optional
|
12
14
|
from typing import TYPE_CHECKING
|
15
|
+
from typing import Type
|
16
|
+
|
17
|
+
from pydantic import Field
|
13
18
|
|
14
19
|
from sqlalchemy import Column
|
15
20
|
from sqlalchemy import String
|
@@ -23,6 +28,9 @@ from .common import PARSABLE
|
|
23
28
|
from .params import WindowsParams
|
24
29
|
from .time import Time
|
25
30
|
from .window import Window
|
31
|
+
from ..types import BaseModel
|
32
|
+
from ..types import DictStrAny
|
33
|
+
from ..types import LDictStrAny
|
26
34
|
|
27
35
|
if TYPE_CHECKING:
|
28
36
|
from .params import WindowParams
|
@@ -33,17 +41,7 @@ WINDOWS = dict[str, Window]
|
|
33
41
|
|
34
42
|
|
35
43
|
|
36
|
-
class
|
37
|
-
"""
|
38
|
-
Some additional class that SQLAlchemy requires to work.
|
39
|
-
|
40
|
-
.. note::
|
41
|
-
Input parameters are not defined, check parent class.
|
42
|
-
"""
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
class WindowsTable(SQLBase):
|
44
|
+
class WindowsTable(DeclarativeBase):
|
47
45
|
"""
|
48
46
|
Schematic for the database operations using SQLAlchemy.
|
49
47
|
|
@@ -73,7 +71,83 @@ class WindowsTable(SQLBase):
|
|
73
71
|
String,
|
74
72
|
nullable=False)
|
75
73
|
|
76
|
-
|
74
|
+
|
75
|
+
|
76
|
+
class WindowsRecord(BaseModel):
|
77
|
+
"""
|
78
|
+
Contain the information of the record from the database.
|
79
|
+
|
80
|
+
:param record: Record from the SQLAlchemy query routine.
|
81
|
+
"""
|
82
|
+
|
83
|
+
group: Annotated[
|
84
|
+
str,
|
85
|
+
Field(...,
|
86
|
+
description='Group the children by category',
|
87
|
+
min_length=1)]
|
88
|
+
|
89
|
+
unique: Annotated[
|
90
|
+
str,
|
91
|
+
Field(...,
|
92
|
+
description='Unique identifier for the child',
|
93
|
+
min_length=1)]
|
94
|
+
|
95
|
+
last: Annotated[
|
96
|
+
str,
|
97
|
+
Field(...,
|
98
|
+
description='Last schedule for the period',
|
99
|
+
min_length=20,
|
100
|
+
max_length=32)]
|
101
|
+
|
102
|
+
next: Annotated[
|
103
|
+
str,
|
104
|
+
Field(...,
|
105
|
+
description='Next schedule for the period',
|
106
|
+
min_length=20,
|
107
|
+
max_length=32)]
|
108
|
+
|
109
|
+
update: Annotated[
|
110
|
+
str,
|
111
|
+
Field(...,
|
112
|
+
description='When the record was updated',
|
113
|
+
min_length=20,
|
114
|
+
max_length=32)]
|
115
|
+
|
116
|
+
|
117
|
+
def __init__(
|
118
|
+
self,
|
119
|
+
record: Optional[DeclarativeBase] = None,
|
120
|
+
) -> None:
|
121
|
+
"""
|
122
|
+
Initialize instance for class using provided parameters.
|
123
|
+
"""
|
124
|
+
|
125
|
+
fields = [
|
126
|
+
'group',
|
127
|
+
'unique',
|
128
|
+
'last',
|
129
|
+
'next',
|
130
|
+
'update']
|
131
|
+
|
132
|
+
params = {
|
133
|
+
x: getattr(record, x)
|
134
|
+
for x in fields}
|
135
|
+
|
136
|
+
|
137
|
+
timefs = [
|
138
|
+
'last',
|
139
|
+
'next',
|
140
|
+
'update']
|
141
|
+
|
142
|
+
params |= {
|
143
|
+
k: (Time(v).simple
|
144
|
+
if v else None)
|
145
|
+
for k, v in
|
146
|
+
params.items()
|
147
|
+
if k in timefs}
|
148
|
+
|
149
|
+
|
150
|
+
super().__init__(**params)
|
77
151
|
|
78
152
|
|
79
153
|
|
@@ -108,6 +182,8 @@ class Windows:
|
|
108
182
|
|
109
183
|
__store: str
|
110
184
|
__group: str
|
185
|
+
__table: Type[WindowsTable]
|
186
|
+
__locker: Lock
|
111
187
|
|
112
188
|
__sengine: Engine
|
113
189
|
__session: (
|
@@ -117,16 +193,17 @@ class Windows:
|
|
117
193
|
__start: Time
|
118
194
|
__stop: Time
|
119
195
|
|
120
|
-
|
196
|
+
__childs: WINDOWS
|
121
197
|
|
122
198
|
|
123
|
-
def __init__(
|
199
|
+
def __init__( # noqa: CFQ002
|
124
200
|
self,
|
125
201
|
params: Optional['WindowsParams'] = None,
|
126
202
|
start: PARSABLE = 'now',
|
127
203
|
stop: PARSABLE = '3000-01-01',
|
128
204
|
*,
|
129
205
|
store: str = 'sqlite:///:memory:',
|
206
|
+
table: str = 'windows',
|
130
207
|
group: str = 'default',
|
131
208
|
) -> None:
|
132
209
|
"""
|
@@ -144,7 +221,17 @@ class Windows:
|
|
144
221
|
self.__store = store
|
145
222
|
self.__group = group
|
146
223
|
|
147
|
-
|
224
|
+
class SQLBase(DeclarativeBase):
|
225
|
+
pass
|
226
|
+
|
227
|
+
self.__table = type(
|
228
|
+
f'encommon_windows_{table}',
|
229
|
+
(SQLBase, WindowsTable),
|
230
|
+
{'__tablename__': table})
|
231
|
+
|
232
|
+
self.__locker = Lock()
|
233
|
+
|
234
|
+
self.__build_engine()
|
148
235
|
|
149
236
|
|
150
237
|
start = Time(start)
|
@@ -156,12 +243,12 @@ class Windows:
|
|
156
243
|
self.__stop = stop
|
157
244
|
|
158
245
|
|
159
|
-
self.
|
246
|
+
self.__childs = {}
|
160
247
|
|
161
|
-
self.
|
248
|
+
self.__build_objects()
|
162
249
|
|
163
250
|
|
164
|
-
def
|
251
|
+
def __build_engine(
|
165
252
|
self,
|
166
253
|
) -> None:
|
167
254
|
"""
|
@@ -172,7 +259,7 @@ class Windows:
|
|
172
259
|
self.__store,
|
173
260
|
pool_pre_ping=True)
|
174
261
|
|
175
|
-
(
|
262
|
+
(self.__table.metadata
|
176
263
|
.create_all(sengine))
|
177
264
|
|
178
265
|
session = (
|
@@ -182,6 +269,23 @@ class Windows:
|
|
182
269
|
self.__session = session
|
183
270
|
|
184
271
|
|
272
|
+
def __build_objects(
|
273
|
+
self,
|
274
|
+
) -> None:
|
275
|
+
"""
|
276
|
+
Construct instances using the configuration parameters.
|
277
|
+
"""
|
278
|
+
|
279
|
+
params = self.__params
|
280
|
+
|
281
|
+
items = (
|
282
|
+
params.windows
|
283
|
+
.items())
|
284
|
+
|
285
|
+
for name, item in items:
|
286
|
+
self.create(name, item)
|
287
|
+
|
288
|
+
|
185
289
|
@property
|
186
290
|
def params(
|
187
291
|
self,
|
@@ -221,6 +325,19 @@ class Windows:
|
|
221
325
|
return self.__group
|
222
326
|
|
223
327
|
|
328
|
+
@property
|
329
|
+
def store_table(
|
330
|
+
self,
|
331
|
+
) -> Type[WindowsTable]:
|
332
|
+
"""
|
333
|
+
Return the value for the attribute from class instance.
|
334
|
+
|
335
|
+
:returns: Value for the attribute from class instance.
|
336
|
+
"""
|
337
|
+
|
338
|
+
return self.__table
|
339
|
+
|
340
|
+
|
224
341
|
@property
|
225
342
|
def store_engine(
|
226
343
|
self,
|
@@ -283,124 +400,55 @@ class Windows:
|
|
283
400
|
:returns: Value for the attribute from class instance.
|
284
401
|
"""
|
285
402
|
|
286
|
-
return dict(self.
|
403
|
+
return dict(self.__childs)
|
287
404
|
|
288
405
|
|
289
|
-
def
|
406
|
+
def save_children(
|
290
407
|
self,
|
291
408
|
) -> None:
|
292
409
|
"""
|
293
|
-
|
410
|
+
Save the child caches from the attribute into database.
|
294
411
|
"""
|
295
412
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
start = self.__start
|
300
|
-
stop = self.__stop
|
413
|
+
sess = self.__session()
|
414
|
+
lock = self.__locker
|
301
415
|
|
416
|
+
table = self.__table
|
302
417
|
group = self.__group
|
418
|
+
childs = self.__childs
|
303
419
|
|
304
|
-
session = self.store_session
|
305
|
-
|
306
|
-
config = params.windows
|
307
|
-
|
308
|
-
|
309
|
-
_table = WindowsTable
|
310
|
-
_group = _table.group
|
311
|
-
_unique = _table.unique
|
312
|
-
|
313
|
-
query = (
|
314
|
-
session.query(_table)
|
315
|
-
.filter(_group == group)
|
316
|
-
.order_by(_unique))
|
317
|
-
|
318
|
-
for record in query.all():
|
319
|
-
|
320
|
-
unique = str(record.unique)
|
321
|
-
next = str(record.next)
|
322
|
-
|
323
|
-
if unique not in config:
|
324
|
-
continue
|
325
420
|
|
326
|
-
|
421
|
+
inserts: LDictStrAny = []
|
327
422
|
|
328
|
-
|
329
|
-
_config.anchor = next
|
423
|
+
update = Time('now')
|
330
424
|
|
331
425
|
|
332
|
-
items =
|
426
|
+
items = childs.items()
|
333
427
|
|
334
|
-
for
|
428
|
+
for unique, cache in items:
|
335
429
|
|
336
|
-
|
430
|
+
_last = cache.last.subsec
|
431
|
+
_next = cache.next.subsec
|
432
|
+
_update = update.subsec
|
337
433
|
|
338
|
-
|
434
|
+
inputs: DictStrAny = {
|
435
|
+
'group': group,
|
436
|
+
'unique': unique,
|
437
|
+
'last': _last,
|
438
|
+
'next': _next,
|
439
|
+
'update': _update}
|
339
440
|
|
340
|
-
|
441
|
+
inserts.append(inputs)
|
341
442
|
|
342
|
-
continue
|
343
443
|
|
344
|
-
|
345
|
-
value.start or start)
|
444
|
+
with lock, sess as session:
|
346
445
|
|
347
|
-
|
348
|
-
value.stop or stop)
|
446
|
+
for insert in inserts:
|
349
447
|
|
350
|
-
|
351
|
-
|
448
|
+
session.merge(
|
449
|
+
table(**insert))
|
352
450
|
|
353
|
-
|
354
|
-
_stop = stop
|
355
|
-
|
356
|
-
_anchor = (
|
357
|
-
value.anchor or _start)
|
358
|
-
|
359
|
-
window = Window(
|
360
|
-
value.window,
|
361
|
-
start=_start,
|
362
|
-
stop=_stop,
|
363
|
-
anchor=_anchor,
|
364
|
-
delay=value.delay)
|
365
|
-
|
366
|
-
windows[key] = window
|
367
|
-
|
368
|
-
|
369
|
-
self.__windows = windows
|
370
|
-
|
371
|
-
|
372
|
-
def save_children(
|
373
|
-
self,
|
374
|
-
) -> None:
|
375
|
-
"""
|
376
|
-
Save the child caches from the attribute into database.
|
377
|
-
"""
|
378
|
-
|
379
|
-
windows = self.__windows
|
380
|
-
|
381
|
-
group = self.__group
|
382
|
-
|
383
|
-
session = self.store_session
|
384
|
-
|
385
|
-
|
386
|
-
items = windows.items()
|
387
|
-
|
388
|
-
for unique, window in items:
|
389
|
-
|
390
|
-
update = Time('now')
|
391
|
-
|
392
|
-
append = WindowsTable(
|
393
|
-
group=group,
|
394
|
-
unique=unique,
|
395
|
-
last=window.last.subsec,
|
396
|
-
next=window.next.subsec,
|
397
|
-
update=update.subsec)
|
398
|
-
|
399
|
-
session.merge(append)
|
400
|
-
|
401
|
-
|
402
|
-
session.commit()
|
403
|
-
session.close()
|
451
|
+
session.commit()
|
404
452
|
|
405
453
|
|
406
454
|
def ready(
|
@@ -416,14 +464,14 @@ class Windows:
|
|
416
464
|
:returns: Boolean indicating whether enough time passed.
|
417
465
|
"""
|
418
466
|
|
419
|
-
|
467
|
+
childs = self.__childs
|
420
468
|
|
421
|
-
if unique not in
|
469
|
+
if unique not in childs:
|
422
470
|
raise ValueError('unique')
|
423
471
|
|
424
|
-
|
472
|
+
child = childs[unique]
|
425
473
|
|
426
|
-
ready =
|
474
|
+
ready = child.ready(update)
|
427
475
|
|
428
476
|
if ready is True:
|
429
477
|
self.save_children()
|
@@ -448,6 +496,52 @@ class Windows:
|
|
448
496
|
unique, update)
|
449
497
|
|
450
498
|
|
499
|
+
def select(
|
500
|
+
self,
|
501
|
+
unique: str,
|
502
|
+
) -> Optional[WindowsRecord]:
|
503
|
+
"""
|
504
|
+
Return the record from within the table in the database.
|
505
|
+
|
506
|
+
:returns: Record from within the table in the database.
|
507
|
+
"""
|
508
|
+
|
509
|
+
sess = self.__session()
|
510
|
+
lock = self.__locker
|
511
|
+
|
512
|
+
table = self.__table
|
513
|
+
model = WindowsRecord
|
514
|
+
|
515
|
+
table = self.__table
|
516
|
+
group = self.__group
|
517
|
+
|
518
|
+
_unique = table.unique
|
519
|
+
_group = table.group
|
520
|
+
|
521
|
+
|
522
|
+
with lock, sess as session:
|
523
|
+
|
524
|
+
query = (
|
525
|
+
session.query(table)
|
526
|
+
.filter(_unique == unique)
|
527
|
+
.filter(_group == group))
|
528
|
+
|
529
|
+
_records = list(query.all())
|
530
|
+
|
531
|
+
|
532
|
+
records = [
|
533
|
+
model(x)
|
534
|
+
for x in _records]
|
535
|
+
|
536
|
+
|
537
|
+
if len(records) == 0:
|
538
|
+
return None
|
539
|
+
|
540
|
+
assert len(records) == 1
|
541
|
+
|
542
|
+
return records[0]
|
543
|
+
|
544
|
+
|
451
545
|
def create(
|
452
546
|
self,
|
453
547
|
unique: str,
|
@@ -461,20 +555,58 @@ class Windows:
|
|
461
555
|
:returns: Newly constructed instance of related class.
|
462
556
|
"""
|
463
557
|
|
464
|
-
|
465
|
-
|
466
|
-
|
558
|
+
childs = self.__childs
|
559
|
+
_start = self.__start
|
560
|
+
_stop = self.__stop
|
467
561
|
|
468
|
-
if unique in
|
562
|
+
if unique in childs:
|
469
563
|
raise ValueError('unique')
|
470
564
|
|
471
|
-
|
565
|
+
window = params.window
|
566
|
+
start = params.start
|
567
|
+
stop = params.stop
|
568
|
+
anchor = params.anchor
|
569
|
+
delay = params.delay
|
570
|
+
|
571
|
+
|
572
|
+
select = self.select(unique)
|
573
|
+
|
574
|
+
if select is not None:
|
575
|
+
start = select.next
|
576
|
+
anchor = select.next
|
577
|
+
|
578
|
+
|
579
|
+
child_start = Time(
|
580
|
+
start if start
|
581
|
+
else _start)
|
582
|
+
|
583
|
+
child_stop = Time(
|
584
|
+
stop if stop
|
585
|
+
else _stop)
|
586
|
+
|
587
|
+
anchor = anchor or start
|
588
|
+
|
589
|
+
|
590
|
+
if child_start < _start:
|
591
|
+
child_start = _start
|
592
|
+
|
593
|
+
if child_stop > _stop:
|
594
|
+
child_stop = _stop
|
595
|
+
|
596
|
+
|
597
|
+
child = Window(
|
598
|
+
window=window,
|
599
|
+
start=child_start,
|
600
|
+
stop=child_stop,
|
601
|
+
anchor=anchor,
|
602
|
+
delay=delay)
|
603
|
+
|
604
|
+
childs[unique] = child
|
472
605
|
|
473
|
-
self.load_children()
|
474
606
|
|
475
607
|
self.save_children()
|
476
608
|
|
477
|
-
return
|
609
|
+
return child
|
478
610
|
|
479
611
|
|
480
612
|
def update(
|
@@ -489,14 +621,14 @@ class Windows:
|
|
489
621
|
:param value: Override the time updated for window value.
|
490
622
|
"""
|
491
623
|
|
492
|
-
|
624
|
+
childs = self.__childs
|
493
625
|
|
494
|
-
if unique not in
|
626
|
+
if unique not in childs:
|
495
627
|
raise ValueError('unique')
|
496
628
|
|
497
|
-
|
629
|
+
child = childs[unique]
|
498
630
|
|
499
|
-
|
631
|
+
child.update(value)
|
500
632
|
|
501
633
|
self.save_children()
|
502
634
|
|
@@ -515,32 +647,26 @@ class Windows:
|
|
515
647
|
:param unique: Unique identifier for the related child.
|
516
648
|
"""
|
517
649
|
|
518
|
-
|
519
|
-
|
650
|
+
sess = self.__session()
|
651
|
+
lock = self.__locker
|
652
|
+
childs = self.__childs
|
520
653
|
|
654
|
+
table = self.__table
|
521
655
|
group = self.__group
|
522
656
|
|
523
|
-
|
524
|
-
|
525
|
-
config = params.windows
|
526
|
-
|
527
|
-
|
528
|
-
if unique in config:
|
529
|
-
del config[unique]
|
657
|
+
_unique = table.unique
|
658
|
+
_group = table.group
|
530
659
|
|
531
|
-
if unique in windows:
|
532
|
-
del windows[unique]
|
533
660
|
|
661
|
+
with lock, sess as session:
|
534
662
|
|
535
|
-
|
536
|
-
|
537
|
-
|
663
|
+
(session.query(table)
|
664
|
+
.filter(_unique == unique)
|
665
|
+
.filter(_group == group)
|
666
|
+
.delete())
|
538
667
|
|
539
|
-
|
540
|
-
.filter(_unique == unique)
|
541
|
-
.filter(_group == group)
|
542
|
-
.delete())
|
668
|
+
session.commit()
|
543
669
|
|
544
670
|
|
545
|
-
|
546
|
-
|
671
|
+
if unique in childs:
|
672
|
+
del childs[unique]
|
encommon/types/__init__.py
CHANGED
@@ -28,6 +28,7 @@ from .strings import instr
|
|
28
28
|
from .strings import rplstr
|
29
29
|
from .strings import strplwr
|
30
30
|
from .types import DictStrAny
|
31
|
+
from .types import LDictStrAny
|
31
32
|
from .types import NCFalse
|
32
33
|
from .types import NCNone
|
33
34
|
from .types import NCTrue
|
@@ -51,6 +52,7 @@ __all__ = [
|
|
51
52
|
'inrepr',
|
52
53
|
'instr',
|
53
54
|
'lattrs',
|
55
|
+
'LDictStrAny',
|
54
56
|
'merge_dicts',
|
55
57
|
'rplstr',
|
56
58
|
'setate',
|
encommon/types/notate.py
CHANGED
@@ -16,6 +16,7 @@ from typing import Union
|
|
16
16
|
|
17
17
|
from .empty import Empty
|
18
18
|
from .types import DictStrAny
|
19
|
+
from .types import LDictStrAny
|
19
20
|
|
20
21
|
|
21
22
|
|
@@ -194,13 +195,13 @@ def delate(
|
|
194
195
|
|
195
196
|
|
196
197
|
def impate( # noqa: CFQ001,CFQ004
|
197
|
-
source: DictStrAny |
|
198
|
+
source: DictStrAny | LDictStrAny,
|
198
199
|
delim: str = '/',
|
199
200
|
parent: Optional[str] = None,
|
200
201
|
*,
|
201
202
|
implode_list: bool = True,
|
202
203
|
recurse_list: bool = True,
|
203
|
-
) -> DictStrAny |
|
204
|
+
) -> DictStrAny | LDictStrAny:
|
204
205
|
"""
|
205
206
|
Implode the dictionary into a single depth of notation.
|
206
207
|
|
encommon/types/types.py
CHANGED
encommon/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.22.
|
1
|
+
0.22.11
|