Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Django 4.0 and Python 3.10 support #528

Merged
merged 15 commits into from
Jun 4, 2022
Merged
8 changes: 7 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.7', '3.8', '3.9', 'pypy-3.9']
python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.9']

services:
rabbitmq:
image: rabbitmq
ports:
- "5672:5672"

steps:
- uses: actions/checkout@v3
Expand Down
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Important Warning about Time Zones



.. note::
.. note::
This will reset the state as if the periodic tasks have never run before.


Expand Down Expand Up @@ -95,7 +95,7 @@ create the interval object:
.. code-block:: Python

>>> from django_celery_beat.models import PeriodicTask, IntervalSchedule

# executes every 10 seconds.
>>> schedule, created = IntervalSchedule.objects.get_or_create(
... every=10,
Expand Down Expand Up @@ -181,7 +181,7 @@ of a ``30 * * * *`` (execute every 30 minutes) crontab entry you specify:
... day_of_week='*',
... day_of_month='*',
... month_of_year='*',
... timezone=pytz.timezone('Canada/Pacific')
... timezone=zoneinfo.ZoneInfo('Canada/Pacific')
... )

The crontab schedule is linked to a specific timezone using the 'timezone' input parameter.
Expand Down Expand Up @@ -288,7 +288,7 @@ After installation, add ``django_celery_beat`` to Django's settings module:
Run the ``django_celery_beat`` migrations using:

.. code-block:: bash

$ python manage.py migrate django_celery_beat


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.0.3 on 2022-03-21 20:20
# flake8: noqa
from django.db import migrations
import django_celery_beat.models
import timezone_field.fields


class Migration(migrations.Migration):

dependencies = [
('django_celery_beat', '0015_edit_solarschedule_events_choices'),
]

operations = [
migrations.AlterField(
model_name='crontabschedule',
name='timezone',
field=timezone_field.fields.TimeZoneField(
default=
django_celery_beat.models.crontab_schedule_celery_timezone,
help_text=
'Timezone to Run the Cron Schedule on. Default is UTC.',
use_pytz=False, verbose_name='Cron Timezone'),
),
]
16 changes: 10 additions & 6 deletions django_celery_beat/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
"""Database models."""
try:
from zoneinfo import available_timezones
except ImportError:
from backports.zoneinfo import available_timezones
from datetime import timedelta

import timezone_field
Expand Down Expand Up @@ -66,10 +70,9 @@ def crontab_schedule_celery_timezone():
settings, '%s_TIMEZONE' % current_app.namespace)
except AttributeError:
return 'UTC'
return CELERY_TIMEZONE if CELERY_TIMEZONE in [
choice[0].zone for choice in timezone_field.
TimeZoneField.default_choices
] else 'UTC'
if CELERY_TIMEZONE in available_timezones():
return CELERY_TIMEZONE
return 'UTC'


class SolarSchedule(models.Model):
Expand Down Expand Up @@ -297,6 +300,7 @@ class CrontabSchedule(models.Model):

timezone = timezone_field.TimeZoneField(
default=crontab_schedule_celery_timezone,
use_pytz=False,
verbose_name=_('Cron Timezone'),
help_text=_(
'Timezone to Run the Cron Schedule on. Default is UTC.'),
Expand Down Expand Up @@ -357,8 +361,8 @@ def from_schedule(cls, schedule):
class PeriodicTasks(models.Model):
"""Helper table for tracking updates to periodic tasks.

This stores a single row with ``ident=1``. ``last_update`` is updated
via django signals whenever anything is changed in the :class:`~.PeriodicTask` model.
This stores a single row with ``ident=1``. ``last_update`` is updated via
signals whenever anything changes in the :class:`~.PeriodicTask` model.
Basically this acts like a DB data audit trigger.
Doing this so we also track deletions, and not just insert/update.
"""
Expand Down
6 changes: 1 addition & 5 deletions django_celery_beat/schedulers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,8 @@ def is_due(self):
return self.schedule.is_due(last_run_at_in_tz)

def _default_now(self):
# The PyTZ datetime must be localised for the Django-Celery-Beat
# scheduler to work. Keep in mind that timezone arithmatic
# with a localized timezone may be inaccurate.
if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True):
now = self.app.now()
now = now.tzinfo.localize(now.replace(tzinfo=None))
now = datetime.datetime.now(self.app.timezone)
else:
# this ends up getting passed to maybe_make_aware, which expects
# all naive datetime objects to be in utc time.
Expand Down
9 changes: 3 additions & 6 deletions django_celery_beat/tzcrontab.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from celery import schedules

from collections import namedtuple
from datetime import datetime
import pytz
from datetime import datetime, timezone


schedstate = namedtuple('schedstate', ('is_due', 'next'))
Expand All @@ -14,7 +13,7 @@ class TzAwareCrontab(schedules.crontab):

def __init__(
self, minute='*', hour='*', day_of_week='*',
day_of_month='*', month_of_year='*', tz=pytz.utc, app=None
day_of_month='*', month_of_year='*', tz=timezone.utc, app=None
):
"""Overwrite Crontab constructor to include a timezone argument."""
self.tz = tz
Expand All @@ -28,9 +27,7 @@ def __init__(
)

def nowfunc(self):
return self.tz.normalize(
pytz.utc.localize(datetime.utcnow())
)
return datetime.now(self.tz)

def is_due(self, last_run_at):
"""Calculate when the next run will take place.
Expand Down
8 changes: 4 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
],
extlinks={
'github_project': (
f'https://github.com/%s',
'GitHub project',
'https://github.com/%s',
'GitHub project %s',
),
'github_pr': (
f'https://github.com/celery/django-celery-beat/pull/%s',
'GitHub PR #',
'https://github.com/celery/django-celery-beat/pull/%s',
'GitHub PR #%s',
),
},
extra_intersphinx_mapping={
Expand Down
4 changes: 3 additions & 1 deletion requirements/default.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
celery>=5.2.3,<6.0
django-timezone-field>=4.2.3
django-timezone-field>=5.0
backports.zoneinfo; python_version<"3.9"
tzdata
python-crontab>=2.3.4
ElSaico marked this conversation as resolved.
Show resolved Hide resolved
1 change: 0 additions & 1 deletion requirements/test-django22.txt

This file was deleted.

5 changes: 2 additions & 3 deletions requirements/test.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
case>=1.3.1
pytest-django<5.0
pytz>dev
pytest<8.0
pytest-django>=2.2,<5.0
pytest>=6.2.5,<8.0
pytest-timeout
ephem
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ def _pyimp():
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
Framework :: Django
Framework :: Django :: 4.0
Framework :: Django :: 3.2
Framework :: Django :: 4.0
Operating System :: OS Independent
Topic :: Communications
Topic :: System :: Distributed Computing
Expand Down
2 changes: 1 addition & 1 deletion t/proj/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
from django.urls import path

urlpatterns = [
path('admin/', admin.site.urls),
path('admin/', admin.site.urls),
]
21 changes: 12 additions & 9 deletions t/unit/test_models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import datetime
import os
try:
from zoneinfo import available_timezones, ZoneInfo
except ImportError:
from backports.zoneinfo import available_timezones, ZoneInfo

from celery import schedules
from django.test import TestCase, override_settings
Expand All @@ -9,8 +14,6 @@
from django.db.migrations.questioner import NonInteractiveMigrationQuestioner
from django.utils import timezone
from django.conf import settings
import pytz, datetime
import timezone_field

from django_celery_beat import migrations as beat_migrations
from django_celery_beat.models import (
Expand Down Expand Up @@ -84,8 +87,7 @@ def _test_duplicate_schedules(self, cls, kwargs, schedule=None):


class CrontabScheduleTestCase(TestCase, TestDuplicatesMixin):
FIRST_VALID_TIMEZONE = timezone_field.\
TimeZoneField.default_choices[0][0].zone
FIRST_VALID_TIMEZONE = available_timezones().pop()

def test_default_timezone_without_settings_config(self):
assert crontab_schedule_celery_timezone() == "UTC"
Expand Down Expand Up @@ -148,11 +150,12 @@ def test_duplicate_schedules(self):
kwargs = {'clocked_time': timezone.now()}
self._test_duplicate_schedules(ClockedSchedule, kwargs)

# IMPORTANT: we must have a valid time-zone (not UTC) to do an accurate testing
@override_settings(TIME_ZONE='Africa/Cairo')
# IMPORTANT: we must have a valid timezone (not UTC) for accurate testing
@override_settings(TIME_ZONE='Africa/Cairo')
def test_timezone_format(self):
"""Make sure the scheduled time is not shown in UTC when time zone is used"""
tz_info = pytz.timezone(settings.TIME_ZONE).localize(datetime.datetime.utcnow())
schedule, created = ClockedSchedule.objects.get_or_create(clocked_time=tz_info)
"""Ensure scheduled time is not shown in UTC when timezone is used"""
tz_info = datetime.datetime.now(ZoneInfo(settings.TIME_ZONE))
schedule, created = ClockedSchedule.objects.get_or_create(
clocked_time=tz_info)
# testnig str(schedule) calls make_aware() internally
assert str(schedule.clocked_time) == str(schedule)
8 changes: 5 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ python =
3.7: py37
3.8: py38, apicheck, linkcheck
3.9: py39, flake8, pydocstyle, cov
3.10: py310
pypy-3.9: pypy3

[gh-actions:env]
DJANGO =
3.2: django32
4.0: django40

[tox]
envlist =
py37-django{32}
py38-django{32,40}
py39-django{32,40}
py310-django{32,40}
pypy3-django{32}
flake8
apicheck
Expand Down Expand Up @@ -43,12 +45,12 @@ commands =


[testenv:apicheck]
basepython = python3.9
basepython = python3.8
commands =
sphinx-build -W -b apicheck -d {envtmpdir}/doctrees docs docs/_build/apicheck

[testenv:linkcheck]
basepython = python3.9
basepython = python3.8
commands =
sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/linkcheck

Expand Down