Skip to content

Commit c7c3992

Browse files
committed
add types, etc.
1 parent ad064ab commit c7c3992

File tree

6 files changed

+61
-74
lines changed

6 files changed

+61
-74
lines changed

scheduler/admin/ephemeral_models.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@ def has_change_permission(self, request, obj=None):
1313
return True
1414

1515
def has_module_permission(self, request):
16-
"""
17-
return True if the given request has any permission in the given
18-
app label.
19-
20-
Can be overridden by the user in subclasses. In such case it should
21-
return True if the given request has permission to view the module on
22-
the admin index page and access the module's index page. Overriding it
23-
does not restrict access to the add, change or delete views. Use
24-
`ModelAdmin.has_(add|change|delete)_permission` for that.
16+
"""Returns True if the given request has any permission in the given app label.
17+
18+
Can be overridden by the user in subclasses. In such case, it should return True if the given request has
19+
permission to view the module on the admin index page and access the module's index page. Overriding it does
20+
not restrict access to the add, change or delete views. Use `ModelAdmin.has_(add|change|delete)_permission` for
21+
that.
2522
"""
2623
return request.user.has_module_perms("django-tasks-scheduler")
2724

scheduler/admin/task_models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from scheduler import tools
88
from scheduler.models import CronTask, TaskArg, TaskKwarg, RepeatableTask, ScheduledTask
99
from scheduler.settings import SCHEDULER_CONFIG, logger
10-
from scheduler.tools import get_job_executions
10+
from scheduler.tools import get_job_executions_for_task
1111

1212

1313
class HiddenMixin(object):
@@ -185,7 +185,7 @@ def change_view(self, request, object_id, form_url="", extra_context=None):
185185
extra = extra_context or {}
186186
obj = self.get_object(request, object_id)
187187
try:
188-
execution_list = get_job_executions(obj.queue, obj)
188+
execution_list = get_job_executions_for_task(obj.queue, obj)
189189
except (redis.ConnectionError, valkey.ConnectionError) as e:
190190
logger.warn(f"Could not get job executions: {e}")
191191
execution_list = list()

scheduler/rq_classes.py

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Any, Optional, Union
1+
from typing import List, Optional, Union
22

33
import django
44
from django.apps import apps
@@ -37,43 +37,33 @@ def register_sentry(sentry_dsn, **opts):
3737
rq_register_sentry(sentry_dsn, **opts)
3838

3939

40-
def as_text(v: Union[bytes, str]) -> Optional[str]:
40+
def as_str(v: Union[bytes, str]) -> Optional[str]:
4141
"""Converts a bytes value to a string using `utf-8`.
4242
43-
:param v: The value (bytes or string)
43+
:param v: The value (None/bytes/str)
4444
:raises: ValueError: If the value is not bytes or string
4545
:returns: Either the decoded string or None
4646
"""
4747
if v is None:
4848
return None
49-
elif isinstance(v, bytes):
49+
if isinstance(v, bytes):
5050
return v.decode("utf-8")
51-
elif isinstance(v, str):
51+
if isinstance(v, str):
5252
return v
53-
else:
54-
raise ValueError("Unknown type %r" % type(v))
55-
56-
57-
def compact(lst: List[Any]) -> List[Any]:
58-
"""Remove `None` values from an iterable object.
59-
:param lst: A list (or list-like) object
60-
:returns: The list without None values
61-
"""
62-
return [item for item in lst if item is not None]
53+
raise ValueError("Unknown type %r" % type(v))
6354

6455

6556
class JobExecution(Job):
66-
def __eq__(self, other):
57+
def __eq__(self, other) -> bool:
6758
return isinstance(other, Job) and self.id == other.id
6859

6960
@property
70-
def is_scheduled_task(self):
61+
def is_scheduled_task(self) -> bool:
7162
return self.meta.get("scheduled_task_id", None) is not None
7263

73-
def is_execution_of(self, scheduled_job):
64+
def is_execution_of(self, task: "ScheduledTask") -> bool:
7465
return (
75-
self.meta.get("task_type", None) == scheduled_job.TASK_TYPE
76-
and self.meta.get("scheduled_task_id", None) == scheduled_job.id
66+
self.meta.get("task_type", None) == task.TASK_TYPE and self.meta.get("scheduled_task_id", None) == task.id
7767
)
7868

7969
def stop_execution(self, connection: ConnectionType):
@@ -138,7 +128,7 @@ def _start_scheduler(
138128
proc = self.scheduler.start()
139129
self._set_property("scheduler_pid", proc.pid)
140130

141-
def execute_job(self, job: "Job", queue: "Queue"):
131+
def execute_job(self, job: "Job", queue: "Queue") -> None:
142132
if self.fork_job_execution:
143133
super(DjangoWorker, self).execute_job(job, queue)
144134
else:
@@ -150,16 +140,17 @@ def work(self, **kwargs) -> bool:
150140
kwargs.setdefault("with_scheduler", True)
151141
return super(DjangoWorker, self).work(**kwargs)
152142

153-
def _set_property(self, prop_name: str, val, pipeline: Optional[PipelineType] = None):
143+
def _set_property(self, prop_name: str, val, pipeline: Optional[PipelineType] = None) -> None:
154144
connection = pipeline if pipeline is not None else self.connection
155145
if val is None:
156146
connection.hdel(self.key, prop_name)
157147
else:
158148
connection.hset(self.key, prop_name, val)
159149

160-
def _get_property(self, prop_name: str, pipeline: Optional[PipelineType] = None):
150+
def _get_property(self, prop_name: str, pipeline: Optional[PipelineType] = None) -> Optional[str]:
161151
connection = pipeline if pipeline is not None else self.connection
162-
return as_text(connection.hget(self.key, prop_name))
152+
res = connection.hget(self.key, prop_name)
153+
return as_str(res)
163154

164155
def scheduler_pid(self) -> Optional[int]:
165156
if len(self.queues) == 0:
@@ -170,6 +161,9 @@ def scheduler_pid(self) -> Optional[int]:
170161

171162

172163
class DjangoQueue(Queue):
164+
"""A subclass of RQ's QUEUE that allows jobs to be stored temporarily to be enqueued later at the end of Django's
165+
request/response cycle."""
166+
173167
REGISTRIES = dict(
174168
finished="finished_job_registry",
175169
failed="failed_job_registry",
@@ -178,12 +172,8 @@ class DjangoQueue(Queue):
178172
deferred="deferred_job_registry",
179173
canceled="canceled_job_registry",
180174
)
181-
"""
182-
A subclass of RQ's QUEUE that allows jobs to be stored temporarily to be
183-
enqueued later at the end of Django's request/response cycle.
184-
"""
185175

186-
def __init__(self, *args, **kwargs):
176+
def __init__(self, *args, **kwargs) -> None:
187177
kwargs["job_class"] = JobExecution
188178
super(DjangoQueue, self).__init__(*args, **kwargs)
189179

@@ -196,43 +186,43 @@ def get_registry(self, name: str) -> Union[None, BaseRegistry, "DjangoQueue"]:
196186
return None
197187

198188
@property
199-
def finished_job_registry(self):
189+
def finished_job_registry(self) -> FinishedJobRegistry:
200190
return FinishedJobRegistry(self.name, self.connection)
201191

202192
@property
203-
def started_job_registry(self):
193+
def started_job_registry(self) -> StartedJobRegistry:
204194
return StartedJobRegistry(
205195
self.name,
206196
self.connection,
207197
job_class=JobExecution,
208198
)
209199

210200
@property
211-
def deferred_job_registry(self):
201+
def deferred_job_registry(self) -> DeferredJobRegistry:
212202
return DeferredJobRegistry(
213203
self.name,
214204
self.connection,
215205
job_class=JobExecution,
216206
)
217207

218208
@property
219-
def failed_job_registry(self):
209+
def failed_job_registry(self) -> FailedJobRegistry:
220210
return FailedJobRegistry(
221211
self.name,
222212
self.connection,
223213
job_class=JobExecution,
224214
)
225215

226216
@property
227-
def scheduled_job_registry(self):
217+
def scheduled_job_registry(self) -> ScheduledJobRegistry:
228218
return ScheduledJobRegistry(
229219
self.name,
230220
self.connection,
231221
job_class=JobExecution,
232222
)
233223

234224
@property
235-
def canceled_job_registry(self):
225+
def canceled_job_registry(self) -> CanceledJobRegistry:
236226
return CanceledJobRegistry(
237227
self.name,
238228
self.connection,
@@ -250,24 +240,24 @@ def get_all_job_ids(self) -> List[str]:
250240
res.extend(self.canceled_job_registry.get_job_ids())
251241
return res
252242

253-
def get_all_jobs(self):
243+
def get_all_jobs(self) -> List[JobExecution]:
254244
job_ids = self.get_all_job_ids()
255-
return compact([self.fetch_job(job_id) for job_id in job_ids])
245+
return list(filter(lambda j: j is not None, [self.fetch_job(job_id) for job_id in job_ids]))
256246

257-
def clean_registries(self):
247+
def clean_registries(self) -> None:
258248
self.started_job_registry.cleanup()
259249
self.failed_job_registry.cleanup()
260250
self.finished_job_registry.cleanup()
261251

262-
def remove_job_id(self, job_id: str):
252+
def remove_job_id(self, job_id: str) -> None:
263253
self.connection.lrem(self.key, 0, job_id)
264254

265-
def last_job_id(self):
255+
def last_job_id(self) -> Optional[str]:
266256
return self.connection.lindex(self.key, 0)
267257

268258

269259
class DjangoScheduler(RQScheduler):
270-
def __init__(self, *args, **kwargs):
260+
def __init__(self, *args, **kwargs) -> None:
271261
kwargs.setdefault("interval", settings.SCHEDULER_CONFIG.SCHEDULER_INTERVAL)
272262
super(DjangoScheduler, self).__init__(*args, **kwargs)
273263

@@ -281,10 +271,10 @@ def reschedule_all_jobs():
281271
logger.debug(f"Rescheduling {str(item)}")
282272
item.save()
283273

284-
def work(self):
274+
def work(self) -> None:
285275
django.setup()
286276
super(DjangoScheduler, self).work()
287277

288-
def enqueue_scheduled_jobs(self):
278+
def enqueue_scheduled_jobs(self) -> None:
289279
self.reschedule_all_jobs()
290280
super(DjangoScheduler, self).enqueue_scheduled_jobs()

scheduler/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def conf_settings():
5454

5555
user_settings = getattr(settings, "SCHEDULER_CONFIG", {})
5656
if "FAKEREDIS" in user_settings:
57+
logger.warning("Configuration using FAKEREDIS is deprecated. Use BROKER='fakeredis' instead")
5758
user_settings["BROKER"] = Broker.FAKEREDIS if user_settings["FAKEREDIS"] else Broker.REDIS
5859
user_settings.pop("FAKEREDIS")
5960
for k in user_settings:

scheduler/tools.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import importlib
22
import os
3+
from typing import List, Any, Callable
34

45
import croniter
56
from django.apps import apps
67
from django.utils import timezone
78
from django.utils.module_loading import import_string
89

910
from scheduler.queues import get_queues, logger, get_queue
10-
from scheduler.rq_classes import DjangoWorker, MODEL_NAMES
11+
from scheduler.rq_classes import DjangoWorker, MODEL_NAMES, JobExecution
1112
from scheduler.settings import SCHEDULER_CONFIG, Broker
1213

1314

14-
def callable_func(callable_str: str):
15+
def callable_func(callable_str: str) -> Callable:
1516
path = callable_str.split(".")
1617
module = importlib.import_module(".".join(path[:-1]))
1718
func = getattr(module, path[-1])
@@ -28,7 +29,7 @@ def get_next_cron_time(cron_string) -> timezone.datetime:
2829
return next_itr
2930

3031

31-
def get_scheduled_task(task_model: str, task_id: int):
32+
def get_scheduled_task(task_model: str, task_id: int) -> "BaseTask":
3233
if task_model not in MODEL_NAMES:
3334
raise ValueError(f"Job Model {task_model} does not exist, choices are {MODEL_NAMES}")
3435
model = apps.get_model(app_label="scheduler", model_name=task_model)
@@ -38,7 +39,7 @@ def get_scheduled_task(task_model: str, task_id: int):
3839
return task
3940

4041

41-
def run_task(task_model: str, task_id: int):
42+
def run_task(task_model: str, task_id: int) -> Any:
4243
"""Run a scheduled job"""
4344
scheduled_task = get_scheduled_task(task_model, task_id)
4445
logger.debug(f"Running task {str(scheduled_task)}")
@@ -48,7 +49,7 @@ def run_task(task_model: str, task_id: int):
4849
return res
4950

5051

51-
def _calc_worker_name(existing_worker_names):
52+
def _calc_worker_name(existing_worker_names) -> str:
5253
hostname = os.uname()[1]
5354
c = 1
5455
worker_name = f"{hostname}-worker.{c}"
@@ -58,10 +59,8 @@ def _calc_worker_name(existing_worker_names):
5859
return worker_name
5960

6061

61-
def create_worker(*queue_names, **kwargs):
62-
"""
63-
Returns a Django worker for all queues or specified ones.
64-
"""
62+
def create_worker(*queue_names, **kwargs) -> DjangoWorker:
63+
"""Returns a Django worker for all queues or specified ones."""
6564

6665
queues = get_queues(*queue_names)
6766
existing_workers = DjangoWorker.all(connection=queues[0].connection)
@@ -84,7 +83,7 @@ def create_worker(*queue_names, **kwargs):
8483
return worker
8584

8685

87-
def get_job_executions(queue_name, scheduled_task):
86+
def get_job_executions_for_task(queue_name, scheduled_task) -> List[JobExecution]:
8887
queue = get_queue(queue_name)
8988
job_list = queue.get_all_jobs()
9089
res = list(filter(lambda j: j.is_execution_of(scheduled_task), job_list))

0 commit comments

Comments
 (0)