reykit 1.1.67__py3-none-any.whl → 1.1.68__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.
reykit/rschedule.py CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
 
12
12
  from typing import Any, Literal, TypedDict, NotRequired
13
+ from functools import wraps as functools_wraps
13
14
  from collections.abc import Callable
14
15
  from apscheduler.executors.pool import ThreadPoolExecutor
15
16
  from apscheduler.schedulers.background import BackgroundScheduler
@@ -54,15 +55,15 @@ class Schedule(Base):
54
55
  - `Database`: Automatic record to database.
55
56
  """
56
57
 
57
- # Set parameter.
58
+ # Build.
59
+
60
+ ## Scheduler.
58
61
  executor = ThreadPoolExecutor(max_workers)
59
62
  executors = {'default': executor}
60
63
  job_defaults = {
61
64
  'coalesce': coalesce,
62
65
  'max_instances': max_instances
63
66
  }
64
-
65
- # Instance.
66
67
  if block:
67
68
  scheduler = BlockingScheduler(
68
69
  executors=executors,
@@ -73,18 +74,20 @@ class Schedule(Base):
73
74
  executors=executors,
74
75
  job_defaults=job_defaults
75
76
  )
76
-
77
- # Set attribute.
78
77
  self.scheduler = scheduler
78
+
79
+ ## Database.
79
80
  self.database = database
80
-
81
- ## Database path name.
81
+
82
+ ### Database path name.
82
83
  self.db_names = {
83
84
  'base': 'base',
84
85
  'base.schedule': 'schedule',
85
- 'base.schedule_stats': 'schedule_stats'
86
+ 'base.stats_schedule': 'stats_schedule'
86
87
  }
87
88
 
89
+ self.notes: dict[str, str] = {}
90
+
88
91
 
89
92
  def start(self) -> None:
90
93
  """
@@ -136,12 +139,91 @@ class Schedule(Base):
136
139
  return jobs
137
140
 
138
141
 
142
+ def wrap_record_db(
143
+ self,
144
+ task: Callable,
145
+ note: str | None
146
+ ) -> None:
147
+ """
148
+ Decorator, record to database.
149
+
150
+ Parameters
151
+ ----------
152
+ task : Task.
153
+ note : Task note.
154
+ """
155
+
156
+
157
+ # Define.
158
+ @functools_wraps(task)
159
+ def _task(*args, **kwargs) -> None:
160
+ """
161
+ Decorated function.
162
+
163
+ Parameters
164
+ ----------
165
+ args : Position arguments of function.
166
+ kwargs : Keyword arguments of function.
167
+ """
168
+
169
+ # Handle parameter.
170
+ nonlocal task, note
171
+
172
+ # Status executing.
173
+ data = {
174
+ 'status': 0,
175
+ 'task': task.__name__,
176
+ 'note': note
177
+ }
178
+ conn = self.database.connect()
179
+ conn.execute_insert(
180
+ (self.db_names['base'], self.db_names['base.schedule']),
181
+ data
182
+ )
183
+ id_ = conn.variables['identity']
184
+ conn.commit()
185
+
186
+ # Try execute.
187
+
188
+ ## Record error.
189
+ task = self.database.error.wrap(task, note=note)
190
+
191
+ try:
192
+ task(*args, **kwargs)
193
+
194
+ # Status occurred error.
195
+ except BaseException:
196
+ data = {
197
+ 'id': id_,
198
+ 'status': 2
199
+ }
200
+ self.database.execute_update(
201
+ (self.db_names['base'], self.db_names['base.schedule']),
202
+ data
203
+ )
204
+ raise
205
+
206
+ # Status completed.
207
+ else:
208
+ data = {
209
+ 'id': id_,
210
+ 'status': 1
211
+ }
212
+ self.database.execute_update(
213
+ (self.db_names['base'], self.db_names['base.schedule']),
214
+ data
215
+ )
216
+
217
+ return _task
218
+
219
+
139
220
  def add_task(
140
221
  self,
141
222
  task: Callable,
142
223
  plan: dict[str, Any],
143
- *args: Any,
144
- **kwargs: Any
224
+ args: Any | None = None,
225
+ kwargs: Any | None = None,
226
+ note: str | None = None
145
227
  ) -> Job:
146
228
  """
147
229
  Add task.
@@ -152,6 +234,7 @@ class Schedule(Base):
152
234
  plan : Plan trigger keyword arguments.
153
235
  args : Task position arguments.
154
236
  kwargs : Task keyword arguments.
237
+ note : Task note.
155
238
 
156
239
  Returns
157
240
  -------
@@ -169,6 +252,11 @@ class Schedule(Base):
169
252
  }
170
253
 
171
254
  # Add.
255
+
256
+ ## Database.
257
+ if self.database is not None:
258
+ task = self.wrap_record_db(task, note)
259
+
172
260
  job = self.scheduler.add_job(
173
261
  task,
174
262
  trigger,
@@ -177,6 +265,9 @@ class Schedule(Base):
177
265
  **trigger_args
178
266
  )
179
267
 
268
+ # Note.
269
+ self.notes[job.id] = note
270
+
180
271
  return job
181
272
 
182
273
 
@@ -184,8 +275,9 @@ class Schedule(Base):
184
275
  self,
185
276
  task: Job | str,
186
277
  plan: dict[str, Any],
187
- *args: Any,
188
- **kwargs: Any
278
+ args: Any | None = None,
279
+ kwargs: Any | None = None,
280
+ note: str | None = None
189
281
  ) -> None:
190
282
  """
191
283
  Modify task.
@@ -196,6 +288,7 @@ class Schedule(Base):
196
288
  plan : Plan trigger keyword arguments.
197
289
  args : Task position arguments.
198
290
  kwargs : Task keyword arguments.
291
+ note : Task note.
199
292
  """
200
293
 
201
294
  # Handle parameter.
@@ -210,7 +303,7 @@ class Schedule(Base):
210
303
  if key != 'trigger'
211
304
  }
212
305
 
213
- # Modify trigger.
306
+ # Modify plan.
214
307
  if plan != {}:
215
308
  self.scheduler.reschedule_job(
216
309
  task,
@@ -224,11 +317,14 @@ class Schedule(Base):
224
317
  or kwargs != {}
225
318
  ):
226
319
  self.scheduler.modify_job(
227
- task.id,
320
+ task,
228
321
  args=args,
229
322
  kwargs=kwargs
230
323
  )
231
324
 
325
+ # Modify note.
326
+ self.notes[task] = note
327
+
232
328
 
233
329
  def remove_task(
234
330
  self,
@@ -310,14 +406,14 @@ class Schedule(Base):
310
406
  ## Database.
311
407
  databases = [
312
408
  {
313
- 'name': self.db_names['worm']
409
+ 'name': self.db_names['base']
314
410
  }
315
411
  ]
316
412
 
317
413
  ## Table.
318
414
  tables = [
319
415
 
320
- ### 'douban_media'.
416
+ ### 'schedule'.
321
417
  {
322
418
  'path': (self.db_names['base'], self.db_names['base.schedule']),
323
419
  'fields': [
@@ -336,123 +432,25 @@ class Schedule(Base):
336
432
  {
337
433
  'name': 'id',
338
434
  'type': 'int unsigned',
339
- 'constraint': 'NOT NULL',
340
- 'comment': 'Douban media ID.'
435
+ 'constraint': 'NOT NULL AUTO_INCREMENT',
436
+ 'comment': 'ID.'
341
437
  },
342
438
  {
343
- 'name': 'imdb',
344
- 'type': 'char(10)',
345
- 'comment': 'IMDb ID.'
346
- },
347
- {
348
- 'name': 'type',
349
- 'type': 'varchar(5)',
350
- 'constraint': 'NOT NULL',
351
- 'comment': 'Media type.'
352
- },
353
- {
354
- 'name': 'name',
355
- 'type': 'varchar(50)',
439
+ 'name': 'status',
440
+ 'type': 'tinyint',
356
441
  'constraint': 'NOT NULL',
357
- 'comment': 'Media name.'
442
+ 'comment': 'Schedule status, 0 is executing, 1 is completed, 2 is occurred error.'
358
443
  },
359
444
  {
360
- 'name': 'year',
361
- 'type': 'year',
445
+ 'name': 'task',
446
+ 'type': 'varchar(100)',
362
447
  'constraint': 'NOT NULL',
363
- 'comment': 'Release year.'
448
+ 'comment': 'Schedule task function name.'
364
449
  },
365
450
  {
366
- 'name': 'desc',
367
- 'type': 'varchar(1000)',
368
- 'comment': 'Media content description.'
369
- },
370
- {
371
- 'name': 'score',
372
- 'type': 'float',
373
- 'comment': 'Media score, [0,10].'
374
- },
375
- {
376
- 'name': 'score_count',
377
- 'type': 'int',
378
- 'comment': 'Media score count.'
379
- },
380
- {
381
- 'name': 'minute',
382
- 'type': 'smallint',
383
- 'comment': 'Movie or TV drama episode minute.'
384
- },
385
- {
386
- 'name': 'episode',
387
- 'type': 'smallint',
388
- 'comment': 'TV drama total episode number.'
389
- },
390
- {
391
- 'name': 'episode_now',
392
- 'type': 'smallint',
393
- 'comment': 'TV drama current episode number.'
394
- },
395
- {
396
- 'name': 'premiere',
397
- 'type': 'json',
398
- 'comment': 'Premiere region and date dictionary.'
399
- },
400
- {
401
- 'name': 'country',
402
- 'type': 'json',
403
- 'comment': 'Release country list.'
404
- },
405
- {
406
- 'name': 'class',
407
- 'type': 'json',
408
- 'comment': 'Class list.'
409
- },
410
- {
411
- 'name': 'director',
412
- 'type': 'json',
413
- 'comment': 'Director list.'
414
- },
415
- {
416
- 'name': 'star',
417
- 'type': 'json',
418
- 'comment': 'Star list.'
419
- },
420
- {
421
- 'name': 'scriptwriter',
422
- 'type': 'json',
423
- 'comment': 'Scriptwriter list.'
424
- },
425
- {
426
- 'name': 'language',
427
- 'type': 'json',
428
- 'comment': 'Language list.'
429
- },
430
- {
431
- 'name': 'alias',
432
- 'type': 'json',
433
- 'comment': 'Alias list.'
434
- },
435
- {
436
- 'name': 'comment',
437
- 'type': 'json',
438
- 'comment': 'Comment list.'
439
- },
440
- {
441
- 'name': 'image',
442
- 'type': 'varchar(150)',
443
- 'constraint': 'NOT NULL',
444
- 'comment': 'Picture image URL.'
445
- },
446
- {
447
- 'name': 'image_low',
448
- 'type': 'varchar(150)',
449
- 'constraint': 'NOT NULL',
450
- 'comment': 'Picture image low resolution URL.'
451
- },
452
- {
453
- 'name': 'video',
454
- 'type': 'varchar(150)',
455
- 'comment': 'Preview video Douban page URL.'
451
+ 'name': 'note',
452
+ 'type': 'varchar(500)',
453
+ 'comment': 'Schedule note.'
456
454
  }
457
455
  ],
458
456
  'primary': 'id',
@@ -470,19 +468,13 @@ class Schedule(Base):
470
468
  'comment': 'Record update time normal index.'
471
469
  },
472
470
  {
473
- 'name': 'u_imdb',
474
- 'fields': 'imdb',
475
- 'type': 'unique',
476
- 'comment': 'IMDb number unique index.'
477
- },
478
- {
479
- 'name': 'n_name',
480
- 'fields': 'name',
471
+ 'name': 'n_task',
472
+ 'fields': 'task',
481
473
  'type': 'noraml',
482
- 'comment': 'Media name normal index.'
474
+ 'comment': 'Schedule task function name normal index.'
483
475
  }
484
476
  ],
485
- 'comment': 'Douban media information table.'
477
+ 'comment': 'Schedule execute record table.'
486
478
  }
487
479
 
488
480
  ]
@@ -490,76 +482,60 @@ class Schedule(Base):
490
482
  ## View stats.
491
483
  views_stats = [
492
484
 
493
- ### 'schedule_stats'.
485
+ ### 'stats_schedule'.
494
486
  {
495
- 'path': (self.db_names['base'], self.db_names['base.schedule_stats']),
487
+ 'path': (self.db_names['base'], self.db_names['base.stats_schedule']),
496
488
  'items': [
497
489
  {
498
490
  'name': 'count',
499
491
  'select': (
500
492
  'SELECT COUNT(1)\n'
501
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
493
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`'
502
494
  ),
503
- 'comment': 'Media count.'
495
+ 'comment': 'Schedule count.'
504
496
  },
505
497
  {
506
498
  'name': 'past_day_count',
507
499
  'select': (
508
500
  'SELECT COUNT(1)\n'
509
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
501
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`\n'
510
502
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
511
503
  ),
512
- 'comment': 'Media count in the past day.'
504
+ 'comment': 'Schedule count in the past day.'
513
505
  },
514
506
  {
515
507
  'name': 'past_week_count',
516
508
  'select': (
517
509
  'SELECT COUNT(1)\n'
518
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
510
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`\n'
519
511
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
520
512
  ),
521
- 'comment': 'Media count in the past week.'
513
+ 'comment': 'Schedule count in the past week.'
522
514
  },
523
515
  {
524
516
  'name': 'past_month_count',
525
517
  'select': (
526
518
  'SELECT COUNT(1)\n'
527
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
519
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`\n'
528
520
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
529
521
  ),
530
- 'comment': 'Media count in the past month.'
531
- },
532
- {
533
- 'name': 'avg_score',
534
- 'select': (
535
- 'SELECT ROUND(AVG(`score`), 1)\n'
536
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
537
- ),
538
- 'comment': 'Media average score.'
522
+ 'comment': 'Schedule count in the past month.'
539
523
  },
540
524
  {
541
- 'name': 'score_count',
525
+ 'name': 'task_count',
542
526
  'select': (
543
- 'SELECT FORMAT(SUM(`score_count`), 0)\n'
544
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
527
+ 'SELECT COUNT(DISTINCT `task`)\n'
528
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`'
545
529
  ),
546
- 'comment': 'Media score count.'
530
+ 'comment': 'Task count.'
547
531
  },
548
532
  {
549
- 'name': 'last_create_time',
550
- 'select': (
551
- 'SELECT MAX(`create_time`)\n'
552
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
553
- ),
554
- 'comment': 'Media last record create time.'
555
- },
556
- {
557
- 'name': 'last_update_time',
533
+ 'name': 'last_time',
558
534
  'select': (
559
535
  'SELECT IFNULL(MAX(`update_time`), MAX(`create_time`))\n'
560
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
536
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`'
561
537
  ),
562
- 'comment': 'Media last record update time.'
538
+ 'comment': 'Schedule last record time.'
563
539
  }
564
540
  ]
565
541
 
@@ -570,5 +546,8 @@ class Schedule(Base):
570
546
  # Build.
571
547
  self.database.build.build(databases, tables, views_stats=views_stats)
572
548
 
549
+ ## Error.
550
+ self.database.error.build_db()
551
+
573
552
 
574
553
  __iter__ = tasks
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reykit
3
- Version: 1.1.67
3
+ Version: 1.1.68
4
4
  Summary: Kit method set.
5
5
  Project-URL: homepage, https://github.com/reyxbo/reykit/
6
6
  Author-email: Rey <reyxbo@163.com>
@@ -11,7 +11,7 @@ reykit/rnum.py,sha256=PhG4V_BkVfCJUsbpMDN1umGZly1Hsus80TW8bpyBtyY,3653
11
11
  reykit/ros.py,sha256=Yi_mfYzVHwjjUZke0BNX7PKFLZpoT5NRyj5aDOSNQRU,46911
12
12
  reykit/rrand.py,sha256=4VwooITgox54_GonELcJfcIpStDi-UJchpnyWKnyeIA,8606
13
13
  reykit/rre.py,sha256=1qva7xatKVE9qC2j7IujjXSM59qxHWwTYpiizFFQ8Xo,6024
14
- reykit/rschedule.py,sha256=UfvreJ3QBvXxZAJOPZosI4Zp5isPOdgPn-oLTFeLD0k,17238
14
+ reykit/rschedule.py,sha256=uUSZyWAjurkWPlvDO57OgRLAreeE7WHOV0J_MG6S-zY,14985
15
15
  reykit/rstdout.py,sha256=yesWo7wIGablpyAu-2J2Gw11Qp3GdQjGICTyIcvLyt4,8200
16
16
  reykit/rsys.py,sha256=AP62KyN40flCeQJBclfJq8shachSAFT0LkVjiKsXkrw,24946
17
17
  reykit/rtable.py,sha256=UQ-JlwjssMR3gY1iY-VGQEKQ5_BZabpJy6TL7Fx19c4,12200
@@ -22,7 +22,7 @@ reykit/rwrap.py,sha256=FEmeK_fboJ-OyXeJf8bilc7U2ph8xIbZGNHb6fLCy2c,15063
22
22
  reykit/rzip.py,sha256=BGEONswuBZxQ-zcgd_xp2fcvYesC9AmKaaXWvnT3bTI,3456
23
23
  reykit/rdll/__init__.py,sha256=nLSb8onBm2ilyoxzpDzUeGfSCKwkLEesIhzK3LiJ8mk,701
24
24
  reykit/rdll/rdll_core.py,sha256=o6-rKcTQgxZQe0kD3GnwyNb3KL9IogzgCQNOmYLMm7A,5086
25
- reykit-1.1.67.dist-info/METADATA,sha256=BGZWI7zUlK8aPG0rOlVMJENMKp12uK86Q6cYaLYaDE4,1872
26
- reykit-1.1.67.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
- reykit-1.1.67.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
28
- reykit-1.1.67.dist-info/RECORD,,
25
+ reykit-1.1.68.dist-info/METADATA,sha256=VkV4-QQHi1iAAq-8m7WMj0KO9qyqIsRkNfes0n2l6RM,1872
26
+ reykit-1.1.68.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
+ reykit-1.1.68.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
28
+ reykit-1.1.68.dist-info/RECORD,,