reykit 1.1.67__py3-none-any.whl → 1.1.69__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,26 +74,22 @@ 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
+ ### Start.
80
+ self.scheduler.start()
81
+
82
+ ## Database.
79
83
  self.database = database
80
-
81
- ## Database path name.
84
+
85
+ ### Database path name.
82
86
  self.db_names = {
83
87
  'base': 'base',
84
88
  'base.schedule': 'schedule',
85
- 'base.schedule_stats': 'schedule_stats'
89
+ 'base.stats_schedule': 'stats_schedule'
86
90
  }
87
91
 
88
-
89
- def start(self) -> None:
90
- """
91
- Start scheduler.
92
- """
93
-
94
- # Start.
95
- self.scheduler.start()
92
+ self.notes: dict[str, str] = {}
96
93
 
97
94
 
98
95
  def pause(self) -> None:
@@ -136,12 +133,91 @@ class Schedule(Base):
136
133
  return jobs
137
134
 
138
135
 
136
+ def wrap_record_db(
137
+ self,
138
+ task: Callable,
139
+ note: str | None
140
+ ) -> None:
141
+ """
142
+ Decorator, record to database.
143
+
144
+ Parameters
145
+ ----------
146
+ task : Task.
147
+ note : Task note.
148
+ """
149
+
150
+
151
+ # Define.
152
+ @functools_wraps(task)
153
+ def _task(*args, **kwargs) -> None:
154
+ """
155
+ Decorated function.
156
+
157
+ Parameters
158
+ ----------
159
+ args : Position arguments of function.
160
+ kwargs : Keyword arguments of function.
161
+ """
162
+
163
+ # Handle parameter.
164
+ nonlocal task, note
165
+
166
+ # Status executing.
167
+ data = {
168
+ 'status': 0,
169
+ 'task': task.__name__,
170
+ 'note': note
171
+ }
172
+ conn = self.database.connect()
173
+ conn.execute_insert(
174
+ (self.db_names['base'], self.db_names['base.schedule']),
175
+ data
176
+ )
177
+ id_ = conn.variables['identity']
178
+ conn.commit()
179
+
180
+ # Try execute.
181
+
182
+ ## Record error.
183
+ task = self.database.error.wrap(task, note=note)
184
+
185
+ try:
186
+ task(*args, **kwargs)
187
+
188
+ # Status occurred error.
189
+ except BaseException:
190
+ data = {
191
+ 'id': id_,
192
+ 'status': 2
193
+ }
194
+ self.database.execute_update(
195
+ (self.db_names['base'], self.db_names['base.schedule']),
196
+ data
197
+ )
198
+ raise
199
+
200
+ # Status completed.
201
+ else:
202
+ data = {
203
+ 'id': id_,
204
+ 'status': 1
205
+ }
206
+ self.database.execute_update(
207
+ (self.db_names['base'], self.db_names['base.schedule']),
208
+ data
209
+ )
210
+
211
+ return _task
212
+
213
+
139
214
  def add_task(
140
215
  self,
141
216
  task: Callable,
142
217
  plan: dict[str, Any],
143
- *args: Any,
144
- **kwargs: Any
218
+ args: Any | None = None,
219
+ kwargs: Any | None = None,
220
+ note: str | None = None
145
221
  ) -> Job:
146
222
  """
147
223
  Add task.
@@ -152,6 +228,7 @@ class Schedule(Base):
152
228
  plan : Plan trigger keyword arguments.
153
229
  args : Task position arguments.
154
230
  kwargs : Task keyword arguments.
231
+ note : Task note.
155
232
 
156
233
  Returns
157
234
  -------
@@ -169,6 +246,11 @@ class Schedule(Base):
169
246
  }
170
247
 
171
248
  # Add.
249
+
250
+ ## Database.
251
+ if self.database is not None:
252
+ task = self.wrap_record_db(task, note)
253
+
172
254
  job = self.scheduler.add_job(
173
255
  task,
174
256
  trigger,
@@ -177,6 +259,9 @@ class Schedule(Base):
177
259
  **trigger_args
178
260
  )
179
261
 
262
+ # Note.
263
+ self.notes[job.id] = note
264
+
180
265
  return job
181
266
 
182
267
 
@@ -184,8 +269,9 @@ class Schedule(Base):
184
269
  self,
185
270
  task: Job | str,
186
271
  plan: dict[str, Any],
187
- *args: Any,
188
- **kwargs: Any
272
+ args: Any | None = None,
273
+ kwargs: Any | None = None,
274
+ note: str | None = None
189
275
  ) -> None:
190
276
  """
191
277
  Modify task.
@@ -196,6 +282,7 @@ class Schedule(Base):
196
282
  plan : Plan trigger keyword arguments.
197
283
  args : Task position arguments.
198
284
  kwargs : Task keyword arguments.
285
+ note : Task note.
199
286
  """
200
287
 
201
288
  # Handle parameter.
@@ -210,7 +297,7 @@ class Schedule(Base):
210
297
  if key != 'trigger'
211
298
  }
212
299
 
213
- # Modify trigger.
300
+ # Modify plan.
214
301
  if plan != {}:
215
302
  self.scheduler.reschedule_job(
216
303
  task,
@@ -224,11 +311,14 @@ class Schedule(Base):
224
311
  or kwargs != {}
225
312
  ):
226
313
  self.scheduler.modify_job(
227
- task.id,
314
+ task,
228
315
  args=args,
229
316
  kwargs=kwargs
230
317
  )
231
318
 
319
+ # Modify note.
320
+ self.notes[task] = note
321
+
232
322
 
233
323
  def remove_task(
234
324
  self,
@@ -310,14 +400,14 @@ class Schedule(Base):
310
400
  ## Database.
311
401
  databases = [
312
402
  {
313
- 'name': self.db_names['worm']
403
+ 'name': self.db_names['base']
314
404
  }
315
405
  ]
316
406
 
317
407
  ## Table.
318
408
  tables = [
319
409
 
320
- ### 'douban_media'.
410
+ ### 'schedule'.
321
411
  {
322
412
  'path': (self.db_names['base'], self.db_names['base.schedule']),
323
413
  'fields': [
@@ -336,123 +426,25 @@ class Schedule(Base):
336
426
  {
337
427
  'name': 'id',
338
428
  'type': 'int unsigned',
339
- 'constraint': 'NOT NULL',
340
- 'comment': 'Douban media ID.'
341
- },
342
- {
343
- 'name': 'imdb',
344
- 'type': 'char(10)',
345
- 'comment': 'IMDb ID.'
429
+ 'constraint': 'NOT NULL AUTO_INCREMENT',
430
+ 'comment': 'ID.'
346
431
  },
347
432
  {
348
- 'name': 'type',
349
- 'type': 'varchar(5)',
433
+ 'name': 'status',
434
+ 'type': 'tinyint',
350
435
  'constraint': 'NOT NULL',
351
- 'comment': 'Media type.'
436
+ 'comment': 'Schedule status, 0 is executing, 1 is completed, 2 is occurred error.'
352
437
  },
353
438
  {
354
- 'name': 'name',
355
- 'type': 'varchar(50)',
439
+ 'name': 'task',
440
+ 'type': 'varchar(100)',
356
441
  'constraint': 'NOT NULL',
357
- 'comment': 'Media name.'
358
- },
359
- {
360
- 'name': 'year',
361
- 'type': 'year',
362
- 'constraint': 'NOT NULL',
363
- 'comment': 'Release year.'
364
- },
365
- {
366
- 'name': 'desc',
367
- 'type': 'varchar(1000)',
368
- 'comment': 'Media content description.'
442
+ 'comment': 'Schedule task function name.'
369
443
  },
370
444
  {
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.'
445
+ 'name': 'note',
446
+ 'type': 'varchar(500)',
447
+ 'comment': 'Schedule note.'
456
448
  }
457
449
  ],
458
450
  'primary': 'id',
@@ -470,19 +462,13 @@ class Schedule(Base):
470
462
  'comment': 'Record update time normal index.'
471
463
  },
472
464
  {
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',
465
+ 'name': 'n_task',
466
+ 'fields': 'task',
481
467
  'type': 'noraml',
482
- 'comment': 'Media name normal index.'
468
+ 'comment': 'Schedule task function name normal index.'
483
469
  }
484
470
  ],
485
- 'comment': 'Douban media information table.'
471
+ 'comment': 'Schedule execute record table.'
486
472
  }
487
473
 
488
474
  ]
@@ -490,76 +476,60 @@ class Schedule(Base):
490
476
  ## View stats.
491
477
  views_stats = [
492
478
 
493
- ### 'schedule_stats'.
479
+ ### 'stats_schedule'.
494
480
  {
495
- 'path': (self.db_names['base'], self.db_names['base.schedule_stats']),
481
+ 'path': (self.db_names['base'], self.db_names['base.stats_schedule']),
496
482
  'items': [
497
483
  {
498
484
  'name': 'count',
499
485
  'select': (
500
486
  'SELECT COUNT(1)\n'
501
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
487
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`'
502
488
  ),
503
- 'comment': 'Media count.'
489
+ 'comment': 'Schedule count.'
504
490
  },
505
491
  {
506
492
  'name': 'past_day_count',
507
493
  'select': (
508
494
  'SELECT COUNT(1)\n'
509
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
495
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`\n'
510
496
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
511
497
  ),
512
- 'comment': 'Media count in the past day.'
498
+ 'comment': 'Schedule count in the past day.'
513
499
  },
514
500
  {
515
501
  'name': 'past_week_count',
516
502
  'select': (
517
503
  'SELECT COUNT(1)\n'
518
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
504
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`\n'
519
505
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
520
506
  ),
521
- 'comment': 'Media count in the past week.'
507
+ 'comment': 'Schedule count in the past week.'
522
508
  },
523
509
  {
524
510
  'name': 'past_month_count',
525
511
  'select': (
526
512
  'SELECT COUNT(1)\n'
527
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
513
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`\n'
528
514
  'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
529
515
  ),
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.'
516
+ 'comment': 'Schedule count in the past month.'
539
517
  },
540
518
  {
541
- 'name': 'score_count',
519
+ 'name': 'task_count',
542
520
  'select': (
543
- 'SELECT FORMAT(SUM(`score_count`), 0)\n'
544
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
521
+ 'SELECT COUNT(DISTINCT `task`)\n'
522
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`'
545
523
  ),
546
- 'comment': 'Media score count.'
524
+ 'comment': 'Task count.'
547
525
  },
548
526
  {
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',
527
+ 'name': 'last_time',
558
528
  'select': (
559
529
  'SELECT IFNULL(MAX(`update_time`), MAX(`create_time`))\n'
560
- f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
530
+ f'FROM `{self.db_names['base']}`.`{self.db_names['base.schedule']}`'
561
531
  ),
562
- 'comment': 'Media last record update time.'
532
+ 'comment': 'Schedule last record time.'
563
533
  }
564
534
  ]
565
535
 
@@ -570,5 +540,8 @@ class Schedule(Base):
570
540
  # Build.
571
541
  self.database.build.build(databases, tables, views_stats=views_stats)
572
542
 
543
+ ## Error.
544
+ self.database.error.build_db()
545
+
573
546
 
574
547
  __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.69
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=FC_8mfF9mj7EmmcDDgtVPEt9X1DST_iwNK15SctFSws,14901
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.69.dist-info/METADATA,sha256=j_h9WMxqDklZbv-Ch2SGAm7qWqW-nlLfqD_SUVVlWf4,1872
26
+ reykit-1.1.69.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
+ reykit-1.1.69.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
28
+ reykit-1.1.69.dist-info/RECORD,,