django-inspect-tasks 0.5.0__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.
File without changes
File without changes
File without changes
@@ -0,0 +1,66 @@
1
+ import argparse
2
+ import logging
3
+ from pprint import pformat
4
+
5
+ from crontask import scheduler
6
+ from django.core.management import BaseCommand, CommandError
7
+
8
+ from django_inspect_tasks import util
9
+ from django_inspect_tasks.util import all_tasks
10
+
11
+
12
+ class Command(BaseCommand):
13
+ def add_arguments(self, parser: argparse.ArgumentParser):
14
+ task = parser.add_argument_group("Task Options")
15
+ task.add_argument("--queue")
16
+ task.add_argument("--backend")
17
+ task.add_argument("--priority")
18
+ task.add_argument("task", nargs="?")
19
+
20
+ def handle_task(self, task: str, **options):
21
+ try:
22
+ task_obj = util.get_task(task)
23
+ result = task_obj.using(
24
+ queue_name=options["queue"],
25
+ priority=options["priority"],
26
+ backend=options["backend"],
27
+ ).enqueue()
28
+ except (ImportError, AttributeError):
29
+ raise CommandError(f"Unknown task: {task}")
30
+ else:
31
+ return pformat(result)
32
+
33
+ def handle(self, task, verbosity, **options):
34
+ ch = logging.StreamHandler()
35
+ formatter = logging.Formatter(logging.BASIC_FORMAT)
36
+ ch.setFormatter(formatter)
37
+ match verbosity:
38
+ case 2:
39
+ logging.root.addHandler(ch)
40
+ logging.root.setLevel(logging.INFO)
41
+ case 3:
42
+ logging.root.addHandler(ch)
43
+ logging.root.setLevel(logging.DEBUG)
44
+
45
+ # If we're passed a task name, we'll send that off to be executed
46
+ if task:
47
+ return self.handle_task(task, **options)
48
+
49
+ # First we need to lookup all the tasks our app can see
50
+ tasks = {t.module_path: t for t in all_tasks()}
51
+
52
+ # Then we check the schedule
53
+ scheduled = {}
54
+ for job in scheduler.get_jobs():
55
+ scheduled[job.func.__self__.module_path] = job.trigger
56
+
57
+ # Then we format the output, showing an extra annotation
58
+ # for scheduled tasks
59
+ padding = max([len(k) for k in tasks])
60
+ for task in sorted(tasks):
61
+ if task in scheduled:
62
+ self.stdout.write(
63
+ task.ljust(padding) + self.style.MIGRATE_HEADING(scheduled[task]),
64
+ )
65
+ else:
66
+ self.stdout.write(task)
@@ -0,0 +1,49 @@
1
+ import importlib
2
+ import logging
3
+ from collections.abc import Iterable
4
+ from types import ModuleType
5
+
6
+ from django.apps import apps
7
+ from django.tasks import Task, task_backends
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def get_task(task: str) -> Task | None:
13
+ try:
14
+ module_name, task_name = task.rsplit(".", 1)
15
+ module = importlib.import_module(module_name)
16
+ return getattr(module, task_name)
17
+ except ModuleNotFoundError as e:
18
+ raise ImportError from e
19
+
20
+
21
+ def task_classes() -> tuple[Task]:
22
+ return tuple({backend.task_class for backend in task_backends.all()})
23
+
24
+
25
+ def task_modules(name="tasks") -> Iterable[ModuleType]:
26
+ for app in apps.get_app_configs():
27
+ try:
28
+ module = importlib.import_module(f"{app.name}.{name}")
29
+ except (ImportError, ModuleNotFoundError):
30
+ logger.debug("No tasks found for %s", app.name)
31
+ else:
32
+ logger.debug("Found %s", module.__name__)
33
+ yield module
34
+
35
+
36
+ def tasks_from_module(mod: ModuleType, TYPES):
37
+ for key in dir(mod):
38
+ obj = getattr(mod, key)
39
+ if isinstance(obj, TYPES):
40
+ yield obj
41
+ if isinstance(obj, ModuleType):
42
+ if mod.__package__ == obj.__package__:
43
+ yield from tasks_from_module(obj, TYPES)
44
+
45
+
46
+ def all_tasks() -> Iterable[Task]:
47
+ TYPES = task_classes()
48
+ for module in task_modules():
49
+ yield from tasks_from_module(module, TYPES)
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-inspect-tasks
3
+ Version: 0.5.0
4
+ Summary: Inspect Tasks in your Django App
5
+ Keywords: django,tasks
6
+ Author: Paul Traylor
7
+ Author-email: Paul Traylor <kungfudiscomonkey@gmail.com>
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Framework :: Django :: 6.0
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Classifier: Programming Language :: Python :: 3.15
15
+ Requires-Dist: django-crontask>=1.0.3
16
+ Requires-Dist: django>=6.0
17
+ Requires-Python: >=3.12
18
+ Project-URL: download, https://pypi.org/project/django-inspect-tasks/
19
+ Project-URL: issues, https://codeberg.org/kfdm/django-inspect-tasks/issues
20
+ Project-URL: source, https://codeberg.org/kfdm/django-inspect-tasks
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Inspect Tasks in your Django App
24
+
25
+ ![PyPI - Version](https://img.shields.io/pypi/v/django-inspect-tasks)
26
+ ![PyPI - License](https://img.shields.io/pypi/l/django-inspect-tasks)
27
+
28
+ # Instalation
29
+
30
+ Install using `pip` or `uv` (or your favorite tool)
31
+
32
+ ```shell
33
+ uv add django-inspect-tasks
34
+ ```
35
+
36
+ Then add to your projects `settings.py` under `INSTALLED_APPS`
37
+
38
+ ```python
39
+ INSTALLED_APPS = [
40
+ "myapp",
41
+ # Third Party
42
+ "crontask",
43
+ "django_inspect_tasks",
44
+ # Default Django
45
+ "django.contrib.admin",
46
+ "django.contrib.auth",
47
+ "django.contrib.contenttypes",
48
+ "django.contrib.sessions",
49
+ "django.contrib.messages",
50
+ "django.contrib.staticfiles",
51
+ ]
52
+ ```
53
+
54
+ Adds a `tasks` subcommand to your app
55
+
56
+ ```shell
57
+ python manage.py tasks
58
+ crontask.tasks.heartbeat cron[month='*', day='*', day_of_week='*', hour='*', minute='*']
59
+ myapp.tasks.example_regular_task
60
+ myapp.tasks.example_scheduled_task interval[0:01:00]
61
+ ```
@@ -0,0 +1,8 @@
1
+ django_inspect_tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ django_inspect_tasks/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ django_inspect_tasks/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ django_inspect_tasks/management/commands/tasks.py,sha256=148CAbf0GZ6W5m1Zf_x0T72phaCkcS80tr0YwLtK3yY,2287
5
+ django_inspect_tasks/util.py,sha256=sfQ6F93z5U_2NPbCufNNYnFvxO3O6X0S21elOqNKSHI,1434
6
+ django_inspect_tasks-0.5.0.dist-info/WHEEL,sha256=KSLUh82mDPEPk0Bx0ScXlWL64bc8KmzIPNcpQZFV-6E,79
7
+ django_inspect_tasks-0.5.0.dist-info/METADATA,sha256=f_aAzmVmjjRREUaphS3kE1wwfWNw2eXwExNEADy_5tk,1780
8
+ django_inspect_tasks-0.5.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.22
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any