diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2603e606..72f874dd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,22 +2,6 @@ exclude: "migrations" repos: - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 - hooks: - - id: pyupgrade - args: ["--py37-plus"] - - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - - - repo: https://github.com/asottile/yesqa - rev: v1.5.0 - hooks: - - id: yesqa - - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: @@ -26,7 +10,11 @@ repos: - id: check-yaml - id: mixed-line-ending - - repo: https://github.com/pycqa/isort - rev: 5.13.2 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.11 hooks: - - id: isort + # Run the linter. + - id: ruff + # args: [ --fix ] + # Run the formatter. + # - id: ruff-format diff --git a/Makefile b/Makefile index 7f34b4a4..128ed4f1 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,7 @@ PYTEST=pytest GIT=git TOX=tox ICONV=iconv -FLAKE8=flake8 -FLAKEPLUS=flakeplus -PYDOCSTYLE=pydocstyle +RUFF=ruff SPHINX2RST=sphinx2rst SPHINX_DIR=docs/ @@ -18,7 +16,6 @@ CONTRIBUTING=CONTRIBUTING.rst CONTRIBUTING_SRC="docs/contributing.rst" SPHINX_HTMLDIR="${SPHINX_BUILDDIR}/html" DOCUMENTATION=Documentation -FLAKEPLUSTARGET=2.7 TESTDIR=t @@ -34,10 +31,7 @@ help: @echo " configcheck - Check configuration reference coverage." @echo " readmecheck - Check README.rst encoding." @echo " contribcheck - Check CONTRIBUTING.rst encoding" - @echo " flakes -------- - Check code for syntax and style errors." - @echo " flakecheck - Run flake8 on the source code." - @echo " flakepluscheck - Run flakeplus on the source code." - @echo " pep257check - Run flakeplus on the source code." + @echo " ruff ---------- - Check code for syntax and style errors." @echo "readme - Regenerate README.rst file." @echo "contrib - Regenerate CONTRIBUTING.rst file" @echo "clean-dist --------- - Clean all distribution build artifacts." @@ -76,7 +70,7 @@ docs: Documentation clean-docs: -rm -rf "$(SPHINX_BUILDDIR)" -lint: flakecheck apicheck configcheck readmecheck +lint: ruff apicheck configcheck readmecheck apicheck: (cd "$(SPHINX_DIR)"; $(MAKE) apicheck) @@ -84,22 +78,8 @@ apicheck: configcheck: true -flakecheck: - $(FLAKE8) "$(PROJ)" "$(TESTDIR)" - -flakediag: - -$(MAKE) flakecheck - -flakepluscheck: - $(FLAKEPLUS) --$(FLAKEPLUSTARGET) "$(PROJ)" "$(TESTDIR)" - -flakeplusdiag: - -$(MAKE) flakepluscheck - -pep257check: - $(PYDOCSTYLE) "$(PROJ)" - -flakes: flakediag flakeplusdiag pep257check +ruff: + $(RUFF) . clean-readme: -rm -f $(README) diff --git a/django_celery_beat/admin.py b/django_celery_beat/admin.py index add96779..cb19ddc6 100644 --- a/django_celery_beat/admin.py +++ b/django_celery_beat/admin.py @@ -10,8 +10,7 @@ from django.utils.translation import gettext_lazy as _ from kombu.utils.json import loads -from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule, - PeriodicTask, PeriodicTasks, SolarSchedule) +from .models import ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule from .utils import is_database_scheduler @@ -23,8 +22,8 @@ class TaskSelectWidget(Select): def tasks_as_choices(self): _ = self._modules - tasks = list(sorted(name for name in self.celery_app.tasks - if not name.startswith('celery.'))) + tasks = sorted(name for name in self.celery_app.tasks + if not name.startswith('celery.')) return (('', ''), ) + tuple(zip(tasks, tasks)) @property diff --git a/django_celery_beat/migrations/0003_auto_20161209_0049.py b/django_celery_beat/migrations/0003_auto_20161209_0049.py index 36881068..ddaff938 100644 --- a/django_celery_beat/migrations/0003_auto_20161209_0049.py +++ b/django_celery_beat/migrations/0003_auto_20161209_0049.py @@ -18,6 +18,6 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='solarschedule', - unique_together=set([('event', 'latitude', 'longitude')]), + unique_together={('event', 'latitude', 'longitude')}, ), ] diff --git a/django_celery_beat/migrations/0010_auto_20190429_0326.py b/django_celery_beat/migrations/0010_auto_20190429_0326.py index ae948ddf..b41e042b 100644 --- a/django_celery_beat/migrations/0010_auto_20190429_0326.py +++ b/django_celery_beat/migrations/0010_auto_20190429_0326.py @@ -1,7 +1,7 @@ # Generated by Django 1.11.20 on 2019-04-29 03:26 -# this file is auto-generated so don't do flake8 on it -# flake8: noqa +# this file is auto-generated so don't do ruff lint on it +# ruff: noqa import django.core.validators from django.db import migrations, models import django.db.models.deletion diff --git a/django_celery_beat/migrations/0011_auto_20190508_0153.py b/django_celery_beat/migrations/0011_auto_20190508_0153.py index d77e7e77..76483a80 100644 --- a/django_celery_beat/migrations/0011_auto_20190508_0153.py +++ b/django_celery_beat/migrations/0011_auto_20190508_0153.py @@ -1,5 +1,5 @@ # Generated by Django 2.2 on 2019-05-08 01:53 -# flake8: noqa +# ruff: noqa from django.db import migrations, models import django.db.models.deletion diff --git a/django_celery_beat/migrations/0012_periodictask_expire_seconds.py b/django_celery_beat/migrations/0012_periodictask_expire_seconds.py index aab98bf1..bdc1d5e7 100644 --- a/django_celery_beat/migrations/0012_periodictask_expire_seconds.py +++ b/django_celery_beat/migrations/0012_periodictask_expire_seconds.py @@ -1,5 +1,5 @@ # Generated by Django 2.2.4 on 2019-08-30 00:46 -# flake8: noqa +# ruff: noqa from django.db import migrations, models diff --git a/django_celery_beat/migrations/0013_auto_20200609_0727.py b/django_celery_beat/migrations/0013_auto_20200609_0727.py index eb9040d6..545631c1 100644 --- a/django_celery_beat/migrations/0013_auto_20200609_0727.py +++ b/django_celery_beat/migrations/0013_auto_20200609_0727.py @@ -1,5 +1,5 @@ # Generated by Django 3.0.6 on 2020-06-09 07:27 -# flake8: noqa +# ruff: noqa from django.db import migrations import django_celery_beat.models import timezone_field.fields diff --git a/django_celery_beat/migrations/0014_remove_clockedschedule_enabled.py b/django_celery_beat/migrations/0014_remove_clockedschedule_enabled.py index 0ee02ddc..32ddb79e 100644 --- a/django_celery_beat/migrations/0014_remove_clockedschedule_enabled.py +++ b/django_celery_beat/migrations/0014_remove_clockedschedule_enabled.py @@ -1,5 +1,5 @@ # Generated by Django 2.2.4 on 2019-08-30 00:46 -# flake8: noqa +# ruff: noqa from django.db import migrations diff --git a/django_celery_beat/migrations/0015_edit_solarschedule_events_choices.py b/django_celery_beat/migrations/0015_edit_solarschedule_events_choices.py index 8ec6ae36..e1a86431 100644 --- a/django_celery_beat/migrations/0015_edit_solarschedule_events_choices.py +++ b/django_celery_beat/migrations/0015_edit_solarschedule_events_choices.py @@ -1,5 +1,5 @@ # Generated by Django 3.0.6 on 2020-12-13 15:00 -# flake8: noqa +# ruff: noqa from django.db import migrations, models diff --git a/django_celery_beat/migrations/0016_alter_crontabschedule_timezone.py b/django_celery_beat/migrations/0016_alter_crontabschedule_timezone.py index ccff6ea3..16a935c8 100644 --- a/django_celery_beat/migrations/0016_alter_crontabschedule_timezone.py +++ b/django_celery_beat/migrations/0016_alter_crontabschedule_timezone.py @@ -1,5 +1,5 @@ # Generated by Django 4.0.3 on 2022-03-21 20:20 -# flake8: noqa +# ruff: noqa from django.db import migrations import django_celery_beat.models import timezone_field.fields diff --git a/django_celery_beat/models.py b/django_celery_beat/models.py index 4f3e1578..a23aeaf5 100644 --- a/django_celery_beat/models.py +++ b/django_celery_beat/models.py @@ -8,8 +8,7 @@ import timezone_field from celery import current_app, schedules -from cron_descriptor import (FormatException, MissingFieldException, - WrongArgumentException, get_description) +from cron_descriptor import FormatException, MissingFieldException, WrongArgumentException, get_description from django.conf import settings from django.core.exceptions import MultipleObjectsReturned, ValidationError from django.core.validators import MaxValueValidator, MinValueValidator @@ -131,11 +130,7 @@ def from_schedule(cls, schedule): return cls(**spec) def __str__(self): - return '{} ({}, {})'.format( - self.get_event_display(), - self.latitude, - self.longitude - ) + return f'{self.get_event_display()} ({self.latitude}, {self.longitude})' class IntervalSchedule(models.Model): @@ -317,11 +312,7 @@ class Meta: @property def human_readable(self): - cron_expression = '{} {} {} {} {}'.format( - cronexp(self.minute), cronexp(self.hour), - cronexp(self.day_of_month), cronexp(self.month_of_year), - cronexp(self.day_of_week) - ) + cron_expression = f'{cronexp(self.minute)} {cronexp(self.hour)} {cronexp(self.day_of_month)} {cronexp(self.month_of_year)} {cronexp(self.day_of_week)}' try: human_readable = get_description(cron_expression) except ( @@ -333,11 +324,7 @@ def human_readable(self): return f'{human_readable} {str(self.timezone)}' def __str__(self): - return '{} {} {} {} {} (m/h/dM/MY/d) {}'.format( - cronexp(self.minute), cronexp(self.hour), - cronexp(self.day_of_month), cronexp(self.month_of_year), - cronexp(self.day_of_week), str(self.timezone) - ) + return f'{cronexp(self.minute)} {cronexp(self.hour)} {cronexp(self.day_of_month)} {cronexp(self.month_of_year)} {cronexp(self.day_of_week)} (m/h/dM/MY/d) {str(self.timezone)}' @property def schedule(self): @@ -579,8 +566,7 @@ def validate_unique(self, *args, **kwargs): 'must be set.' ) - err_msg = 'Only one of clocked, interval, crontab, '\ - 'or solar must be set' + err_msg = 'Only one of clocked, interval, crontab, or solar must be set' if len(selected_schedule_types) > 1: error_info = {} for selected_schedule_type in selected_schedule_types: diff --git a/django_celery_beat/schedulers.py b/django_celery_beat/schedulers.py index 846b97a9..8ef14eb5 100644 --- a/django_celery_beat/schedulers.py +++ b/django_celery_beat/schedulers.py @@ -1,4 +1,5 @@ """Beat Scheduler Implementation.""" +import contextlib import datetime import logging import math @@ -16,8 +17,7 @@ from kombu.utils.json import dumps, loads from .clockedschedule import clocked -from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule, - PeriodicTask, PeriodicTasks, SolarSchedule) +from .models import ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule from .utils import NEVER_CHECK_TIMEOUT # This scheduler must wake up more frequently than the @@ -136,12 +136,12 @@ def is_due(self): return self.schedule.is_due(last_run_at_in_tz) def _default_now(self): - if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True): + if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True): # noqa: SIM108 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. - now = datetime.datetime.utcnow() + now = datetime.datetime.utcnow() # utcnow() is deprecated in Python 3.12 return now def __next__(self): @@ -149,7 +149,7 @@ def __next__(self): self.model.total_run_count += 1 self.model.no_changes = True return self.__class__(self.model) - next = __next__ # for 2to3 + next = __next__ # for 2to3 # noqa: A003 def save(self): # Object may not be synchronized, so only @@ -209,10 +209,7 @@ def _unpack_options(cls, queue=None, exchange=None, routing_key=None, } def __repr__(self): - return ''.format( - safe_str(self.name), self.task, safe_repr(self.args), - safe_repr(self.kwargs), self.schedule, - ) + return f'' class DatabaseScheduler(Scheduler): @@ -245,10 +242,8 @@ def all_as_schedule(self): debug('DatabaseScheduler: Fetching database schedule') s = {} for model in self.Model.objects.enabled(): - try: + with contextlib.suppress(ValueError): s[model.name] = self.Entry(model, app=self.app) - except ValueError: - pass return s def schedule_changed(self): @@ -259,10 +254,8 @@ def schedule_changed(self): # REPEATABLE-READ (default), then we won't see changes done by # other transactions until the current transaction is # committed (Issue #41). - try: + with contextlib.suppress(transaction.TransactionManagementError): transaction.commit() - except transaction.TransactionManagementError: - pass # not in transaction management. last, ts = self._last_timestamp, self.Changes.last_change() except DatabaseError as exc: @@ -325,7 +318,7 @@ def update_from_dict(self, mapping): if entry.model.enabled: s[name] = entry - except Exception as exc: + except Exception as exc: # noqa: PERF203 logger.exception(ADD_ENTRY_ERROR, name, exc, entry_fields) self.schedule.update(s) diff --git a/django_celery_beat/signals.py b/django_celery_beat/signals.py index 65a4d769..17f0db34 100644 --- a/django_celery_beat/signals.py +++ b/django_celery_beat/signals.py @@ -5,8 +5,7 @@ def signals_connect(): """Connect to signals.""" from django.db.models import signals - from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule, - PeriodicTask, PeriodicTasks, SolarSchedule) + from .models import ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule signals.pre_save.connect( PeriodicTasks.changed, sender=PeriodicTask diff --git a/django_celery_beat/tzcrontab.py b/django_celery_beat/tzcrontab.py index 3c41f9f5..cd9fcbd1 100644 --- a/django_celery_beat/tzcrontab.py +++ b/django_celery_beat/tzcrontab.py @@ -48,10 +48,10 @@ def is_due(self, last_run_at): # Needed to support pickling def __repr__(self): - return """ - """.format(self) + return f""" + """ def __reduce__(self): return (self.__class__, (self._orig_minute, diff --git a/django_celery_beat/utils.py b/django_celery_beat/utils.py index f22b65b6..fd18a580 100644 --- a/django_celery_beat/utils.py +++ b/django_celery_beat/utils.py @@ -23,10 +23,9 @@ def make_aware(value): # then convert to the Django configured timezone. default_tz = timezone.get_default_timezone() value = timezone.localtime(value, default_tz) - else: + elif timezone.is_naive(value): # naive datetimes are assumed to be in local timezone. - if timezone.is_naive(value): - value = timezone.make_aware(value, timezone.get_default_timezone()) + value = timezone.make_aware(value, timezone.get_default_timezone()) return value diff --git a/django_celery_beat/validators.py b/django_celery_beat/validators.py index 71c8fd34..afa88426 100644 --- a/django_celery_beat/validators.py +++ b/django_celery_beat/validators.py @@ -19,7 +19,7 @@ def __init__(self, *args): def validate(cls, *args): try: cls(*args) - except Exception as e: + except Exception as e: # noqa: BLE001 raise ValueError(e) @@ -59,7 +59,7 @@ def parse(self, value): self.dangling = 0 self.vto = self.slice.parse_value(vto, sunday=6) if self.vto < self.vfrom: - raise ValueError("Bad range '{0.vfrom}-{0.vto}'".format(self)) + raise ValueError(f"Bad range '{self.vfrom}-{self.vto}'") elif value == '*': self.all() else: diff --git a/docs/conf.py b/docs/conf.py index 2afa72bd..ee731cef 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,4 @@ -import os +import os # noqa: INP001 from sphinx_celery import conf diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..b5077c8f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,88 @@ +[tool.ruff] +select = [ + "A", # flake8-builtins + "AIR", # Airflow + "ASYNC", # flake8-async + "BLE", # flake8-blind-except + "C4", # flake8-comprehensions + "C90", # McCabe cyclomatic complexity + "CPY", # flake8-copyright + "DJ", # flake8-django + "E", # pycodestyle + "EXE", # flake8-executable + "F", # Pyflakes + "FA", # flake8-future-annotations + "FLY", # flynt + "FURB", # refurb + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "INP", # flake8-no-pep420 + "ISC", # flake8-implicit-str-concat + "LOG", # flake8-logging + "N", # pep8-naming + "NPY", # NumPy-specific rules + "PD", # pandas-vet + "PERF", # Perflint + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # Pylint + "PT", # flake8-pytest-style + "RSE", # flake8-raise + "S", # flake8-bandit + "SIM", # flake8-simplify + "SLOT", # flake8-slots + "T10", # flake8-debugger + "TCH", # flake8-type-checking + "TID", # flake8-tidy-imports + "TRIO", # flake8-trio + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 + # "ANN", # flake8-annotations + # "ARG", # flake8-unused-arguments + # "B", # flake8-bugbear + # "COM", # flake8-commas + # "D", # pydocstyle + # "DTZ", # flake8-datetimez + # "EM", # flake8-errmsg + # "ERA", # eradicate + # "FBT", # flake8-boolean-trap + # "FIX", # flake8-fixme + # "INT", # flake8-gettext + # "PTH", # flake8-use-pathlib + # "PYI", # flake8-pyi + # "Q", # flake8-quotes + # "RET", # flake8-return + # "RUF", # Ruff-specific rules + # "SLF", # flake8-self + # "T20", # flake8-print + # "TD", # flake8-todos + # "TRY", # tryceratops +] +ignore = [ + "DJ001", + "DJ006", + "DJ008", + "DJ012", + "N801", + "N802", + "N803", + "N806", + "PT004", + "PT009", + "PT027", +] +line-length = 274 +target-version = "py38" + +[tool.ruff.per-file-ignores] +"*/migrations/*" = ["D", "I"] +"docker/base/celery.py" = ["INP001"] +"setup.py" = ["EXE001"] +"t/*" = ["S101"] +"t/unit/conftest.py" = ["F401"] + +[tool.ruff.pylint] +allow-magic-value-types = ["float", "int", "str"] +max-args = 8 # Default: 5 diff --git a/requirements/pkgutils.txt b/requirements/pkgutils.txt index eec7d2ca..6980835e 100644 --- a/requirements/pkgutils.txt +++ b/requirements/pkgutils.txt @@ -1,7 +1,6 @@ +bumpversion +ruff setuptools>=40.8.0 -wheel>=0.33.1 -flake8>=3.8.3 -tox>=2.3.1 sphinx2rst>=1.0 -bumpversion -pydocstyle +tox>=2.3.1 +wheel>=0.33.1 diff --git a/setup.cfg b/setup.cfg index 1e9f7c02..6c5b1e1f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,14 +2,3 @@ testpaths = t/unit/ python_classes = test_* DJANGO_SETTINGS_MODULE=t.proj.settings - -[flake8] -# classes can be lowercase, arguments and variables can be uppercase -# whenever it makes the code more readable. -ignore = N806, N802, N801, N803, W503, W504 -exclude = - **/migrations/*.py - -[pep257] -ignore = D102,D104,D203,D105,D213 -match-dir = [^migrations] diff --git a/setup.py b/setup.py index ad06b5f7..81afca3d 100644 --- a/setup.py +++ b/setup.py @@ -98,7 +98,7 @@ def _pip_requirement(req): def _reqs(*f): return [ _pip_requirement(r) for r in ( - strip_comments(line) for line in open( + strip_comments(line) for line in open( # noqa: SIM115 os.path.join(os.getcwd(), 'requirements', *f)).readlines() ) if r] diff --git a/t/proj/__init__.py b/t/proj/__init__.py index 0a8d3da3..044e6676 100644 --- a/t/proj/__init__.py +++ b/t/proj/__init__.py @@ -1 +1 @@ -from .celery import app as celery_app # noqa +from .celery import app as celery_app # noqa: F401 diff --git a/t/proj/models.py b/t/proj/models.py index 597c46eb..c2c90b23 100644 --- a/t/proj/models.py +++ b/t/proj/models.py @@ -5,4 +5,3 @@ class O2OToPeriodicTasks(PeriodicTask): """ The test-case model of OneToOne relation. """ - pass diff --git a/t/proj/settings.py b/t/proj/settings.py index abf8f4f4..75c6b9da 100644 --- a/t/proj/settings.py +++ b/t/proj/settings.py @@ -31,7 +31,7 @@ # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'u($kbs9$irs0)436gbo9%!b&#zyd&70tx!n7!i&fl6qun@z1_l' +SECRET_KEY = 'u($kbs9$irs0)436gbo9%!b&#zyd&70tx!n7!i&fl6qun@z1_l' # noqa: S105 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/t/unit/conftest.py b/t/unit/conftest.py index a4f34c7e..1d323721 100644 --- a/t/unit/conftest.py +++ b/t/unit/conftest.py @@ -1,19 +1,18 @@ from unittest.mock import MagicMock import pytest + # we have to import the pytest plugin fixtures here, # in case user did not do the `python setup.py develop` yet, # that installs the pytest plugin into the setuptools registry. -from celery.contrib.pytest import (celery_app, celery_config, - celery_enable_logging, celery_parameters, - depends_on_current_app, use_celery_app_trap) +from celery.contrib.pytest import celery_app, celery_config, celery_enable_logging, celery_parameters, depends_on_current_app, use_celery_app_trap from celery.contrib.testing.app import TestApp, Trap # Tricks flake8 into silencing redefining fixtures warnings. -__all__ = ( - 'celery_app', 'celery_enable_logging', 'depends_on_current_app', - 'celery_parameters', 'celery_config', 'use_celery_app_trap' -) +#__all__ = ( +# 'celery_app', 'celery_enable_logging', 'depends_on_current_app', +# 'celery_parameters', 'celery_config', 'use_celery_app_trap' +#) @pytest.fixture(scope='session', autouse=True) @@ -23,7 +22,7 @@ def setup_default_app_trap(): @pytest.fixture() -def app(celery_app): +def app(celery_app): # noqa: F811 return celery_app @@ -44,7 +43,7 @@ def add(x, y): request.instance.app = None -@pytest.fixture +@pytest.fixture() def patching(monkeypatch): def _patching(attr): monkeypatch.setattr(attr, MagicMock()) diff --git a/t/unit/test_admin.py b/t/unit/test_admin.py index 6d35c17c..1b9b87dd 100644 --- a/t/unit/test_admin.py +++ b/t/unit/test_admin.py @@ -6,9 +6,7 @@ from django.test import TestCase from django_celery_beat.admin import PeriodicTaskAdmin -from django_celery_beat.models import (DAYS, ClockedSchedule, CrontabSchedule, - IntervalSchedule, PeriodicTask, - SolarSchedule) +from django_celery_beat.models import DAYS, ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, SolarSchedule @pytest.mark.django_db() diff --git a/t/unit/test_models.py b/t/unit/test_models.py index a745d76c..6103281f 100644 --- a/t/unit/test_models.py +++ b/t/unit/test_models.py @@ -4,7 +4,7 @@ try: from zoneinfo import ZoneInfo, available_timezones except ImportError: - from backports.zoneinfo import available_timezones, ZoneInfo + from backports.zoneinfo import ZoneInfo, available_timezones import pytest from celery import schedules @@ -18,10 +18,7 @@ from django.utils import timezone from django_celery_beat import migrations as beat_migrations -from django_celery_beat.models import (DAYS, ClockedSchedule, CrontabSchedule, - IntervalSchedule, PeriodicTasks, - SolarSchedule, - crontab_schedule_celery_timezone) +from django_celery_beat.models import DAYS, ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTasks, SolarSchedule, crontab_schedule_celery_timezone from t.proj.models import O2OToPeriodicTasks @@ -104,7 +101,7 @@ def test_duplicate_schedules(self): "day_of_week": "*", "day_of_month": "*", "month_of_year": "*", - "day_of_week": "*", + "day_of_week": "*", # noqa: F601 } schedule = schedules.crontab(hour="4") self._test_duplicate_schedules(CrontabSchedule, kwargs, schedule) diff --git a/t/unit/test_schedulers.py b/t/unit/test_schedulers.py index dbafe666..c7c436d7 100644 --- a/t/unit/test_schedulers.py +++ b/t/unit/test_schedulers.py @@ -15,9 +15,7 @@ from django_celery_beat import schedulers from django_celery_beat.admin import PeriodicTaskAdmin from django_celery_beat.clockedschedule import clocked -from django_celery_beat.models import (DAYS, ClockedSchedule, CrontabSchedule, - IntervalSchedule, PeriodicTask, - PeriodicTasks, SolarSchedule) +from django_celery_beat.models import DAYS, ClockedSchedule, CrontabSchedule, IntervalSchedule, PeriodicTask, PeriodicTasks, SolarSchedule from django_celery_beat.utils import NEVER_CHECK_TIMEOUT, make_aware _ids = count(0) @@ -83,27 +81,27 @@ def create_model_clocked(self, schedule, **kwargs): def create_conf_entry(self): name = f'thefoo{next(_ids)}' - return name, dict( - task=f'djcelery.unittest.add{next(_ids)}', - schedule=timedelta(0, 600), - args=(), - relative=False, - kwargs={}, - options={'queue': 'extra_queue'} - ) + return name, { + 'task': f'djcelery.unittest.add{next(_ids)}', + 'schedule': timedelta(0, 600), + 'args': (), + 'relative': False, + 'kwargs': {}, + 'options': {'queue': 'extra_queue'} + } def create_model(self, Model=PeriodicTask, **kwargs): - entry = dict( - name=f'thefoo{next(_ids)}', - task=f'djcelery.unittest.add{next(_ids)}', - args='[2, 2]', - kwargs='{"callback": "foo"}', - queue='xaz', - routing_key='cpu', - priority=1, - headers='{"_schema_name": "foobar"}', - exchange='foo', - ) + entry = { + 'name': f'thefoo{next(_ids)}', + 'task': f'djcelery.unittest.add{next(_ids)}', + 'args': '[2, 2]', + 'kwargs': '{"callback": "foo"}', + 'queue': 'xaz', + 'routing_key': 'cpu', + 'priority': 1, + 'headers': '{"_schema_name": "foobar"}', + 'exchange': 'foo', + } return Model(**dict(entry, **kwargs)) def create_interval_schedule(self): @@ -407,7 +405,7 @@ def test_all_as_schedule(self): assert sched assert len(sched) == 6 assert 'celery.backend_cleanup' in sched - for n, e in sched.items(): + for e in sched.values(): assert isinstance(e, self.s.Entry) def test_schedule_changed(self): @@ -619,7 +617,8 @@ def test_heap_always_return_the_first_item(self): time.sleep(tick_interval) if s.should_sync(): s.sync() - assert len(tried) == 1 and tried == {e1.name} + assert len(tried) == 1 + assert tried == {e1.name} def test_starttime_trigger(self, monkeypatch): # Ensure there is no heap block in case of new task with start_time @@ -677,9 +676,7 @@ def test_PeriodicTask_unicode_crontab(self): hour='4, 5', day_of_week='4, 5', )) - assert str(p) == """{}: * 4,5 * * 4,5 (m/h/dM/MY/d) UTC""".format( - p.name - ) + assert str(p) == f"""{p.name}: * 4,5 * * 4,5 (m/h/dM/MY/d) UTC""" def test_PeriodicTask_unicode_solar(self): p = self.create_model_solar( @@ -799,7 +796,8 @@ def test_ClockedSchedule_schedule(self): assert s.schedule is not None isdue2, nextcheck2 = s.schedule.is_due(dt2_lastrun) assert isdue2 is True # True means task is due and should run. - assert (nextcheck2 == NEVER_CHECK_TIMEOUT) and (isdue2 is True) + assert (nextcheck2 == NEVER_CHECK_TIMEOUT) + assert (isdue2 is True) @pytest.mark.django_db() diff --git a/tox.ini b/tox.ini index 7608ebb8..0c78c886 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [gh-actions] python = 3.8: py38, apicheck, linkcheck - 3.9: py39, flake8, pydocstyle, cov + 3.9: py39, ruff, cov 3.10: py310 3.11: py311 3.12: py312 @@ -22,10 +22,9 @@ envlist = py311-django{41,42,50} py312-django{41,42,50} pypy3-django{32,41,42,50} - flake8 + ruff apicheck linkcheck - pydocstyle cov [testenv] @@ -42,7 +41,7 @@ deps= django50: -r{toxinidir}/requirements/test-django50.txt linkcheck,apicheck: -r{toxinidir}/requirements/docs.txt - flake8,pydocstyle: -r{toxinidir}/requirements/pkgutils.txt + ruff: -r{toxinidir}/requirements/pkgutils.txt sitepackages = False recreate = False commands = @@ -60,15 +59,9 @@ basepython = python3.8 commands = sphinx-build -W -b linkcheck -d {envtmpdir}/doctrees docs docs/_build/linkcheck -[testenv:flake8] -basepython = python3.9 -commands = - python -m flake8 {toxinidir}/django_celery_beat {toxinidir}/t - -[testenv:pydocstyle] -basepython = python3.9 +[testenv:ruff] commands = - pydocstyle {toxinidir}/django_celery_beat + ruff . [testenv:cov] basepython = python3.9