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