reykit 1.1.65__py3-none-any.whl → 1.1.67__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/rnet.py +2 -3
- reykit/ros.py +5 -1
- reykit/rschedule.py +334 -33
- {reykit-1.1.65.dist-info → reykit-1.1.67.dist-info}/METADATA +1 -1
- {reykit-1.1.65.dist-info → reykit-1.1.67.dist-info}/RECORD +7 -7
- {reykit-1.1.65.dist-info → reykit-1.1.67.dist-info}/WHEEL +0 -0
- {reykit-1.1.65.dist-info → reykit-1.1.67.dist-info}/licenses/LICENSE +0 -0
reykit/rnet.py
CHANGED
@@ -432,9 +432,8 @@ def download(url: str, path: str | None = None) -> str:
|
|
432
432
|
else:
|
433
433
|
file_name = None
|
434
434
|
if file_name is None:
|
435
|
-
file_type_obj =
|
436
|
-
|
437
|
-
file_name = 'download.' + file_type_obj.EXTENSION
|
435
|
+
file_type_obj = filetype_guess(content)
|
436
|
+
file_name = 'download.' + file_type_obj.EXTENSION
|
438
437
|
file_name = file_name or 'download'
|
439
438
|
path = os_abspath(file_name)
|
440
439
|
|
reykit/ros.py
CHANGED
@@ -352,7 +352,7 @@ class File(Base):
|
|
352
352
|
|
353
353
|
|
354
354
|
@overload
|
355
|
-
def open(self, mode: OpenBinaryMode = 'wb+'
|
355
|
+
def open(self, mode: OpenBinaryMode = 'wb+') -> BinaryIO: ...
|
356
356
|
|
357
357
|
@overload
|
358
358
|
def open(self, mode: OpenTextMode, encode: str = 'utf-8') -> TextIO: ...
|
@@ -371,6 +371,10 @@ class File(Base):
|
|
371
371
|
IO object.
|
372
372
|
"""
|
373
373
|
|
374
|
+
# Handle parameter.
|
375
|
+
if 'b' in mode:
|
376
|
+
encode = None
|
377
|
+
|
374
378
|
# Open.
|
375
379
|
io = open(self.path, mode, encoding=encode)
|
376
380
|
|
reykit/rschedule.py
CHANGED
@@ -9,14 +9,15 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from typing import Any, Literal
|
12
|
+
from typing import Any, Literal, TypedDict, NotRequired
|
13
13
|
from collections.abc import Callable
|
14
14
|
from apscheduler.executors.pool import ThreadPoolExecutor
|
15
15
|
from apscheduler.schedulers.background import BackgroundScheduler
|
16
16
|
from apscheduler.schedulers.blocking import BlockingScheduler
|
17
17
|
from apscheduler.job import Job
|
18
|
+
from reydb.rdb import Database
|
18
19
|
|
19
|
-
from .rbase import Base
|
20
|
+
from .rbase import Base, throw
|
20
21
|
|
21
22
|
|
22
23
|
__all__ = (
|
@@ -27,6 +28,7 @@ __all__ = (
|
|
27
28
|
class Schedule(Base):
|
28
29
|
"""
|
29
30
|
Schedule type.
|
31
|
+
Can create database used `self.build_db` method.
|
30
32
|
"""
|
31
33
|
|
32
34
|
|
@@ -35,7 +37,8 @@ class Schedule(Base):
|
|
35
37
|
max_workers: int = 10,
|
36
38
|
max_instances: int = 1,
|
37
39
|
coalesce: bool = True,
|
38
|
-
block: bool = False
|
40
|
+
block: bool = False,
|
41
|
+
database: Database | None = None
|
39
42
|
) -> None:
|
40
43
|
"""
|
41
44
|
Build instance attributes.
|
@@ -46,6 +49,9 @@ class Schedule(Base):
|
|
46
49
|
max_instances : Maximum number of synchronized executions of tasks with the same ID.
|
47
50
|
coalesce : Whether to coalesce tasks with the same ID.
|
48
51
|
block : Whether to block.
|
52
|
+
database : `Database` instance.
|
53
|
+
- `None`: Not use database.
|
54
|
+
- `Database`: Automatic record to database.
|
49
55
|
"""
|
50
56
|
|
51
57
|
# Set parameter.
|
@@ -70,6 +76,14 @@ class Schedule(Base):
|
|
70
76
|
|
71
77
|
# Set attribute.
|
72
78
|
self.scheduler = scheduler
|
79
|
+
self.database = database
|
80
|
+
|
81
|
+
## Database path name.
|
82
|
+
self.db_names = {
|
83
|
+
'base': 'base',
|
84
|
+
'base.schedule': 'schedule',
|
85
|
+
'base.schedule_stats': 'schedule_stats'
|
86
|
+
}
|
73
87
|
|
74
88
|
|
75
89
|
def start(self) -> None:
|
@@ -125,10 +139,9 @@ class Schedule(Base):
|
|
125
139
|
def add_task(
|
126
140
|
self,
|
127
141
|
task: Callable,
|
128
|
-
|
129
|
-
args:
|
130
|
-
kwargs:
|
131
|
-
**trigger_kwargs: Any
|
142
|
+
plan: dict[str, Any],
|
143
|
+
*args: Any,
|
144
|
+
**kwargs: Any
|
132
145
|
) -> Job:
|
133
146
|
"""
|
134
147
|
Add task.
|
@@ -136,23 +149,32 @@ class Schedule(Base):
|
|
136
149
|
Parameters
|
137
150
|
----------
|
138
151
|
task : Task function.
|
139
|
-
|
152
|
+
plan : Plan trigger keyword arguments.
|
140
153
|
args : Task position arguments.
|
141
154
|
kwargs : Task keyword arguments.
|
142
|
-
trigger_kwargs : Trigger keyword arguments.
|
143
155
|
|
144
156
|
Returns
|
145
157
|
-------
|
146
158
|
Task instance.
|
147
159
|
"""
|
148
160
|
|
161
|
+
# Handle parameter.
|
162
|
+
if plan is None:
|
163
|
+
plan = {}
|
164
|
+
trigger = plan.get('trigger')
|
165
|
+
trigger_args = {
|
166
|
+
key: value
|
167
|
+
for key, value in plan.items()
|
168
|
+
if key != 'trigger'
|
169
|
+
}
|
170
|
+
|
149
171
|
# Add.
|
150
172
|
job = self.scheduler.add_job(
|
151
173
|
task,
|
152
174
|
trigger,
|
153
175
|
args,
|
154
176
|
kwargs,
|
155
|
-
**
|
177
|
+
**trigger_args
|
156
178
|
)
|
157
179
|
|
158
180
|
return job
|
@@ -161,10 +183,9 @@ class Schedule(Base):
|
|
161
183
|
def modify_task(
|
162
184
|
self,
|
163
185
|
task: Job | str,
|
164
|
-
|
165
|
-
args:
|
166
|
-
kwargs:
|
167
|
-
**trigger_kwargs: Any
|
186
|
+
plan: dict[str, Any],
|
187
|
+
*args: Any,
|
188
|
+
**kwargs: Any
|
168
189
|
) -> None:
|
169
190
|
"""
|
170
191
|
Modify task.
|
@@ -172,35 +193,40 @@ class Schedule(Base):
|
|
172
193
|
Parameters
|
173
194
|
----------
|
174
195
|
task : Task instance or ID.
|
175
|
-
|
196
|
+
plan : Plan trigger keyword arguments.
|
176
197
|
args : Task position arguments.
|
177
198
|
kwargs : Task keyword arguments.
|
178
|
-
trigger_kwargs : Trigger keyword arguments.
|
179
199
|
"""
|
180
200
|
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
201
|
+
# Handle parameter.
|
202
|
+
if type(task) == Job:
|
203
|
+
task = task.id
|
204
|
+
if plan is None:
|
205
|
+
plan = {}
|
206
|
+
trigger = plan.get('trigger')
|
207
|
+
trigger_args = {
|
208
|
+
key: value
|
209
|
+
for key, value in plan.items()
|
210
|
+
if key != 'trigger'
|
211
|
+
}
|
187
212
|
|
188
|
-
|
189
|
-
if
|
190
|
-
self.scheduler.
|
191
|
-
task
|
192
|
-
|
213
|
+
# Modify trigger.
|
214
|
+
if plan != {}:
|
215
|
+
self.scheduler.reschedule_job(
|
216
|
+
task,
|
217
|
+
trigger=trigger,
|
218
|
+
**trigger_args
|
193
219
|
)
|
194
220
|
|
195
|
-
#
|
221
|
+
# Modify arguments.
|
196
222
|
if (
|
197
|
-
|
198
|
-
or
|
223
|
+
args != ()
|
224
|
+
or kwargs != {}
|
199
225
|
):
|
200
|
-
self.scheduler.
|
226
|
+
self.scheduler.modify_job(
|
201
227
|
task.id,
|
202
|
-
|
203
|
-
|
228
|
+
args=args,
|
229
|
+
kwargs=kwargs
|
204
230
|
)
|
205
231
|
|
206
232
|
|
@@ -270,4 +296,279 @@ class Schedule(Base):
|
|
270
296
|
self.scheduler.resume_job(id_)
|
271
297
|
|
272
298
|
|
299
|
+
def build_db(self) -> None:
|
300
|
+
"""
|
301
|
+
Check and build all standard databases and tables, by `self.db_names`.
|
302
|
+
"""
|
303
|
+
|
304
|
+
# Check.
|
305
|
+
if self.database is None:
|
306
|
+
throw(ValueError, self.database)
|
307
|
+
|
308
|
+
# Set parameter.
|
309
|
+
|
310
|
+
## Database.
|
311
|
+
databases = [
|
312
|
+
{
|
313
|
+
'name': self.db_names['worm']
|
314
|
+
}
|
315
|
+
]
|
316
|
+
|
317
|
+
## Table.
|
318
|
+
tables = [
|
319
|
+
|
320
|
+
### 'douban_media'.
|
321
|
+
{
|
322
|
+
'path': (self.db_names['base'], self.db_names['base.schedule']),
|
323
|
+
'fields': [
|
324
|
+
{
|
325
|
+
'name': 'create_time',
|
326
|
+
'type': 'datetime',
|
327
|
+
'constraint': 'NOT NULL DEFAULT CURRENT_TIMESTAMP',
|
328
|
+
'comment': 'Record create time.'
|
329
|
+
},
|
330
|
+
{
|
331
|
+
'name': 'update_time',
|
332
|
+
'type': 'datetime',
|
333
|
+
'constraint': 'DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP',
|
334
|
+
'comment': 'Record update time.'
|
335
|
+
},
|
336
|
+
{
|
337
|
+
'name': 'id',
|
338
|
+
'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.'
|
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)',
|
356
|
+
'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.'
|
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.'
|
456
|
+
}
|
457
|
+
],
|
458
|
+
'primary': 'id',
|
459
|
+
'indexes': [
|
460
|
+
{
|
461
|
+
'name': 'n_create_time',
|
462
|
+
'fields': 'create_time',
|
463
|
+
'type': 'noraml',
|
464
|
+
'comment': 'Record create time normal index.'
|
465
|
+
},
|
466
|
+
{
|
467
|
+
'name': 'n_update_time',
|
468
|
+
'fields': 'update_time',
|
469
|
+
'type': 'noraml',
|
470
|
+
'comment': 'Record update time normal index.'
|
471
|
+
},
|
472
|
+
{
|
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',
|
481
|
+
'type': 'noraml',
|
482
|
+
'comment': 'Media name normal index.'
|
483
|
+
}
|
484
|
+
],
|
485
|
+
'comment': 'Douban media information table.'
|
486
|
+
}
|
487
|
+
|
488
|
+
]
|
489
|
+
|
490
|
+
## View stats.
|
491
|
+
views_stats = [
|
492
|
+
|
493
|
+
### 'schedule_stats'.
|
494
|
+
{
|
495
|
+
'path': (self.db_names['base'], self.db_names['base.schedule_stats']),
|
496
|
+
'items': [
|
497
|
+
{
|
498
|
+
'name': 'count',
|
499
|
+
'select': (
|
500
|
+
'SELECT COUNT(1)\n'
|
501
|
+
f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
|
502
|
+
),
|
503
|
+
'comment': 'Media count.'
|
504
|
+
},
|
505
|
+
{
|
506
|
+
'name': 'past_day_count',
|
507
|
+
'select': (
|
508
|
+
'SELECT COUNT(1)\n'
|
509
|
+
f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
|
510
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) = 0'
|
511
|
+
),
|
512
|
+
'comment': 'Media count in the past day.'
|
513
|
+
},
|
514
|
+
{
|
515
|
+
'name': 'past_week_count',
|
516
|
+
'select': (
|
517
|
+
'SELECT COUNT(1)\n'
|
518
|
+
f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
|
519
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 6'
|
520
|
+
),
|
521
|
+
'comment': 'Media count in the past week.'
|
522
|
+
},
|
523
|
+
{
|
524
|
+
'name': 'past_month_count',
|
525
|
+
'select': (
|
526
|
+
'SELECT COUNT(1)\n'
|
527
|
+
f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`\n'
|
528
|
+
'WHERE TIMESTAMPDIFF(DAY, `create_time`, NOW()) <= 29'
|
529
|
+
),
|
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.'
|
539
|
+
},
|
540
|
+
{
|
541
|
+
'name': 'score_count',
|
542
|
+
'select': (
|
543
|
+
'SELECT FORMAT(SUM(`score_count`), 0)\n'
|
544
|
+
f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
|
545
|
+
),
|
546
|
+
'comment': 'Media score count.'
|
547
|
+
},
|
548
|
+
{
|
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',
|
558
|
+
'select': (
|
559
|
+
'SELECT IFNULL(MAX(`update_time`), MAX(`create_time`))\n'
|
560
|
+
f'FROM `{self.db_names['worm']}`.`{self.db_names['worm.douban_media']}`'
|
561
|
+
),
|
562
|
+
'comment': 'Media last record update time.'
|
563
|
+
}
|
564
|
+
]
|
565
|
+
|
566
|
+
}
|
567
|
+
|
568
|
+
]
|
569
|
+
|
570
|
+
# Build.
|
571
|
+
self.database.build.build(databases, tables, views_stats=views_stats)
|
572
|
+
|
573
|
+
|
273
574
|
__iter__ = tasks
|
@@ -6,12 +6,12 @@ reykit/remail.py,sha256=l4HGKXdfHNBxyBT3YxeZyQhfecbElqTqSAGInwWhap8,6723
|
|
6
6
|
reykit/rimage.py,sha256=lNN2iMpvSMqh-nPTpxrA9yHy43EA5WoYdxKYhqPwMgk,6154
|
7
7
|
reykit/rlog.py,sha256=TRAWaVG9KTgzeNjN-FXkcvBmvq1IhICgawllQEGoUdg,25745
|
8
8
|
reykit/rmonkey.py,sha256=Dj2GBzBDFXbo0Z-5f8Zep4dfbaIw1bo1FUmC31xvDuk,7929
|
9
|
-
reykit/rnet.py,sha256=
|
9
|
+
reykit/rnet.py,sha256=AfMUcAW26zNauW6PeS3GYkLJcJu_82g1tkZGnc--Qto,16848
|
10
10
|
reykit/rnum.py,sha256=PhG4V_BkVfCJUsbpMDN1umGZly1Hsus80TW8bpyBtyY,3653
|
11
|
-
reykit/ros.py,sha256=
|
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=
|
14
|
+
reykit/rschedule.py,sha256=UfvreJ3QBvXxZAJOPZosI4Zp5isPOdgPn-oLTFeLD0k,17238
|
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.
|
26
|
-
reykit-1.1.
|
27
|
-
reykit-1.1.
|
28
|
-
reykit-1.1.
|
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,,
|
File without changes
|
File without changes
|