├── .coveragerc
├── .editorconfig
├── .github
└── workflows
│ ├── release.yml
│ └── tests.yml
├── .gitignore
├── LICENSE.txt
├── README.md
├── README_IMAGES
├── django-celerybeat-status-admin.png
└── django-celerybeat-status-tasks.png
├── celerybeat_status
├── __init__.py
├── admin.py
├── apps.py
├── helpers.py
├── templates
│ └── celerybeat_status
│ │ ├── custom_admin
│ │ ├── index.html
│ │ ├── sidebar.html
│ │ └── sidebar_widgets
│ │ │ ├── actions.html
│ │ │ └── statuscheck.html
│ │ └── periodic_tasks_status_list.html
├── tests
│ ├── __init__.py
│ ├── test_views.py
│ └── utils.py
├── urls.py
└── views.py
├── manage.py
├── requirements_test.txt
├── runtests.py
├── setup.cfg
├── setup.py
├── tests
├── __init__.py
├── settings.py
└── urls.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | branch = true
3 |
4 | [report]
5 | omit =
6 | *site-packages*
7 | *tests*
8 | *migrations*
9 | *.tox
10 | celerybeat_status/urls.py
11 | celerybeat_status/admin.py
12 | celerybeat_status/apps.py
13 | show_missing = True
14 | exclude_lines =
15 | raise NotImplementedError
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 4
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 | end_of_line = lf
12 |
13 | [*.{json,html,md,yml,yaml}]
14 | indent_size = 2
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
19 | [*.ini]
20 | indent_style = tab
21 |
22 | [Makefile]
23 | indent_style = tab
24 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release - Publish to PyPI
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | release:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Checkout code
13 | uses: actions/checkout@v4
14 | - name: Set up Python
15 | uses: actions/setup-python@v5
16 | with:
17 | python-version: "3.x"
18 | - name: Install dependencies
19 | run: |
20 | python -m pip install --upgrade pip
21 | pip install build twine
22 | - name: Build package
23 | run: |
24 | python -m build
25 | twine check dist/*
26 | - name: Publish package
27 | run: twine upload dist/*
28 | env:
29 | TWINE_USERNAME: __token__
30 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
31 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | name: Test (Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }})
8 |
9 | runs-on: ubuntu-latest
10 |
11 | strategy:
12 | matrix:
13 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
14 | django-version: ["4.2", "5.0"]
15 |
16 | steps:
17 | - name: Checkout code
18 | uses: actions/checkout@v4
19 | - name: Set up Python ${{ matrix.python-version }}
20 | uses: actions/setup-python@v5
21 | with:
22 | python-version: ${{ matrix.python-version }}
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install -r requirements_test.txt
27 | - name: Run tests with coverage
28 | run: tox -- --keepdb --parallel
29 | env:
30 | COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.db
3 | *~
4 |
5 |
6 | /site/
7 | /htmlcov/
8 | /coverage/
9 | /build/
10 | /dist/
11 | /*.egg-info/
12 | /env/
13 | MANIFEST
14 | coverage.*
15 | .coverage
16 | .tox
17 | .vscode/
18 | .python-version
19 | celerybeat-schedule
20 | celerybeat-schedule.*
21 | *.sqlite
22 | *.sqlite3
23 |
24 | !.gitignore
25 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Vinta Serviços e Soluções Tecnológicas Ltda
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Django Celery Beat Status
2 |
3 | 
4 | 
5 | 
6 | [](https://github.com/vintasoftware/django-celerybeat-status/actions/workflows/tests.yml)
7 | [](https://coveralls.io/github/vintasoftware/django-celerybeat-status?branch=main)
8 |
9 | A library that integrates with django admin and shows in a simple GUI when your periodic are going to run next.
10 |
11 | ## Instalation
12 |
13 | ```bash
14 | pip install django-celerybeat-status
15 | ```
16 |
17 | ## Configuration
18 |
19 | 1. Add `"celerybeat_status"` to your `INSTALLED_APPS` variable in django settings
20 |
21 | ```python
22 | INSTALLED_APPS = [
23 | ...
24 | "celerybeat_status",
25 | ]
26 | ```
27 |
28 | 2. Create a url for the status check view
29 |
30 | ```python
31 | from django.urls import include, path
32 |
33 | urlpatterns = [
34 | # other urls...
35 | path("admin/statuscheck/", include("celerybeat_status.urls")), # celerybeat_status admin
36 | path("admin/", admin.site.urls), # django admin
37 | ]
38 | ```
39 |
40 | ## Usage
41 |
42 | Check your tasks under `/admin/statuscheck/periodic-tasks/` (if you configured your urls the way we suggested in this docs).
43 |
44 | You can also find a link in `/admin` sidebar.
45 |
46 | How you admin page will look like:
47 |
48 | 
49 |
50 | How your tasks will be shown:
51 |
52 | 
53 |
54 | ## Contributing
55 |
56 | ### Setting up the development environment
57 |
58 | 1. Clone the repository.
59 |
60 | 2. Create a virtual environment.
61 |
62 | 3. Install the dependencies.
63 |
64 | ```bash
65 | pip install -r requirements_test.txt
66 | ```
67 |
68 | 4. Run the project. Relevant to check UI changes.
69 |
70 | ```bash
71 | # Create the database and run the migrations.
72 | python manage.py migrate
73 | # Create a superuser. This will allow you to access the admin interface.
74 | python manage.py createsuperuser
75 | # Start the development server. You can view the application by navigating to the URL provided in the terminal.
76 | python manage.py runserver
77 | ```
78 |
79 | 5. Run the tests. This package uses `tox` to run tests on multiple evironments, please make sure they are passing before submitting a pull request.
80 |
81 | ```bash
82 | tox
83 | ```
84 |
85 | ## Commercial Support
86 |
87 | This project, as other Vinta open-source projects, is used in products of Vinta clients. We are always looking for exciting work, so if you need any commercial support, feel free to get in touch: contact@vinta.com.br
88 |
89 | Copyright (c) 2017 Vinta Serviços e Soluções Tecnológicas Ltda
90 |
--------------------------------------------------------------------------------
/README_IMAGES/django-celerybeat-status-admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vintasoftware/django-celerybeat-status/c75c219ea85656030c266d665a36c4e1ff2251b3/README_IMAGES/django-celerybeat-status-admin.png
--------------------------------------------------------------------------------
/README_IMAGES/django-celerybeat-status-tasks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vintasoftware/django-celerybeat-status/c75c219ea85656030c266d665a36c4e1ff2251b3/README_IMAGES/django-celerybeat-status-tasks.png
--------------------------------------------------------------------------------
/celerybeat_status/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8
2 | __title__ = "CeleryBeat Status"
3 | __version__ = "1.0.1"
4 | __author__ = "Vinta Software"
5 | __license__ = "MIT License"
6 | __copyright__ = "Copyright 2017 Vinta Serviços e Soluções Tecnológicas Ltda"
7 |
8 | # Version synonym
9 | VERSION = __version__
10 |
--------------------------------------------------------------------------------
/celerybeat_status/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib.admin.sites import AdminSite
2 |
3 | AdminSite.index_template = "celerybeat_status/custom_admin/index.html"
4 |
--------------------------------------------------------------------------------
/celerybeat_status/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CeleryBeatStatusConfig(AppConfig):
5 | name = "celerybeat_status"
6 |
--------------------------------------------------------------------------------
/celerybeat_status/helpers.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import json
3 |
4 | from celery.beat import Service
5 | from django.utils import timezone
6 |
7 |
8 | def get_periodic_tasks_info():
9 | from celery import current_app
10 |
11 | schedule = Service(current_app).get_scheduler().get_schedule()
12 | tasks = []
13 | for key, entry in schedule.items():
14 | # entry.is_due() returns (is_due, time_in_seconds_for_next_execution)
15 | is_due_tpl = entry.is_due()
16 |
17 | next_execution = timezone.now() + datetime.timedelta(seconds=is_due_tpl[1])
18 |
19 | # remove delay between the timezone.now and the schedule entry due date
20 | next_execution = next_execution.replace(microsecond=0)
21 |
22 | tasks.append(
23 | {
24 | "name": key,
25 | "task": entry.task,
26 | "args": "(" + ", ".join([json.dumps(arg) for arg in entry.args]) + ")",
27 | "kwargs": json.dumps(entry.kwargs),
28 | "is_due": is_due_tpl[0],
29 | "next_execution": next_execution,
30 | }
31 | )
32 |
33 | return tasks
34 |
--------------------------------------------------------------------------------
/celerybeat_status/templates/celerybeat_status/custom_admin/index.html:
--------------------------------------------------------------------------------
1 | {% extends "admin/index.html" %}
2 | {% load i18n static %}
3 |
4 | {% block sidebar %}
5 | {% include "celerybeat_status/custom_admin/sidebar.html" %}
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/celerybeat_status/templates/celerybeat_status/custom_admin/sidebar.html:
--------------------------------------------------------------------------------
1 |
2 | {% include "celerybeat_status/custom_admin/sidebar_widgets/statuscheck.html" %}
3 | {% include "celerybeat_status/custom_admin/sidebar_widgets/actions.html" %}
4 |
5 |
--------------------------------------------------------------------------------
/celerybeat_status/templates/celerybeat_status/custom_admin/sidebar_widgets/actions.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
3 |
4 |
{% trans 'Recent actions' %}
5 |
{% trans 'My actions' %}
6 | {% load log %}
7 | {% get_admin_log 10 as admin_log for_user user %}
8 | {% if not admin_log %}
9 |
{% trans 'None available' %}
10 | {% else %}
11 |
12 | {% for entry in admin_log %}
13 | -
14 | {% if entry.is_deletion or not entry.get_admin_url %}
15 | {{entry.object_repr}}
16 | {% else %}
17 | {{entry.object_repr}}
18 | {% endif %}
19 |
20 | {% if entry.content_type %}
21 | {% filter capfirst %}{{ entry.content_type }}{% endfilter %}
22 | {% else %}
23 | {% trans 'Unknown content' %}
24 | {% endif %}
25 |
26 | {% endfor %}
27 |
28 | {% endif %}
29 |
30 |
--------------------------------------------------------------------------------
/celerybeat_status/templates/celerybeat_status/custom_admin/sidebar_widgets/statuscheck.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
3 |
4 |
{% trans 'Status check links' %}
5 |
8 |
9 |
--------------------------------------------------------------------------------
/celerybeat_status/templates/celerybeat_status/periodic_tasks_status_list.html:
--------------------------------------------------------------------------------
1 | {% extends "admin/index.html" %}
2 | {% load i18n static %}
3 |
4 | {% block extrastyle %}{{ block.super }}{% endblock %}
5 |
6 | {% block coltype %}colMS{% endblock %}
7 |
8 | {% block bodyclass %}{{ block.super }} dashboard{% endblock %}
9 |
10 | {% block breadcrumbs %}
11 |
15 | {% endblock %}
16 |
17 | {% block content %}
18 |
19 |
20 |
21 | {% for task in tasks %}
22 | -
23 | {{task.name}}
24 |
25 | - {% trans 'Is due?' %} {% if task.is_due %} {% trans 'Yes' %} {% else %} {% trans 'No' %} {% endif %}
26 | - {% trans 'Next execution:' %} {{ task.next_execution | date:"m/d/Y fa e" }}
27 | - {% trans 'Task:' %} {{ task.task }}
28 | - {% trans 'Arguments:' %} {{ task.args }}
29 | - {% trans 'Keyword Arguments:' %} {{ task.kwargs }}
30 |
31 |
32 | {% endfor %}
33 |
34 |
35 |
36 |
37 | {% endblock %}
38 |
39 |
40 | {% block sidebar %}{% endblock %}
41 |
--------------------------------------------------------------------------------
/celerybeat_status/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vintasoftware/django-celerybeat-status/c75c219ea85656030c266d665a36c4e1ff2251b3/celerybeat_status/tests/__init__.py
--------------------------------------------------------------------------------
/celerybeat_status/tests/test_views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.urls import reverse
3 |
4 | from celerybeat_status.tests.utils import BaseTestCase, TestRequiresAuthenticatedUser
5 |
6 | User = get_user_model()
7 |
8 |
9 | class PeriodicTasksStatusListViewTests(TestRequiresAuthenticatedUser, BaseTestCase):
10 | view_name = "celerybeat_status:periodic-tasks-status"
11 |
12 | def setUp(self):
13 | super().setUp()
14 | self.view_url = reverse(self.view_name)
15 |
16 | def test_non_authenticated_user_is_redirected(self):
17 | response = self.client.get(self.view_url)
18 | self.assertRedirects(response, "/admin/login/?next=" + self.view_url)
19 |
20 | def test_regular_user_access_returns_forbidden(self):
21 | self.client.force_login(self.regular_user)
22 | response = self.client.get(self.view_url)
23 | self.assertEqual(response.status_code, 403)
24 |
25 | def test_staff_user_access_returns_forbidden(self):
26 | self.client.force_login(self.staff_user)
27 | response = self.client.get(self.view_url)
28 | self.assertEqual(response.status_code, 403)
29 |
30 | def test_superuser_access_returns_success(self):
31 | self.client.force_login(self.superuser)
32 | response = self.client.get(self.view_url)
33 | self.assertEqual(response.status_code, 200)
34 |
--------------------------------------------------------------------------------
/celerybeat_status/tests/utils.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import get_user_model
2 | from django.test import Client, TestCase
3 |
4 | User = get_user_model()
5 |
6 |
7 | class BaseTestCase(TestCase):
8 |
9 | def setUp(self):
10 | super().setUp()
11 | self.regular_user = User.objects.create_user(
12 | username="regular",
13 | email="regular@email.com",
14 | password="123",
15 | is_staff=False,
16 | is_superuser=False,
17 | )
18 | self.staff_user = User.objects.create_user(
19 | username="staff",
20 | email="staff@email.com",
21 | password="123",
22 | is_staff=True,
23 | is_superuser=False,
24 | )
25 | self.superuser = User.objects.create_user(
26 | username="super",
27 | email="superuser@gmail.com",
28 | password="123",
29 | is_staff=True,
30 | is_superuser=True,
31 | )
32 |
33 |
34 | class TestRequiresAuthenticatedUser(object):
35 |
36 | def test_requires_authenticated_user(self):
37 | response = self.client.get(self.view_url)
38 | self.assertEqual(response.status_code, 302)
39 |
--------------------------------------------------------------------------------
/celerybeat_status/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from celerybeat_status.views import PeriodicTasksStatusListView
4 |
5 | app_name = "celerybeat_status"
6 |
7 | urlpatterns = [
8 | path(
9 | "periodic-tasks/",
10 | PeriodicTasksStatusListView.as_view(),
11 | name="periodic-tasks-status",
12 | ),
13 | ]
14 |
--------------------------------------------------------------------------------
/celerybeat_status/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.mixins import UserPassesTestMixin
2 | from django.utils.translation import gettext_lazy
3 | from django.views.generic.base import TemplateView
4 |
5 | from celerybeat_status.helpers import get_periodic_tasks_info
6 |
7 |
8 | class PeriodicTasksStatusListView(UserPassesTestMixin, TemplateView):
9 | template_name = "celerybeat_status/periodic_tasks_status_list.html"
10 | site_url = "/"
11 | login_url = "admin:login"
12 |
13 | def test_func(self):
14 | return self.request.user.is_staff and self.request.user.is_superuser
15 |
16 | def get_context_data(self, **kwargs):
17 | context = super().get_context_data(**kwargs)
18 | context["title"] = gettext_lazy("Periodic tasks status")
19 | context["user"] = self.request.user
20 | context["site_url"] = self.site_url
21 | context["has_permission"] = self.request.user.is_superuser
22 | context["tasks"] = get_periodic_tasks_info()
23 |
24 | return context
25 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == "__main__":
22 | main()
23 |
--------------------------------------------------------------------------------
/requirements_test.txt:
--------------------------------------------------------------------------------
1 | celery==5.4.0
2 | coverage==7.5.1
3 | mock>=5.1.0
4 | flake8>=7.0.0
5 | tox>=4.15.0
6 | tox-gh>=1.3.1
7 | django-model-utils>=4.5.1
8 | djangorestframework
9 | model_mommy
10 |
--------------------------------------------------------------------------------
/runtests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8
3 | from __future__ import absolute_import, unicode_literals
4 |
5 | import os
6 | import sys
7 |
8 | import django
9 | from django.conf import settings
10 | from django.test.utils import get_runner
11 |
12 |
13 | def run_tests(*args, **kwargs):
14 | os.environ["DJANGO_SETTINGS_MODULE"] = "tests.settings"
15 | django.setup()
16 | TestRunner = get_runner(settings)
17 | test_runner = TestRunner(**kwargs)
18 | failures = test_runner.run_tests(args)
19 | try:
20 | os.remove("./celerybeat-schedule.bak")
21 | except Exception:
22 | pass
23 |
24 | try:
25 | os.remove("./celerybeat-schedule.dat")
26 | except Exception:
27 | pass
28 |
29 | try:
30 | os.remove("./celerybeat-schedule.dir")
31 | except Exception:
32 | pass
33 |
34 | sys.exit(bool(failures))
35 |
36 |
37 | def process_kwargs(kwarg):
38 | if len(kwarg.split("=")) == 2:
39 | return (kwarg.split("=")[0], kwarg.split("=")[1])
40 |
41 | else:
42 | return (kwarg, True)
43 |
44 |
45 | if __name__ == "__main__":
46 |
47 | args = [a for a in sys.argv[1:] if not a.startswith("--")]
48 | kwargs = dict(process_kwargs(a[2:]) for a in sys.argv[1:] if a.startswith("--"))
49 |
50 | run_tests(*args, **kwargs)
51 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [wheel]
2 | universal = 1
3 |
4 | [flake8]
5 | ignore = E501
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import os
4 | import re
5 | import shutil
6 | import sys
7 | from io import open
8 |
9 | from setuptools import setup
10 |
11 | long_description = ""
12 | try:
13 | with open("README.md") as f:
14 | long_description = f.read()
15 | except FileNotFoundError:
16 | print("warning: README.md not found, could not set long_description")
17 |
18 |
19 | def get_version(package):
20 | """
21 | Return package version as listed in `__version__` in `init.py`.
22 | """
23 | init_py = open(os.path.join(package, "__init__.py")).read()
24 | return re.search("__version__ = ['\"]([^'\"]+)['\"]", init_py).group(1)
25 |
26 |
27 | def get_packages(package):
28 | """
29 | Return root package and all sub-packages.
30 | """
31 | return [
32 | dirpath
33 | for dirpath, dirnames, filenames in os.walk(package)
34 | if os.path.exists(os.path.join(dirpath, "__init__.py"))
35 | ]
36 |
37 |
38 | def get_package_data(package):
39 | """
40 | Return all files under the root package, that are not in a
41 | package themselves.
42 | """
43 | walk = [
44 | (dirpath.replace(package + os.sep, "", 1), filenames)
45 | for dirpath, dirnames, filenames in os.walk(package)
46 | if not os.path.exists(os.path.join(dirpath, "__init__.py"))
47 | ]
48 |
49 | filepaths = []
50 | for base, filenames in walk:
51 | filepaths.extend([os.path.join(base, filename) for filename in filenames])
52 | return {package: filepaths}
53 |
54 |
55 | version = get_version("celerybeat_status")
56 |
57 |
58 | if sys.argv[-1] == "publish":
59 | if os.system("pip freeze | grep twine"):
60 | print("twine not installed.\nUse `pip install twine`.\nExiting.")
61 | sys.exit()
62 | os.system("python setup.py sdist bdist_wheel")
63 | os.system("twine upload dist/*")
64 | print("You probably want to also tag the version now:")
65 | print(" git tag -a %s -m 'version %s'" % (version, version))
66 | print(" git push --tags")
67 | shutil.rmtree("dist")
68 | shutil.rmtree("build")
69 | shutil.rmtree("django_celerybeat_status.egg-info")
70 | sys.exit()
71 |
72 |
73 | setup(
74 | name="django-celerybeat-status",
75 | version=version,
76 | license="MIT",
77 | description="A simple django admin extension that shows when your periodic are going to run next",
78 | long_description=long_description,
79 | long_description_content_type="text/markdown",
80 | author="Vinta Software",
81 | author_email="contact@vinta.com.br",
82 | packages=get_packages("celerybeat_status"),
83 | package_data=get_package_data("celerybeat_status"),
84 | install_requires=[],
85 | zip_safe=False,
86 | classifiers=[
87 | "Development Status :: 5 - Production/Stable",
88 | "Intended Audience :: Developers",
89 | "Framework :: Django",
90 | "Framework :: Django :: 4.2",
91 | "Framework :: Django :: 5.0",
92 | "Programming Language :: Python :: 3.8",
93 | "Programming Language :: Python :: 3.9",
94 | "Programming Language :: Python :: 3.10",
95 | "Programming Language :: Python :: 3.11",
96 | "Programming Language :: Python :: 3.12",
97 | ],
98 | )
99 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vintasoftware/django-celerybeat-status/c75c219ea85656030c266d665a36c4e1ff2251b3/tests/__init__.py
--------------------------------------------------------------------------------
/tests/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for tests project.
3 |
4 | Generated by 'django-admin startproject' using Django 5.0.6.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/5.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/5.0/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 |
15 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
16 | BASE_DIR = Path(__file__).resolve().parent.parent
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = "django-insecure-2#mnq%u++zzqhlftquaky2y=)ida=5759jg=ck&n7@ez+sqs#1"
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ["*"]
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | "django.contrib.admin",
35 | "django.contrib.auth",
36 | "django.contrib.contenttypes",
37 | "django.contrib.sessions",
38 | "django.contrib.messages",
39 | "django.contrib.staticfiles",
40 | "celerybeat_status",
41 | ]
42 |
43 | MIDDLEWARE = [
44 | "django.middleware.security.SecurityMiddleware",
45 | "django.contrib.sessions.middleware.SessionMiddleware",
46 | "django.middleware.common.CommonMiddleware",
47 | "django.middleware.csrf.CsrfViewMiddleware",
48 | "django.contrib.auth.middleware.AuthenticationMiddleware",
49 | "django.contrib.messages.middleware.MessageMiddleware",
50 | "django.middleware.clickjacking.XFrameOptionsMiddleware",
51 | ]
52 |
53 | ROOT_URLCONF = "tests.urls"
54 |
55 | TEMPLATES = [
56 | {
57 | "BACKEND": "django.template.backends.django.DjangoTemplates",
58 | # "DIRS": [os.path.join(BASE_DIR, "templates")],
59 | "DIRS": [],
60 | "APP_DIRS": True,
61 | "OPTIONS": {
62 | "context_processors": [
63 | "django.template.context_processors.debug",
64 | "django.template.context_processors.request",
65 | "django.contrib.auth.context_processors.auth",
66 | "django.contrib.messages.context_processors.messages",
67 | ],
68 | },
69 | },
70 | ]
71 |
72 |
73 | # Database
74 | # https://docs.djangoproject.com/en/5.0/ref/settings/#databases
75 |
76 | DATABASES = {
77 | "default": {
78 | "ENGINE": "django.db.backends.sqlite3",
79 | "NAME": BASE_DIR / "db.sqlite3",
80 | }
81 | }
82 |
83 |
84 | # Internationalization
85 | # https://docs.djangoproject.com/en/5.0/topics/i18n/
86 |
87 | LANGUAGE_CODE = "en-us"
88 |
89 | TIME_ZONE = "UTC"
90 |
91 | USE_I18N = True
92 |
93 | USE_TZ = True
94 |
95 |
96 | # Static files (CSS, JavaScript, Images)
97 | # https://docs.djangoproject.com/en/5.0/howto/static-files/
98 |
99 | STATIC_URL = "static/"
100 |
--------------------------------------------------------------------------------
/tests/urls.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.urls import include, path
3 |
4 | urlpatterns = [
5 | # The new admin catch-all view will break URL patterns routed after the admin URLs and matching
6 | # the admin URL prefix. Source: https://docs.djangoproject.com/en/5.0/releases/3.2/#id1
7 | path("admin/statuscheck/", include("celerybeat_status.urls")),
8 | path("admin/", admin.site.urls),
9 | ]
10 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | requires =
3 | tox>=4
4 | envlist =
5 | # Django official Python support
6 | # Source: https://docs.djangoproject.com/en/5.0/faq/install/#what-python-version-can-i-use-with-django
7 | {py38,py39,py310,py311,py312}-django42
8 | {py310,py311,py312}-django50
9 | coverage
10 |
11 | [gh]
12 | python =
13 | 3.12 = py312-django42, py312-django50, coverage
14 | 3.11 = py311-django42, py311-django50
15 | 3.10 = py310-django42, py310-django50
16 | 3.9 = py39-django42
17 | 3.8 = py38-django42
18 |
19 | [testenv]
20 | description = run tests
21 | setenv =
22 | PYTHONPATH = {toxinidir}:{toxinidir}/celerybeat_status:{toxinidir}
23 | commands = coverage run --source celerybeat_status runtests.py {posargs}
24 | deps =
25 | django42: Django>=4.2,<5
26 | django50: Django>=5.0,<5.1
27 | -r{toxinidir}/requirements_test.txt
28 | basepython =
29 | py312: python3.12
30 | py311: python3.11
31 | py310: python3.10
32 | py39: python3.9
33 | py38: python3.8
34 |
35 | [testenv:coverage]
36 | description = run coveralls
37 | passenv = COVERALLS_REPO_TOKEN
38 | allowlist_externals = coverage
39 | basepython = python3.12
40 | deps =
41 | {[testenv]deps}
42 | coveralls
43 | commands =
44 | coverage run --source celerybeat_status runtests.py {posargs}
45 | coveralls
46 |
--------------------------------------------------------------------------------