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/timers.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 TimersParams
24
29
  from .time import Time
25
30
  from .timer import Timer
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 TimerParams
@@ -33,17 +41,7 @@ TIMERS = dict[str, Timer]
33
41
 
34
42
 
35
43
 
36
- class SQLBase(DeclarativeBase):
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 TimersTable(SQLBase):
44
+ class TimersTable(DeclarativeBase):
47
45
  """
48
46
  Schematic for the database operations using SQLAlchemy.
49
47
 
@@ -69,7 +67,74 @@ class TimersTable(SQLBase):
69
67
  String,
70
68
  nullable=False)
71
69
 
72
- __tablename__ = 'timers'
70
+
71
+
72
+ class TimersRecord(BaseModel):
73
+ """
74
+ Contain the information of the record from the database.
75
+
76
+ :param record: Record from the SQLAlchemy query routine.
77
+ """
78
+
79
+ group: Annotated[
80
+ str,
81
+ Field(...,
82
+ description='Group the children by category',
83
+ min_length=1)]
84
+
85
+ unique: Annotated[
86
+ str,
87
+ Field(...,
88
+ description='Unique identifier for the child',
89
+ min_length=1)]
90
+
91
+ last: Annotated[
92
+ str,
93
+ Field(...,
94
+ description='Last interval for the period',
95
+ min_length=20,
96
+ max_length=32)]
97
+
98
+ update: Annotated[
99
+ str,
100
+ Field(...,
101
+ description='When the record was updated',
102
+ min_length=20,
103
+ max_length=32)]
104
+
105
+
106
+ def __init__(
107
+ self,
108
+ record: Optional[DeclarativeBase] = None,
109
+ ) -> None:
110
+ """
111
+ Initialize instance for class using provided parameters.
112
+ """
113
+
114
+ fields = [
115
+ 'group',
116
+ 'unique',
117
+ 'last',
118
+ 'update']
119
+
120
+ params = {
121
+ x: getattr(record, x)
122
+ for x in fields}
123
+
124
+
125
+ timefs = [
126
+ 'last',
127
+ 'update']
128
+
129
+ params |= {
130
+ k: (Time(v).simple
131
+ if v else None)
132
+ for k, v in
133
+ params.items()
134
+ if k in timefs}
135
+
136
+
137
+ super().__init__(**params)
73
138
 
74
139
 
75
140
 
@@ -106,13 +171,15 @@ class Timers:
106
171
 
107
172
  __store: str
108
173
  __group: str
174
+ __table: Type[TimersTable]
175
+ __locker: Lock
109
176
 
110
177
  __sengine: Engine
111
178
  __session: (
112
179
  # pylint: disable=unsubscriptable-object
113
180
  sessionmaker[Session])
114
181
 
115
- __timers: TIMERS
182
+ __childs: TIMERS
116
183
 
117
184
 
118
185
  def __init__(
@@ -120,6 +187,7 @@ class Timers:
120
187
  params: Optional['TimersParams'] = None,
121
188
  *,
122
189
  store: str = 'sqlite:///:memory:',
190
+ table: str = 'timers',
123
191
  group: str = 'default',
124
192
  ) -> None:
125
193
  """
@@ -137,15 +205,25 @@ class Timers:
137
205
  self.__store = store
138
206
  self.__group = group
139
207
 
140
- self.__make_engine()
208
+ class SQLBase(DeclarativeBase):
209
+ pass
141
210
 
211
+ self.__table = type(
212
+ f'encommon_timers_{table}',
213
+ (SQLBase, TimersTable),
214
+ {'__tablename__': table})
142
215
 
143
- self.__timers = {}
216
+ self.__locker = Lock()
144
217
 
145
- self.load_children()
218
+ self.__build_engine()
146
219
 
147
220
 
148
- def __make_engine(
221
+ self.__childs = {}
222
+
223
+ self.__build_objects()
224
+
225
+
226
+ def __build_engine(
149
227
  self,
150
228
  ) -> None:
151
229
  """
@@ -156,7 +234,7 @@ class Timers:
156
234
  self.__store,
157
235
  pool_pre_ping=True)
158
236
 
159
- (SQLBase.metadata
237
+ (self.__table.metadata
160
238
  .create_all(sengine))
161
239
 
162
240
  session = (
@@ -166,6 +244,23 @@ class Timers:
166
244
  self.__session = session
167
245
 
168
246
 
247
+ def __build_objects(
248
+ self,
249
+ ) -> None:
250
+ """
251
+ Construct instances using the configuration parameters.
252
+ """
253
+
254
+ params = self.__params
255
+
256
+ items = (
257
+ params.timers
258
+ .items())
259
+
260
+ for name, item in items:
261
+ self.create(name, item)
262
+
263
+
169
264
  @property
170
265
  def params(
171
266
  self,
@@ -205,6 +300,19 @@ class Timers:
205
300
  return self.__group
206
301
 
207
302
 
303
+ @property
304
+ def store_table(
305
+ self,
306
+ ) -> Type[TimersTable]:
307
+ """
308
+ Return the value for the attribute from class instance.
309
+
310
+ :returns: Value for the attribute from class instance.
311
+ """
312
+
313
+ return self.__table
314
+
315
+
208
316
  @property
209
317
  def store_engine(
210
318
  self,
@@ -241,101 +349,53 @@ class Timers:
241
349
  :returns: Value for the attribute from class instance.
242
350
  """
243
351
 
244
- return dict(self.__timers)
352
+ return dict(self.__childs)
245
353
 
246
354
 
247
- def load_children(
355
+ def save_children(
248
356
  self,
249
357
  ) -> None:
250
358
  """
251
- Construct the children instances for the primary class.
359
+ Save the child caches from the attribute into database.
252
360
  """
253
361
 
254
- params = self.__params
255
- timers = self.__timers
362
+ sess = self.__session()
363
+ lock = self.__locker
256
364
 
365
+ table = self.__table
257
366
  group = self.__group
258
-
259
- session = self.store_session
260
-
261
- config = params.timers
367
+ childs = self.__childs
262
368
 
263
369
 
264
- _table = TimersTable
265
- _group = _table.group
266
- _unique = _table.unique
370
+ inserts: LDictStrAny = []
267
371
 
268
- query = (
269
- session.query(_table)
270
- .filter(_group == group)
271
- .order_by(_unique))
372
+ update = Time('now')
272
373
 
273
- for record in query.all():
274
374
 
275
- unique = str(record.unique)
276
- last = str(record.last)
375
+ items = childs.items()
277
376
 
278
- if unique not in config:
279
- continue
377
+ for unique, cache in items:
280
378
 
281
- _config = config[unique]
379
+ _last = cache.time.subsec
380
+ _update = update.subsec
282
381
 
283
- _config.start = last
382
+ inputs: DictStrAny = {
383
+ 'group': group,
384
+ 'unique': unique,
385
+ 'last': _last,
386
+ 'update': _update}
284
387
 
388
+ inserts.append(inputs)
285
389
 
286
- items = config.items()
287
390
 
288
- for key, value in items:
391
+ with lock, sess as session:
289
392
 
290
- if key in timers:
393
+ for insert in inserts:
291
394
 
292
- timer = timers[key]
395
+ session.merge(
396
+ table(**insert))
293
397
 
294
- timer.update(value.start)
295
-
296
- continue
297
-
298
- timer = Timer(
299
- value.timer,
300
- start=value.start)
301
-
302
- timers[key] = timer
303
-
304
-
305
- self.__timers = timers
306
-
307
-
308
- def save_children(
309
- self,
310
- ) -> None:
311
- """
312
- Save the child caches from the attribute into database.
313
- """
314
-
315
- timers = self.__timers
316
-
317
- group = self.__group
318
-
319
- session = self.store_session
320
-
321
-
322
- items = timers.items()
323
-
324
- for unique, timer in items:
325
-
326
- update = Time('now')
327
-
328
- append = TimersTable(
329
- group=group,
330
- unique=unique,
331
- last=timer.time.subsec,
332
- update=update.subsec)
333
-
334
- session.merge(append)
335
-
336
-
337
- session.commit()
338
- session.close()
398
+ session.commit()
339
399
 
340
400
 
341
401
  def ready(
@@ -351,14 +411,14 @@ class Timers:
351
411
  :returns: Boolean indicating whether enough time passed.
352
412
  """
353
413
 
354
- timers = self.__timers
414
+ childs = self.__childs
355
415
 
356
- if unique not in timers:
416
+ if unique not in childs:
357
417
  raise ValueError('unique')
358
418
 
359
- timer = timers[unique]
419
+ child = childs[unique]
360
420
 
361
- ready = timer.ready(update)
421
+ ready = child.ready(update)
362
422
 
363
423
  if ready is True:
364
424
  self.save_children()
@@ -383,6 +443,52 @@ class Timers:
383
443
  unique, update)
384
444
 
385
445
 
446
+ def select(
447
+ self,
448
+ unique: str,
449
+ ) -> Optional[TimersRecord]:
450
+ """
451
+ Return the record from within the table in the database.
452
+
453
+ :returns: Record from within the table in the database.
454
+ """
455
+
456
+ sess = self.__session()
457
+ lock = self.__locker
458
+
459
+ table = self.__table
460
+ model = TimersRecord
461
+
462
+ table = self.__table
463
+ group = self.__group
464
+
465
+ _unique = table.unique
466
+ _group = table.group
467
+
468
+
469
+ with lock, sess as session:
470
+
471
+ query = (
472
+ session.query(table)
473
+ .filter(_unique == unique)
474
+ .filter(_group == group))
475
+
476
+ _records = list(query.all())
477
+
478
+
479
+ records = [
480
+ model(x)
481
+ for x in _records]
482
+
483
+
484
+ if len(records) == 0:
485
+ return None
486
+
487
+ assert len(records) == 1
488
+
489
+ return records[0]
490
+
491
+
386
492
  def create(
387
493
  self,
388
494
  unique: str,
@@ -396,20 +502,31 @@ class Timers:
396
502
  :returns: Newly constructed instance of related class.
397
503
  """
398
504
 
399
- config = (
400
- self.params
401
- .timers)
505
+ childs = self.__childs
402
506
 
403
- if unique in config:
507
+ if unique in childs:
404
508
  raise ValueError('unique')
405
509
 
406
- config[unique] = params
510
+ timer = params.timer
511
+ start = params.start
512
+
513
+
514
+ select = self.select(unique)
515
+
516
+ if select is not None:
517
+ start = select.last
518
+
519
+
520
+ child = Timer(
521
+ timer=timer,
522
+ start=start)
523
+
524
+ childs[unique] = child
407
525
 
408
- self.load_children()
409
526
 
410
527
  self.save_children()
411
528
 
412
- return self.children[unique]
529
+ return child
413
530
 
414
531
 
415
532
  def update(
@@ -424,14 +541,14 @@ class Timers:
424
541
  :param value: Override the time updated for timer value.
425
542
  """
426
543
 
427
- timers = self.__timers
544
+ childs = self.__childs
428
545
 
429
- if unique not in timers:
546
+ if unique not in childs:
430
547
  raise ValueError('unique')
431
548
 
432
- timer = timers[unique]
549
+ child = childs[unique]
433
550
 
434
- timer.update(value)
551
+ child.update(value)
435
552
 
436
553
  self.save_children()
437
554
 
@@ -450,32 +567,26 @@ class Timers:
450
567
  :param unique: Unique identifier for the related child.
451
568
  """
452
569
 
453
- params = self.__params
454
- timers = self.__timers
570
+ sess = self.__session()
571
+ lock = self.__locker
572
+ childs = self.__childs
455
573
 
574
+ table = self.__table
456
575
  group = self.__group
457
576
 
458
- session = self.store_session
459
-
460
- config = params.timers
461
-
462
-
463
- if unique in config:
464
- del config[unique]
577
+ _unique = table.unique
578
+ _group = table.group
465
579
 
466
- if unique in timers:
467
- del timers[unique]
468
580
 
581
+ with lock, sess as session:
469
582
 
470
- _table = TimersTable
471
- _group = _table.group
472
- _unique = _table.unique
583
+ (session.query(table)
584
+ .filter(_unique == unique)
585
+ .filter(_group == group)
586
+ .delete())
473
587
 
474
- (session.query(_table)
475
- .filter(_unique == unique)
476
- .filter(_group == group)
477
- .delete())
588
+ session.commit()
478
589
 
479
590
 
480
- session.commit()
481
- session.close()
591
+ if unique in childs:
592
+ del childs[unique]