diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 454acf0..ad4b632 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -13,8 +13,8 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.7, 3.8, 3.9] - django_version: [~=2.2.0, ~=3.2.0] + python-version: [3.8, 3.9, '3.10', 3.11] + django_version: [~=3.2.0, ~=4.2.0] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} diff --git a/.travis.yml b/.travis.yml index 64f4ee6..728b0a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,34 +3,16 @@ os: linux language: python jobs: include: - - python: "2.7" - env: DJANGO=1.11.* DJANGO_SETTINGS_MODULE='settings_sqllite' - - python: "2.7" - env: DJANGO=1.11.* DJANGO_SETTINGS_MODULE='settings_postgres' + - python: "3.8" + env: DJANGO=3.2.* DJANGO_SETTINGS_MODULE='settings_sqllite' + - python: "3.8" + env: DJANGO=3.2.* DJANGO_SETTINGS_MODULE='settings_postgres' services: - postgresql before_script: - psql -c 'create database travis_test;' -U postgres - - python: "2.7" - env: DJANGO=1.11.* DJANGO_SETTINGS_MODULE='settings_mysql' - services: - - mysql - before_script: - - mysql -e 'create database travis_test;' - - python: "3.7" - env: DJANGO=1.11.* DJANGO_SETTINGS_MODULE='settings_sqllite' - - python: "3.7" - env: DJANGO=2.0.* DJANGO_SETTINGS_MODULE='settings_sqllite' - - python: "3.7" - env: DJANGO=3.0.* DJANGO_SETTINGS_MODULE='settings_sqllite' - - python: "3.7" - env: DJANGO=3.0.* DJANGO_SETTINGS_MODULE='settings_postgres' - services: - - postgresql - before_script: - - psql -c 'create database travis_test;' -U postgres - - python: "3.7" - env: DJANGO=3.0.* DJANGO_SETTINGS_MODULE='settings_mysql' + - python: "3.8" + env: DJANGO=3.2.* DJANGO_SETTINGS_MODULE='settings_mysql' services: - mysql before_script: diff --git a/demo/demo/__init__.py b/demo/demo/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/demo/demo/cron.py b/demo/demo/cron.py deleted file mode 100644 index f026950..0000000 --- a/demo/demo/cron.py +++ /dev/null @@ -1,42 +0,0 @@ -import datetime - -from django.conf import settings -from django.contrib.auth.models import User -from django.core.mail import send_mail - -from django_cron import CronJobBase, Schedule - - -class EmailUserCountCronJob(CronJobBase): - """ - Send an email with the user count. - """ - - RUN_EVERY_MINS = 0 if settings.DEBUG else 360 # 6 hours when not DEBUG - - schedule = Schedule(run_every_mins=RUN_EVERY_MINS) - code = 'cron.EmailUserCountCronJob' - - def do(self): - message = 'Active users: %d' % User.objects.count() - print(message) - send_mail( - '[django-cron demo] Active user count', - message, - 'no-reply@django-cron-demo.com', - ['test@django-cron-demo.com'], - ) - - -class WriteDateToFileCronJob(CronJobBase): - """ - Write current date to file. - """ - - schedule = Schedule(run_at_times=["12:20", "12:25"], retry_after_failure_mins=1) - code = 'cron.WriteDateToFileCronJob' - - def do(self): - message = f"Current date: {datetime.datetime.now()} \n" - with open("cron-demo.txt", "w") as myfile: - myfile.write(message) diff --git a/demo/demo/settings.py b/demo/demo/settings.py deleted file mode 100644 index d014e1b..0000000 --- a/demo/demo/settings.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -Django settings for demo project. - -Generated by 'django-admin startproject' using Django 1.9. - -For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ -""" - -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '9q&m51g%e0nel(5s5mwm%d%f%_hld=f(^lc2)rsg$3@_az4##k' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django_cron', -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'demo.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'demo.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } -} - - -# Password validation -# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/1.9/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.9/howto/static-files/ - -STATIC_URL = '/static/' - -EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' - -CRON_CLASSES = [ - "demo.cron.EmailUserCountCronJob", - "demo.cron.WriteDateToFileCronJob", -] -# If you want to test django locking with database -# DJANGO_CRON_LOCK_BACKEND = "django_cron.backends.lock.database.DatabaseLock" diff --git a/demo/demo/urls.py b/demo/demo/urls.py deleted file mode 100644 index 91db732..0000000 --- a/demo/demo/urls.py +++ /dev/null @@ -1,22 +0,0 @@ -"""demo URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.9/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Add an import: from blog import urls as blog_urls - 2. Import the include() function: from django.conf.urls import url, include - 3. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) -""" -from django.contrib import admin -from django.urls import re_path - -urlpatterns = [ - re_path(r'^admin/', admin.site.urls), -] diff --git a/demo/demo/wsgi.py b/demo/demo/wsgi.py deleted file mode 100644 index eca6ef4..0000000 --- a/demo/demo/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for demo project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") - -application = get_wsgi_application() diff --git a/demo/manage.py b/demo/manage.py deleted file mode 100755 index 86cc0b0..0000000 --- a/demo/manage.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff --git a/demo/requirements.txt b/demo/requirements.txt deleted file mode 100644 index 8ea5eff..0000000 --- a/demo/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -Django<4 --e ../ diff --git a/django_cron/backends/lock/database.py b/django_cron/backends/lock/database.py index 3bf78a1..91ccd81 100644 --- a/django_cron/backends/lock/database.py +++ b/django_cron/backends/lock/database.py @@ -5,13 +5,13 @@ class DatabaseLock(DjangoCronJobLock): """ - Locking cron jobs with database. Its good when you have not parallel run and want to make sure 2 jobs won't be + Locking cron jobs with database. It's good when you have not parallel run and want to make sure 2 jobs won't be fired at the same time - which may happened when job execution is longer that job interval. """ @transaction.atomic def lock(self): - lock, created = CronJobLock.objects.get_or_create(job_name=self.job_name) + lock, created = CronJobLock.objects.select_for_update().get_or_create(job_name=self.job_name) if lock.locked: return False else: diff --git a/django_cron/cron.py b/django_cron/cron.py index 5dac8e5..d0f92d2 100644 --- a/django_cron/cron.py +++ b/django_cron/cron.py @@ -1,6 +1,6 @@ from django.conf import settings -from django_common.helper import send_mail +from django.core.mail import send_mail from django_cron import CronJobBase, Schedule, get_class from django_cron.models import CronJobLog @@ -97,5 +97,5 @@ def get_send_mail_kwargs(self, cron_cls, failed_jobs): return dict( subject=subject, message=message, from_email=self.config['CRON_FAILURE_FROM_EMAIL'], - recipient_emails=self.config['CRON_FAILURE_EMAIL_RECIPIENTS'] + recipient_list=self.config['CRON_FAILURE_EMAIL_RECIPIENTS'] ) diff --git a/django_cron/tests.py b/django_cron/tests.py index ece4266..9a9d647 100644 --- a/django_cron/tests.py +++ b/django_cron/tests.py @@ -480,5 +480,5 @@ def test_uses_send_mail(self, mock_send_mail): self.assertIn('ERROR!!!', kwargs['subject']) self.assertEquals('from@email.com', kwargs['from_email']) self.assertEquals( - ['foo@bar.com', 'x@y.com'], kwargs['recipient_emails'] + ['foo@bar.com', 'x@y.com'], kwargs['recipient_list'] ) diff --git a/docs/conf.py b/docs/conf.py index 93a6bfa..c798a11 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ # built documents. # # The short X.Y version. -version = '0.6' +version = '0.7' # The full version, including alpha/beta/rc tags. -release = '0.6.1a1' +release = '0.7.1a1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 39d3e40..1ceb12f 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ setup( name='django-cron', - version='0.6.1a1', + version='0.7.1a1', author='Sumit Chachra', author_email='chachra@tivix.com', url='http://github.com/tivix/django-cron', @@ -29,7 +29,7 @@ long_description=long_description, keywords='django cron', zip_safe=False, - install_requires=['Django>=2.2,<4', 'django-common-helpers>=0.6.4'], + install_requires=['Django>=3.2,<5', 'django-common-helpers>=0.6.4'], test_suite='runtests.runtests', include_package_data=True, classifiers=[