1
1
import math
2
2
from datetime import timedelta , datetime
3
- from typing import Dict , Any , Optional
3
+ from typing import Dict , Any , Optional , List , Tuple , Callable
4
4
5
5
import croniter
6
6
from django .conf import settings as django_settings
29
29
def _get_task_for_job (job : JobModel ) -> Optional ["Task" ]:
30
30
if job .task_type is None or job .scheduled_task_id is None :
31
31
return None
32
- task = Task .objects .filter (id = job .scheduled_task_id ).first ()
32
+ task : Task = Task .objects .filter (id = job .scheduled_task_id ).first ()
33
33
return task
34
34
35
35
36
- def failure_callback (job : JobModel , connection , result , * args , ** kwargs ) :
36
+ def failure_callback (job : JobModel , connection : ConnectionType , result : Any , * args : Any , ** kwargs : Any ) -> None :
37
37
task = _get_task_for_job (job )
38
38
if task is None :
39
39
logger .warn (f"Could not find task for job { job .name } " )
@@ -48,7 +48,7 @@ def failure_callback(job: JobModel, connection, result, *args, **kwargs):
48
48
task .save (schedule_job = True , clean = False )
49
49
50
50
51
- def success_callback (job : JobModel , connection : ConnectionType , result : Any , * args , ** kwargs ) :
51
+ def success_callback (job : JobModel , connection : ConnectionType , result : Any , * args : Any , ** kwargs : Any ) -> None :
52
52
task = _get_task_for_job (job )
53
53
if task is None :
54
54
logger .warn (f"Could not find task for job { job .name } " )
@@ -59,7 +59,7 @@ def success_callback(job: JobModel, connection: ConnectionType, result: Any, *ar
59
59
task .save (schedule_job = True , clean = False )
60
60
61
61
62
- def get_queue_choices ():
62
+ def get_queue_choices () -> List [ Tuple [ str , str ]] :
63
63
queue_names = get_queue_names ()
64
64
return [(queue , queue ) for queue in queue_names ]
65
65
@@ -176,20 +176,20 @@ class TimeUnits(models.TextChoices):
176
176
),
177
177
)
178
178
179
- def callable_func (self ):
179
+ def callable_func (self )-> Callable :
180
180
"""Translate callable string to callable"""
181
181
return utils .callable_func (self .callable )
182
182
183
- @admin .display (boolean = True , description = _ ("is scheduled?" ))
183
+ @admin .display (boolean = True , description = _ ("is scheduled?" )) # type: ignore[misc]
184
184
def is_scheduled (self ) -> bool :
185
185
"""Check whether a next job for this task is queued/scheduled to be executed"""
186
186
if self .job_name is None : # no job_id => is not scheduled
187
187
return False
188
188
# check whether job_id is in scheduled/queued/active jobs
189
189
res = (
190
- (self .job_name in self .rqueue .scheduled_job_registry .all ())
191
- or (self .job_name in self .rqueue .queued_job_registry .all ())
192
- or (self .job_name in self .rqueue .active_job_registry .all ())
190
+ (self .job_name in self .rqueue .scheduled_job_registry .all ())
191
+ or (self .job_name in self .rqueue .queued_job_registry .all ())
192
+ or (self .job_name in self .rqueue .active_job_registry .all ())
193
193
)
194
194
# If the job_id is not scheduled/queued/started,
195
195
# update the job_id to None. (The job_id belongs to a previous run which is completed)
@@ -198,29 +198,29 @@ def is_scheduled(self) -> bool:
198
198
super (Task , self ).save ()
199
199
return res
200
200
201
- @admin .display (description = "Callable" )
201
+ @admin .display (description = "Callable" ) # type: ignore[misc]
202
202
def function_string (self ) -> str :
203
203
args = self .parse_args ()
204
204
args_list = [repr (arg ) for arg in args ]
205
205
kwargs = self .parse_kwargs ()
206
206
kwargs_list = [k + "=" + repr (v ) for (k , v ) in kwargs .items ()]
207
207
return self .callable + f"({ ', ' .join (args_list + kwargs_list )} )"
208
208
209
- def parse_args (self ):
209
+ def parse_args (self ) -> List [ Any ] :
210
210
"""Parse args for running the job"""
211
211
args = self .callable_args .all ()
212
212
return [arg .value () for arg in args ]
213
213
214
- def parse_kwargs (self ):
214
+ def parse_kwargs (self ) -> Dict [ str , Any ] :
215
215
"""Parse kwargs for running the job"""
216
216
kwargs = self .callable_kwargs .all ()
217
217
return dict ([kwarg .value () for kwarg in kwargs ])
218
218
219
- def _next_job_id (self ):
219
+ def _next_job_id (self ) -> str :
220
220
addition = timezone .now ().strftime ("%Y%m%d%H%M%S%f" )
221
221
return f"{ self .queue } :{ self .id } :{ addition } "
222
222
223
- def _enqueue_args (self ) -> Dict :
223
+ def _enqueue_args (self ) -> Dict [ str , Any ] :
224
224
"""Args for Queue.enqueue_call.
225
225
Set all arguments for Queue.enqueue. Particularly:
226
226
- set job timeout and ttl
@@ -282,7 +282,7 @@ def _schedule_time(self) -> datetime:
282
282
self .repeat = (self .repeat - gap ) if self .repeat is not None else None
283
283
return utc (self .scheduled_time ) if django_settings .USE_TZ else self .scheduled_time
284
284
285
- def to_dict (self ) -> Dict :
285
+ def to_dict (self ) -> Dict [ str , Any ] :
286
286
"""Export model to dictionary, so it can be saved as external file backup"""
287
287
interval_unit = str (self .interval_unit ) if self .interval_unit else None
288
288
res = dict (
@@ -321,16 +321,11 @@ def to_dict(self) -> Dict:
321
321
)
322
322
return res
323
323
324
- def get_absolute_url (self ):
324
+ def get_absolute_url (self ) -> str :
325
325
model = self ._meta .model .__name__ .lower ()
326
- return reverse (
327
- f"admin:scheduler_{ model } _change" ,
328
- args = [
329
- self .id ,
330
- ],
331
- )
326
+ return reverse (f"admin:scheduler_{ model } _change" , args = [self .id ])
332
327
333
- def __str__ (self ):
328
+ def __str__ (self ) -> str :
334
329
func = self .function_string ()
335
330
return f"{ self .task_type } [{ self .name } ={ func } ]"
336
331
@@ -359,7 +354,7 @@ def _schedule(self) -> bool:
359
354
self .job_name = job .name
360
355
return True
361
356
362
- def save (self , ** kwargs ) :
357
+ def save (self , ** kwargs : Any ) -> None :
363
358
should_clean = kwargs .pop ("clean" , True )
364
359
if should_clean :
365
360
self .clean ()
@@ -372,25 +367,25 @@ def save(self, **kwargs):
372
367
self ._schedule ()
373
368
super (Task , self ).save ()
374
369
375
- def delete (self , ** kwargs ) :
370
+ def delete (self , ** kwargs : Any ) -> None :
376
371
self .unschedule ()
377
372
super (Task , self ).delete (** kwargs )
378
373
379
- def interval_seconds (self ):
374
+ def interval_seconds (self ) -> float :
380
375
kwargs = {
381
376
self .interval_unit : self .interval ,
382
377
}
383
378
return timedelta (** kwargs ).total_seconds ()
384
379
385
- def clean_callable (self ):
380
+ def clean_callable (self ) -> None :
386
381
try :
387
382
utils .callable_func (self .callable )
388
383
except Exception :
389
384
raise ValidationError (
390
385
{"callable" : ValidationError (_ ("Invalid callable, must be importable" ), code = "invalid" )}
391
386
)
392
387
393
- def clean_queue (self ):
388
+ def clean_queue (self ) -> None :
394
389
queue_names = get_queue_names ()
395
390
if self .queue not in queue_names :
396
391
raise ValidationError (
@@ -401,7 +396,7 @@ def clean_queue(self):
401
396
}
402
397
)
403
398
404
- def clean_interval_unit (self ):
399
+ def clean_interval_unit (self ) -> None :
405
400
config = settings .SCHEDULER_CONFIG
406
401
if config .SCHEDULER_INTERVAL > self .interval_seconds ():
407
402
raise ValidationError (
@@ -424,13 +419,13 @@ def clean_result_ttl(self) -> None:
424
419
params = {"interval" : self .interval_seconds ()},
425
420
)
426
421
427
- def clean_cron_string (self ):
422
+ def clean_cron_string (self ) -> None :
428
423
try :
429
424
croniter .croniter (self .cron_string )
430
425
except ValueError as e :
431
426
raise ValidationError ({"cron_string" : ValidationError (_ (str (e )), code = "invalid" )})
432
427
433
- def clean (self ):
428
+ def clean (self ) -> None :
434
429
if self .task_type not in TaskType .values :
435
430
raise ValidationError (
436
431
{"task_type" : ValidationError (_ ("Invalid task type" ), code = "invalid" )},
@@ -470,7 +465,7 @@ def get_scheduled_task(task_type_str: str, task_id: int) -> Task:
470
465
task = Task .objects .filter (task_type = task_type , id = task_id ).first ()
471
466
if task is None :
472
467
raise ValueError (f"Job { task_type } :{ task_id } does not exit" )
473
- return task
468
+ return task # type: ignore[no-any-return]
474
469
except ValueError :
475
470
raise ValueError (f"Invalid task type { task_type_str } " )
476
471
raise ValueError (f"Job Model { task_type_str } does not exist, choices are { TASK_TYPES } " )
@@ -484,5 +479,5 @@ def run_task(task_model: str, task_id: int) -> Any:
484
479
logger .debug (f"Running task { str (scheduled_task )} " )
485
480
args = scheduled_task .parse_args ()
486
481
kwargs = scheduled_task .parse_kwargs ()
487
- res = scheduled_task .callable_func ()(* args , ** kwargs )
482
+ res = scheduled_task .callable_func ()(* args , ** kwargs ) # type: ignore[no-untyped-call]
488
483
return res
0 commit comments