From 6ccd45234b1c2be78888365f37d738215abc78c9 Mon Sep 17 00:00:00 2001 From: Johannes Maron Date: Sun, 11 Oct 2026 21:49:22 +0200 Subject: [PATCH 1/4] Update the Ruff configuration - Use the shared extend-select rule set, including D213 and S - Align the ignore list with the other projects --- pyproject.toml | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c2c12ce..4b60226 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,18 +78,27 @@ name = "crontask" [tool.ruff] src = [ "crontask", "tests" ] [tool.ruff.lint] -select = [ - "B", # flake8-bugbear - "C", # flake8-comprehensions - "D", # pydocstyle - "E", # pycodestyle errors - "F", # pyflakes - "I", # isort - "S", # flake8-bandit - "UP", # pyupgrade - "W", # pycodestyle warnings +extend-select = [ + "C90", + "D", + "D213", + "DJ", + "E", + "G", + "N", + "PERF", + "PT", + "PTH", + "RET", + "S", + "SIM", + "SLOT", + "T20", + "TRY", + "UP", + "W", ] -ignore = [ "B904", "D1", "E501", "S101" ] +ignore = [ "D1", "D203", "D212", "E501", "RUF01" ] isort.combine-as-imports = true isort.force-wrap-aliases = true isort.section-order = [ "future", "standard-library", "third-party", "first-party", "local-folder" ] From d8215db968e4b87705dc2e15dfd6ccdd9c64559d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 11 Oct 2026 19:57:07 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- crontask/__init__.py | 2 +- crontask/utils.py | 2 +- tests/test_commands.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crontask/__init__.py b/crontask/__init__.py index 45a64a0..7d58fda 100644 --- a/crontask/__init__.py +++ b/crontask/__init__.py @@ -13,7 +13,7 @@ from . import _version from .contrib import sentry -__all__ = ["cron", "scheduler", "VERSION", "__version__"] +__all__ = ["VERSION", "__version__", "cron", "scheduler"] __version__ = _version.version VERSION = _version.version_tuple diff --git a/crontask/utils.py b/crontask/utils.py index c7592b2..ad3f8a4 100644 --- a/crontask/utils.py +++ b/crontask/utils.py @@ -16,7 +16,7 @@ def extend(self, additional_time=None, replace_ttl=False): if redis_url := get_settings().REDIS_URL: import redis - from redis.exceptions import LockError, LockNotOwnedError # noqa + from redis.exceptions import LockError, LockNotOwnedError redis_client = redis.Redis.from_url(redis_url) lock = redis_client.lock( diff --git a/tests/test_commands.py b/tests/test_commands.py index e1c9636..a778aec 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -17,7 +17,7 @@ def test_kill_softly(): class Testcrontask: - @pytest.fixture() + @pytest.fixture def patch_launch(self, monkeypatch): monkeypatch.setattr( "crontask.management.commands.crontask.Command.launch_scheduler", From 722f67939ea664d6f561a12c5a4f6d86983bfa1f Mon Sep 17 00:00:00 2001 From: Johannes Maron Date: Mon, 12 Oct 2026 00:20:05 +0200 Subject: [PATCH 3/4] Fix the remaining Ruff violations - Scope the new rules to tests with per-file-ignores - Modernise the code the new rules flag, without changing behaviour --- crontask/__init__.py | 6 ++++-- crontask/management/commands/crontask.py | 3 ++- pyproject.toml | 1 + tests/contrib/test_sentry.py | 6 +++--- tests/test_commands.py | 22 ++++++++++++++-------- tests/test_tasks.py | 2 +- tests/testapp/settings.py | 2 +- 7 files changed, 26 insertions(+), 16 deletions(-) diff --git a/crontask/__init__.py b/crontask/__init__.py index 7d58fda..5905c65 100644 --- a/crontask/__init__.py +++ b/crontask/__init__.py @@ -62,9 +62,11 @@ def decorator(task: Task) -> Task: # so in Berlin Monday is 0, and Sunday is 6. We use literals to avoid # confusion. Literals are also more readable and crontab conform. if any(i.isdigit() for i in day_schedule): - raise ValueError( - "Please use a literal day of week (Mon, Tue, Wed, Thu, Fri, Sat, Sun) or *" + msg = ( + "Please use a literal day of week " + "(Mon, Tue, Wed, Thu, Fri, Sat, Sun) or *" ) + raise ValueError(msg) trigger = CronTrigger.from_crontab( schedule, timezone=timezone.get_default_timezone(), diff --git a/crontask/management/commands/crontask.py b/crontask/management/commands/crontask.py index 617894e..c791cb0 100644 --- a/crontask/management/commands/crontask.py +++ b/crontask/management/commands/crontask.py @@ -20,7 +20,8 @@ def kill_softly(signum, frame): """Raise a KeyboardInterrupt to stop the scheduler and release the lock.""" signame = signal.Signals(signum).name - raise KeyboardInterrupt(f"Received {signame} ({signum}), shutting down…") + msg = f"Received {signame} ({signum}), shutting down…" + raise KeyboardInterrupt(msg) class Command(BaseCommand): diff --git a/pyproject.toml b/pyproject.toml index 4b60226..cdea914 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ extend-select = [ "W", ] ignore = [ "D1", "D203", "D212", "E501", "RUF01" ] +per-file-ignores."tests/**" = [ "DJ006", "DJ007", "DJ008", "PLR2004", "S101", "S105", "S106", "S311", "S603", "S607" ] isort.combine-as-imports = true isort.force-wrap-aliases = true isort.section-order = [ "future", "standard-library", "third-party", "first-party", "local-folder" ] diff --git a/tests/contrib/test_sentry.py b/tests/contrib/test_sentry.py index e0387d4..610203e 100644 --- a/tests/contrib/test_sentry.py +++ b/tests/contrib/test_sentry.py @@ -32,7 +32,7 @@ def test_monitor_config__cron_trigger__with_day_of_week(): @pytest.mark.parametrize( - "seconds,expected", + ("seconds", "expected"), [ (60, {"type": "interval", "value": 1, "unit": "minute"}), (300, {"type": "interval", "value": 5, "unit": "minute"}), @@ -65,7 +65,7 @@ def test_monitor_config__unsupported_interval_trigger(seconds): @pytest.mark.parametrize( - "kwargs,expected", + ("kwargs", "expected"), [ ({"years": 1}, {"type": "interval", "value": 1, "unit": "year"}), ({"months": 2}, {"type": "interval", "value": 2, "unit": "month"}), @@ -87,7 +87,7 @@ def test_monitor_config__calendar_interval_trigger(kwargs, expected): CalendarIntervalTrigger( months=1, days=1, timezone=timezone.get_default_timezone() ), - DateTrigger(run_date=datetime.datetime(2021, 1, 1)), + DateTrigger(run_date=datetime.datetime(2021, 1, 1, tzinfo=datetime.UTC)), ], ) def test_monitor_config__unsupported(trigger): diff --git a/tests/test_commands.py b/tests/test_commands.py index a778aec..75be7fb 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -94,10 +94,12 @@ def test_load_tasks__optional_tasks(self, patch_launch, monkeypatch): def test_locked(self): """A lock was already acquired by another process.""" pytest.importorskip("redis", reason="redis is not installed") - with utils.redis_client.lock("crontask-lock", blocking_timeout=0): - with io.StringIO() as stderr: - call_command("crontask", stderr=stderr) - assert "Another scheduler is already running." in stderr.getvalue() + with ( + utils.redis_client.lock("crontask-lock", blocking_timeout=0), + io.StringIO() as stderr, + ): + call_command("crontask", stderr=stderr) + assert "Another scheduler is already running." in stderr.getvalue() def test_locked_no_refresh(self, monkeypatch): """A lock was acquired, but it was not refreshed.""" @@ -143,8 +145,10 @@ def mock_signal(signum, handler): signal_calls.append(signum) return original_signal(signum, handler) - with patch("signal.signal", side_effect=mock_signal): - with io.StringIO() as stdout: + with ( + patch("signal.signal", side_effect=mock_signal), + io.StringIO() as stdout, + ): call_command("crontask", stdout=stdout) assert signal.SIGHUP in signal_calls assert signal.SIGTERM in signal_calls @@ -164,8 +168,10 @@ def mock_signal(signum, handler): signal_calls.append(signum) return original_signal(signum, handler) - with patch("signal.signal", side_effect=mock_signal): - with io.StringIO() as stdout: + with ( + patch("signal.signal", side_effect=mock_signal), + io.StringIO() as stdout, + ): call_command("crontask", stdout=stdout) assert signal.SIGTERM in signal_calls assert signal.SIGINT in signal_calls diff --git a/tests/test_tasks.py b/tests/test_tasks.py index b65b3d9..c73dd09 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -92,7 +92,7 @@ def test_cron__trigger_attribute(): ) def test_cron__error(schedule): assert not scheduler.remove_all_jobs() - with pytest.raises(ValueError) as e: + with pytest.raises(ValueError, match="Please use a literal day of week") as e: cron(schedule)(tasks.heartbeat) assert ( "Please use a literal day of week (Mon, Tue, Wed, Thu, Fri, Sat, Sun) or *" diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 6716342..d77eb05 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -21,7 +21,7 @@ # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure--@w!1qsi6azo&=a**ia3b43k^@q9aor_rqyu=1i5yd-zinpo)0" # noqa: S105 +SECRET_KEY = "django-insecure--@w!1qsi6azo&=a**ia3b43k^@q9aor_rqyu=1i5yd-zinpo)0" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True From a63a59d1da48cdd6c90bb1bbc41ae548709bbfef Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 11 Oct 2026 22:20:28 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_commands.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index 75be7fb..f5436ae 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -149,10 +149,10 @@ def mock_signal(signum, handler): patch("signal.signal", side_effect=mock_signal), io.StringIO() as stdout, ): - call_command("crontask", stdout=stdout) - assert signal.SIGHUP in signal_calls - assert signal.SIGTERM in signal_calls - assert signal.SIGINT in signal_calls + call_command("crontask", stdout=stdout) + assert signal.SIGHUP in signal_calls + assert signal.SIGTERM in signal_calls + assert signal.SIGINT in signal_calls @pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific test") def test_launch_scheduler_windows_signals(self, monkeypatch): @@ -172,11 +172,11 @@ def mock_signal(signum, handler): patch("signal.signal", side_effect=mock_signal), io.StringIO() as stdout, ): - call_command("crontask", stdout=stdout) - assert signal.SIGTERM in signal_calls - assert signal.SIGINT in signal_calls - if hasattr(signal, "SIGBREAK"): - assert signal.SIGBREAK in signal_calls - assert not any( - sig == getattr(signal, "SIGHUP", None) for sig in signal_calls - ) + call_command("crontask", stdout=stdout) + assert signal.SIGTERM in signal_calls + assert signal.SIGINT in signal_calls + if hasattr(signal, "SIGBREAK"): + assert signal.SIGBREAK in signal_calls + assert not any( + sig == getattr(signal, "SIGHUP", None) for sig in signal_calls + )