From fa83253056f8ba2e15aacb2733e8b86019d8526f Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 8 Jul 2019 12:37:02 +0100 Subject: [PATCH] Don't trigger axes.W003 for subclasses of AxesBackend The [usage documentation](https://django-axes.readthedocs.io/en/latest/3_usage.html) advises to create subclass of `AxesBackend` to ignore the lack of `request` if necessary. I've done this in a project using `django-oauth-toolkit`, which doesn't pass `request` (though it should as per [this PR](https://github.com/jazzband/django-oauth-toolkit/pull/643)). This meant that the axes.W003 check was being triggered, so I've fixed it to check for subclasses of `AxesBackend` as well as the class itself. --- CHANGES.rst | 5 +++++ axes/checks.py | 12 ++++++++++-- axes/tests/test_checks.py | 14 +++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 381dfde..52b11f4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,11 @@ Changes ======= +Pending +------- + +- Stop axes.W003 check from being triggered for subclasses of ``AxesBackend``. + [adamchainz] 5.0.7 (2019-06-14) ------------------ diff --git a/axes/checks.py b/axes/checks.py index dbca833..98b6324 100644 --- a/axes/checks.py +++ b/axes/checks.py @@ -1,5 +1,7 @@ from django.core.checks import Tags, Warning, register # pylint: disable=redefined-builtin +from django.utils.module_loading import import_string +from axes.backends import AxesBackend from axes.conf import settings @@ -14,7 +16,7 @@ class Messages: "You do not have 'axes.middleware.AxesMiddleware' in your settings.MIDDLEWARE." ) BACKEND_INVALID = ( - "You do not have 'axes.backends.AxesBackend' in your settings.AUTHENTICATION_BACKENDS." + "You do not have 'axes.backends.AxesBackend' or a subclass in your settings.AUTHENTICATION_BACKENDS." ) SETTING_DEPRECATED = ( 'You have a deprecated setting {deprecated_setting} configured in your project settings' @@ -80,7 +82,13 @@ def axes_middleware_check(app_configs, **kwargs): # pylint: disable=unused-argu def axes_backend_check(app_configs, **kwargs): # pylint: disable=unused-argument warnings = [] - if 'axes.backends.AxesBackend' not in settings.AUTHENTICATION_BACKENDS: + found = False + for name in settings.AUTHENTICATION_BACKENDS: + klass = import_string(name) + if issubclass(klass, AxesBackend): + found = True + + if not found: warnings.append(Warning( msg=Messages.BACKEND_INVALID, hint=Hints.BACKEND_INVALID, diff --git a/axes/tests/test_checks.py b/axes/tests/test_checks.py index 2d41e95..9f849e6 100644 --- a/axes/tests/test_checks.py +++ b/axes/tests/test_checks.py @@ -1,6 +1,7 @@ from django.core.checks import run_checks, Warning # pylint: disable=redefined-builtin from django.test import override_settings, modify_settings +from axes.backends import AxesBackend from axes.checks import Messages, Hints, Codes from axes.tests.base import AxesTestCase @@ -58,13 +59,17 @@ class MiddlewareCheckTestCase(AxesTestCase): ]) +class MyBackend(AxesBackend): + pass + + class BackendCheckTestCase(AxesTestCase): @modify_settings( AUTHENTICATION_BACKENDS={ 'remove': ['axes.backends.AxesBackend'] }, ) - def test_cache_check_warnings(self): + def test_backend_missing(self): warnings = run_checks() warning = Warning( msg=Messages.BACKEND_INVALID, @@ -76,6 +81,13 @@ class BackendCheckTestCase(AxesTestCase): warning, ]) + @override_settings( + AUTHENTICATION_BACKENDS=[__name__ + "." + MyBackend.__name__] + ) + def test_custom_backend(self): + warnings = run_checks() + self.assertEqual(warnings, []) + class DeprecatedSettingsTestCase(AxesTestCase): def setUp(self):