reydb 1.1.61__py3-none-any.whl → 1.2.1__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.
reydb/rerror.py CHANGED
@@ -9,29 +9,46 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import Any
12
+ from typing import Any, NoReturn, TypeVar, Generic
13
13
  from collections.abc import Callable
14
+ from inspect import iscoroutinefunction
14
15
  from traceback import StackSummary
15
16
  from functools import wraps as functools_wraps
17
+ from datetime import datetime as Datetime
16
18
  from reykit.rbase import T, Exit, catch_exc
17
19
 
18
20
  from . import rdb
19
21
  from .rbase import DatabaseBase
22
+ from .rorm import DatabaseORM as orm
20
23
 
21
24
 
22
25
  __all__ = (
26
+ 'DatabaseErrorSuper',
23
27
  'DatabaseError',
28
+ 'DatabaseErrorAsync'
24
29
  )
25
30
 
26
31
 
27
- class DatabaseError(DatabaseBase):
32
+ DatabaseT = TypeVar('DatabaseT', 'rdb.Database', 'rdb.DatabaseAsync')
33
+
34
+
35
+ class DatabaseErrorSuper(DatabaseBase, Generic[DatabaseT]):
28
36
  """
29
- Database error type.
37
+ Database error super type.
30
38
  Can create database used `self.build_db` method.
39
+
40
+ Attributes
41
+ ----------
42
+ db_names : Database table name mapping dictionary.
31
43
  """
32
44
 
45
+ db_names = {
46
+ 'error': 'error',
47
+ 'stats_error': 'stats_error'
48
+ }
33
49
 
34
- def __init__(self, db: 'rdb.Database') -> None:
50
+
51
+ def __init__(self, db: DatabaseT) -> None:
35
52
  """
36
53
  Build instance attributes.
37
54
 
@@ -43,101 +60,36 @@ class DatabaseError(DatabaseBase):
43
60
  # Build.
44
61
  self.db = db
45
62
 
46
- ## Database path name.
47
- self.db_names = {
48
- 'base': 'base',
49
- 'base.error': 'error',
50
- 'base.stats_error': 'stats_error'
51
- }
52
-
53
63
 
54
- def build_db(self) -> None:
64
+ def handle_build_db(self) -> None:
55
65
  """
56
- Check and build database tables, by `self.db_names`.
66
+ Handle method of check and build database tables, by `self.db_names`.
57
67
  """
58
68
 
59
- # Set parameter.
60
-
61
- ## Database.
62
- databases = [
63
- {
64
- 'name': self.db_names['base']
65
- }
66
- ]
69
+ # Handle parameter.
67
70
 
68
71
  ## Table.
69
- tables = [
70
-
71
- ### 'error'.
72
- {
73
- 'path': (self.db_names['base'], self.db_names['base.error']),
74
- 'fields': [
75
- {
76
- 'name': 'create_time',
77
- 'type': 'datetime',
78
- 'constraint': 'NOT NULL DEFAULT CURRENT_TIMESTAMP',
79
- 'comment': 'Record create time.'
80
- },
81
- {
82
- 'name': 'id',
83
- 'type': 'int unsigned',
84
- 'constraint': 'NOT NULL AUTO_INCREMENT',
85
- 'comment': 'ID.'
86
- },
87
- {
88
- 'name': 'type',
89
- 'type': 'varchar(50)',
90
- 'constraint': 'NOT NULL',
91
- 'comment': 'Error type.'
92
- },
93
- {
94
- 'name': 'data',
95
- 'type': 'json',
96
- 'comment': 'Error data.'
97
- },
98
- {
99
- 'name': 'stack',
100
- 'type': 'json',
101
- 'comment': 'Error code traceback stack.'
102
- },
103
- {
104
- 'name': 'note',
105
- 'type': 'varchar(500)',
106
- 'comment': 'Error note.'
107
- }
108
- ],
109
- 'primary': 'id',
110
- 'indexes': [
111
- {
112
- 'name': 'n_create_time',
113
- 'fields': 'create_time',
114
- 'type': 'noraml',
115
- 'comment': 'Record create time normal index.'
116
- },
117
- {
118
- 'name': 'n_type',
119
- 'fields': 'type',
120
- 'type': 'noraml',
121
- 'comment': 'Error type normal index.'
122
- }
123
- ],
124
- 'comment': 'Error log table.'
125
- },
126
-
127
- ]
72
+ class error(orm.Model, table=True):
73
+ __name__ = self.db_names['error']
74
+ __comment__ = 'Error log table.'
75
+ create_time: Datetime = orm.Field(field_default='CURRENT_TIMESTAMP', not_null=True, index_n=True, comment='Record create time.')
76
+ id: int = orm.Field(field_name='idd', field_type=orm.types_mysql.INTEGER(unsigned=True), key=True, key_auto=True, not_null=True, comment='ID.')
77
+ type: str = orm.Field(field_type=orm.types.VARCHAR(50), not_null=True, index_n=True, comment='Error type.')
78
+ data: str = orm.Field(field_type=orm.types.JSON, comment='Error data.')
79
+ stack: str = orm.Field(field_type=orm.types.JSON, comment='Error code traceback stack.')
80
+ note: str = orm.Field(field_type=orm.types.VARCHAR(500), comment='Error note.')
81
+ tables = [error]
128
82
 
129
83
  ## View stats.
130
84
  views_stats = [
131
-
132
- ### 'stats_error'.
133
85
  {
134
- 'path': (self.db_names['base'], self.db_names['base.stats_error']),
86
+ 'path': self.db_names['stats_error'],
135
87
  'items': [
136
88
  {
137
89
  'name': 'count',
138
90
  'select': (
139
91
  'SELECT COUNT(1)\n'
140
- f'FROM `{self.db_names['base']}`.`{self.db_names['base.error']}`'
92
+ f'FROM `{self.db.database}`.`{self.db_names['error']}`'
141
93
  ),
142
94
  'comment': 'Error log count.'
143
95
  },
@@ -145,7 +97,7 @@ class DatabaseError(DatabaseBase):
145
97
  'name': 'past_day_count',
146
98
  'select': (
147
99
  'SELECT COUNT(1)\n'
148
- f'FROM `{self.db_names['base']}`.`{self.db_names['base.error']}`\n'
100
+ f'FROM `{self.db.database}`.`{self.db_names['error']}`\n'
149
101
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
150
102
  ),
151
103
  'comment': 'Error log count in the past day.'
@@ -154,7 +106,7 @@ class DatabaseError(DatabaseBase):
154
106
  'name': 'past_week_count',
155
107
  'select': (
156
108
  'SELECT COUNT(1)\n'
157
- f'FROM `{self.db_names['base']}`.`{self.db_names['base.error']}`\n'
109
+ f'FROM `{self.db.database}`.`{self.db_names['error']}`\n'
158
110
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
159
111
  ),
160
112
  'comment': 'Error log count in the past week.'
@@ -163,7 +115,7 @@ class DatabaseError(DatabaseBase):
163
115
  'name': 'past_month_count',
164
116
  'select': (
165
117
  'SELECT COUNT(1)\n'
166
- f'FROM `{self.db_names['base']}`.`{self.db_names['base.error']}`\n'
118
+ f'FROM `{self.db.database}`.`{self.db_names['error']}`\n'
167
119
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
168
120
  ),
169
121
  'comment': 'Error log count in the past month.'
@@ -172,21 +124,18 @@ class DatabaseError(DatabaseBase):
172
124
  'name': 'last_time',
173
125
  'select': (
174
126
  'SELECT MAX(`create_time`)\n'
175
- f'FROM `{self.db_names['base']}`.`{self.db_names['base.error']}`'
127
+ f'FROM `{self.db.database}`.`{self.db_names['error']}`'
176
128
  ),
177
129
  'comment': 'Error log last record create time.'
178
130
  }
179
131
  ]
180
-
181
132
  }
182
-
183
133
  ]
184
134
 
185
- # Build.
186
- self.db.build.build(databases, tables, views_stats=views_stats)
135
+ return tables, views_stats
187
136
 
188
137
 
189
- def record(
138
+ def handle_record(
190
139
  self,
191
140
  exc: BaseException,
192
141
  stack: StackSummary,
@@ -221,13 +170,87 @@ class DatabaseError(DatabaseBase):
221
170
  'note': note
222
171
  }
223
172
 
173
+ return data
174
+
175
+
176
+ class DatabaseError(DatabaseErrorSuper['rdb.Database']):
177
+ """
178
+ Database error type.
179
+ Can create database used `self.build_db` method.
180
+ """
181
+
182
+
183
+ def build_db(self) -> None:
184
+ """
185
+ Check and build database tables, by `self.db_names`.
186
+ """
187
+
188
+ # Handle parameter.
189
+ tables, views_stats = self.handle_build_db()
190
+
191
+ # Build.
192
+ self.db.build.build(tables=tables, views_stats=views_stats, skip=True)
193
+
194
+
195
+ def record(
196
+ self,
197
+ exc: BaseException,
198
+ stack: StackSummary,
199
+ note: str | None = None
200
+ ) -> None:
201
+ """
202
+ Insert exception information into the table of database.
203
+
204
+ Parameters
205
+ ----------
206
+ exc : Exception instance.
207
+ stack : Exception traceback stack instance.
208
+ note : Exception note.
209
+ """
210
+
211
+ # Handle parameter.
212
+ data = self.handle_record(exc, stack, note)
213
+
224
214
  # Insert.
225
215
  self.db.execute.insert(
226
- self.db_names['base.error'],
216
+ self.db_names['error'],
227
217
  data=data
228
218
  )
229
219
 
230
220
 
221
+ __call__ = record
222
+
223
+
224
+ def record_catch(
225
+ self,
226
+ note: str | None = None,
227
+ filter_type : BaseException | tuple[BaseException, ...] = Exit
228
+ ) -> NoReturn:
229
+ """
230
+ Catch and insert exception information into the table of database and throw exception, must used in except syntax.
231
+
232
+ Parameters
233
+ ----------
234
+ note : Exception note.
235
+ filter_type : Exception types of not insert, but still throw exception.
236
+ """
237
+
238
+ # Handle parameter.
239
+ _, exc, stack = catch_exc()
240
+
241
+ # Filter.
242
+ for type_ in filter_type:
243
+ if isinstance(exc, type_):
244
+ break
245
+
246
+ # Record.
247
+ else:
248
+ self.record(exc, stack, note)
249
+
250
+ # Throw exception.
251
+ raise
252
+
253
+
231
254
  def wrap(
232
255
  self,
233
256
  func: Callable[..., T] | None = None,
@@ -236,13 +259,13 @@ class DatabaseError(DatabaseBase):
236
259
  filter_type : BaseException | tuple[BaseException, ...] = Exit
237
260
  ) -> T | Callable[[Callable[..., T]], Callable[..., T]]:
238
261
  """
239
- Decorator, insert exception information into the table of database, throw exception.
262
+ Decorator, insert exception information into the table of database and throw exception.
240
263
 
241
264
  Parameters
242
265
  ----------
243
266
  func : Function.
244
267
  note : Exception note.
245
- filter_type : Exception type of not inserted, but still throw exception.
268
+ filter_type : Exception types of not insert, but still throw exception.
246
269
 
247
270
  Returns
248
271
  -------
@@ -251,21 +274,21 @@ class DatabaseError(DatabaseBase):
251
274
  Examples
252
275
  --------
253
276
  Method one.
254
- >>> @wrap_error
277
+ >>> @wrap
255
278
  >>> def func(*args, **kwargs): ...
256
279
 
257
280
  Method two.
258
- >>> @wrap_error(**wrap_kwargs)
281
+ >>> @wrap(**wrap_kwargs)
259
282
  >>> def func(*args, **kwargs): ...
260
283
 
261
284
  Method three.
262
285
  >>> def func(*args, **kwargs): ...
263
- >>> func = wrap_error(func, **wrap_kwargs)
286
+ >>> func = wrap(func, **wrap_kwargs)
264
287
 
265
288
  Method four.
266
289
  >>> def func(*args, **kwargs): ...
267
- >>> wrap_error = wrap_error(**wrap_kwargs)
268
- >>> func = wrap_error(func)
290
+ >>> wrap = wrap(**wrap_kwargs)
291
+ >>> func = wrap(func)
269
292
 
270
293
  >>> func(*args, **kwargs)
271
294
  """
@@ -308,18 +331,191 @@ class DatabaseError(DatabaseBase):
308
331
  try:
309
332
  result = func_(*args, **kwargs)
310
333
 
311
- # Log.
334
+ # Record.
312
335
  except BaseException:
313
- _, exc, stack = catch_exc()
336
+ self.record_catch(note, filter_type)
314
337
 
315
- ## Filter.
316
- for type_ in filter_type:
317
- if isinstance(exc, type_):
318
- break
338
+ return result
339
+
340
+
341
+ return _func
342
+
343
+
344
+ # Decorator.
345
+ if func is None:
346
+ return _wrap
347
+
348
+ # Decorated function.
349
+ else:
350
+ _func = _wrap(func)
351
+ return _func
352
+
353
+
354
+ class DatabaseErrorAsync(DatabaseErrorSuper['rdb.DatabaseAsync']):
355
+ """
356
+ Asynchrouous database error type.
357
+ Can create database used `self.build_db` method.
358
+ """
359
+
360
+
361
+ async def build_db(self) -> None:
362
+ """
363
+ Asynchrouous check and build database tables, by `self.db_names`.
364
+ """
365
+
366
+ # Handle parameter.
367
+ tables, views_stats = self.handle_build_db()
368
+
369
+ # Build.
370
+ await self.db.build.build(tables=tables, views_stats=views_stats, skip=True)
371
+
372
+
373
+ async def record(
374
+ self,
375
+ exc: BaseException,
376
+ stack: StackSummary,
377
+ note: str | None = None
378
+ ) -> None:
379
+ """
380
+ Asynchrouous insert exception information into the table of database.
381
+
382
+ Parameters
383
+ ----------
384
+ exc : Exception instance.
385
+ stack : Exception traceback stack instance.
386
+ note : Exception note.
387
+ """
388
+
389
+ # Handle parameter.
390
+ data = self.handle_record(exc, stack, note)
391
+
392
+ # Insert.
393
+ await self.db.execute.insert(
394
+ self.db_names['error'],
395
+ data=data
396
+ )
397
+
398
+
399
+ __call__ = record
400
+
401
+
402
+ async def record_catch(
403
+ self,
404
+ note: str | None = None,
405
+ filter_type : BaseException | tuple[BaseException, ...] = Exit
406
+ ) -> NoReturn:
407
+ """
408
+ Asynchrouous catch and insert exception information into the table of database and throw exception, must used in except syntax.
409
+
410
+ Parameters
411
+ ----------
412
+ note : Exception note.
413
+ filter_type : Exception types of not insert, but still throw exception.
414
+ """
415
+
416
+ # Handle parameter.
417
+ _, exc, stack = catch_exc()
418
+
419
+ # Filter.
420
+ for type_ in filter_type:
421
+ if isinstance(exc, type_):
422
+ break
423
+
424
+ # Record.
425
+ else:
426
+ await self.record(exc, stack, note)
427
+
428
+ # Throw exception.
429
+ raise
430
+
431
+
432
+ def wrap(
433
+ self,
434
+ func: Callable[..., T] | None = None,
435
+ *,
436
+ note: str | None = None,
437
+ filter_type : BaseException | tuple[BaseException, ...] = Exit
438
+ ) -> T | Callable[[Callable[..., T]], Callable[..., T]]:
439
+ """
440
+ Asynchrouous decorator, insert exception information into the table of database, throw exception.
441
+
442
+ Parameters
443
+ ----------
444
+ func : Function.
445
+ note : Exception note.
446
+ filter_type : Exception types of not insert, but still throw exception.
447
+
448
+ Returns
449
+ -------
450
+ Decorated function or decorator with parameter.
451
+
452
+ Examples
453
+ --------
454
+ Method one.
455
+ >>> @wrap
456
+ >>> [async ]def func(*args, **kwargs): ...
457
+
458
+ Method two.
459
+ >>> @wrap(**wrap_kwargs)
460
+ >>> [async ]def func(*args, **kwargs): ...
461
+
462
+ Method three.
463
+ >>> [async ]def func(*args, **kwargs): ...
464
+ >>> func = wrap(func, **wrap_kwargs)
465
+
466
+ Method four.
467
+ >>> [async ]def func(*args, **kwargs): ...
468
+ >>> wrap = wrap(**wrap_kwargs)
469
+ >>> func = wrap(func)
470
+
471
+ Must asynchrouous execute.
472
+ >>> await func(*args, **kwargs)
473
+ """
474
+
475
+ # Handle parameter.
476
+ if issubclass(filter_type, BaseException):
477
+ filter_type = (filter_type,)
478
+
479
+
480
+ def _wrap(func_: Callable[..., T]) -> Callable[..., T]:
481
+ """
482
+ Decorator, insert exception information into the table of database.
483
+
484
+ Parameters
485
+ ----------
486
+ _func : Function.
487
+
488
+ Returns
489
+ -------
490
+ Decorated function.
491
+ """
492
+
493
+
494
+ @functools_wraps(func_)
495
+ async def _func(*args, **kwargs) -> Any:
496
+ """
497
+ Decorated function.
498
+
499
+ Parameters
500
+ ----------
501
+ args : Position arguments of function.
502
+ kwargs : Keyword arguments of function.
503
+
504
+ Returns
505
+ -------
506
+ Function return.
507
+ """
508
+
509
+ # Try execute.
510
+ try:
511
+ if iscoroutinefunction(func_):
512
+ result = await func_(*args, **kwargs)
319
513
  else:
320
- self.record(exc, stack, note)
514
+ result = func_(*args, **kwargs)
321
515
 
322
- raise
516
+ # Record.
517
+ except BaseException:
518
+ await self.record_catch(note, filter_type)
323
519
 
324
520
  return result
325
521
 
@@ -335,5 +531,3 @@ class DatabaseError(DatabaseBase):
335
531
  else:
336
532
  _func = _wrap(func)
337
533
  return _func
338
-
339
- __call__ = record