From d9b54783b2df17b3d42a4b0dde871b8446e58b8c Mon Sep 17 00:00:00 2001 From: Raffaele Salmaso Date: Mon, 19 Feb 2018 19:32:44 +0100 Subject: [PATCH] Move configuration check to django check framework --- src/wiki/apps.py | 8 +++++ src/wiki/checks.py | 71 +++++++++++++++++++++++++++++++++++++ src/wiki/compat.py | 14 ++++++++ src/wiki/models/__init__.py | 54 ---------------------------- tests/core/test_checks.py | 38 ++++++++++++++++++++ 5 files changed, 131 insertions(+), 54 deletions(-) create mode 100644 src/wiki/checks.py create mode 100644 tests/core/test_checks.py diff --git a/src/wiki/apps.py b/src/wiki/apps.py index 8f2b17cf..aba8e911 100644 --- a/src/wiki/apps.py +++ b/src/wiki/apps.py @@ -1,7 +1,15 @@ from django.apps import AppConfig +from django.core.checks import register from django.utils.translation import gettext_lazy as _ +from . import checks + class WikiConfig(AppConfig): name = "wiki" verbose_name = _("Wiki") + + def ready(self): + register(checks.check_for_required_installed_apps, checks.Tags.required_installed_apps) + register(checks.check_for_obsolete_installed_apps, checks.Tags.obsolete_installed_apps) + register(checks.check_for_context_processors, checks.Tags.context_processors) diff --git a/src/wiki/checks.py b/src/wiki/checks.py new file mode 100644 index 00000000..7c745cea --- /dev/null +++ b/src/wiki/checks.py @@ -0,0 +1,71 @@ +from django.apps import apps +from django.core.checks import Error +from wiki.compat import get_default_engine + + +class Tags: + required_installed_apps = "required_installed_apps" + obsolete_installed_apps = "obsolete_installed_apps" + context_processors = "context_processors" + + +REQUIRED_INSTALLED_APPS = ( + # module name, package name, error code + ('mptt', 'django-mptt', 'E001'), + ('sekizai', 'django-sekizai', 'E002'), + ('django.contrib.humanize', 'django.contrib.humanize', 'E003'), + ('django.contrib.contenttypes', 'django.contrib.contenttypes', 'E004'), + ('django.contrib.sites', 'django.contrib.sites', 'E005'), +) + +OBSOLETE_INSTALLED_APPS = ( + # obsolete module name, new module name, error code + ('django_notify', 'django_nyt', 'E006'), +) + +REQUIRED_CONTEXT_PROCESSORS = ( + # context processor name, error code + ('django.contrib.auth.context_processors.auth', 'E007'), + ('django.template.context_processors.request', 'E008'), + ('sekizai.context_processors.sekizai', 'E009'), +) + + +def check_for_required_installed_apps(app_configs, **kwargs): + errors = [] + for app in REQUIRED_INSTALLED_APPS: + if not apps.is_installed(app[0]): + errors.append( + Error( + 'needs %s in INSTALLED_APPS' % app[1], + id='wiki.%s' % app[2], + ) + ) + return errors + + +def check_for_obsolete_installed_apps(app_configs, **kwargs): + errors = [] + for app in OBSOLETE_INSTALLED_APPS: + if apps.is_installed(app[0]): + errors.append( + Error( + 'You need to change from %s to %s in INSTALLED_APPS and your urlconfig.' % (app[0], app[1]), + id='wiki.%s' % app[2], + ) + ) + return errors + + +def check_for_context_processors(app_configs, **kwargs): + errors = [] + context_processors = get_default_engine().context_processors + for context_processor in REQUIRED_CONTEXT_PROCESSORS: + if context_processor[0] not in context_processors: + errors.append( + Error( + "needs %s in TEMPLATE['OPTIONS']['context_processors']" % context_processor[0], + id='wiki.%s' % context_processor[1], + ) + ) + return errors diff --git a/src/wiki/compat.py b/src/wiki/compat.py index 81042f2d..2bbb746d 100644 --- a/src/wiki/compat.py +++ b/src/wiki/compat.py @@ -10,6 +10,7 @@ except ImportError: __all__ = [ 'BuildAttrsCompat', + 'get_default_engine', 'include', 'url' ] @@ -28,3 +29,16 @@ class BuildAttrsCompat: if kwargs is not None: attrs.update(kwargs) return attrs + + +def get_default_engine(): + """ + Django >= 2.1 Engine.get_default() behaviour + """ + from django.core.exceptions import ImproperlyConfigured + from django.template import engines + from django.template.backends.django import DjangoTemplates + for engine in engines.all(): + if isinstance(engine, DjangoTemplates): + return engine.engine + raise ImproperlyConfigured('No DjangoTemplates backend is configured.') diff --git a/src/wiki/models/__init__.py b/src/wiki/models/__init__.py index a9357924..e448ee27 100644 --- a/src/wiki/models/__init__.py +++ b/src/wiki/models/__init__.py @@ -1,6 +1,3 @@ -from django.apps import apps -from django.conf import settings as django_settings -from django.core.exceptions import ImproperlyConfigured from django.urls import base from django import urls from django import shortcuts @@ -11,57 +8,6 @@ from .pluginbase import * # noqa from .urlpath import * # noqa from django.utils.functional import lazy -# TODO: Should the below stuff be executed a more logical place? -# Follow Django's default_settings.py / settings.py pattern and put these -# in d_s.py? That might be confusing, though. - -###################### -# Configuration stuff -###################### - -if not apps.is_installed('mptt'): - raise ImproperlyConfigured('django-wiki: needs mptt in INSTALLED_APPS') - -if not apps.is_installed('sekizai'): - raise ImproperlyConfigured('django-wiki: needs sekizai in INSTALLED_APPS') - -# if not apps.is_installed('django_nyt'): -# raise ImproperlyConfigured('django-wiki: needs django_nyt in INSTALLED_APPS') - -if not apps.is_installed('django.contrib.humanize'): - raise ImproperlyConfigured( - 'django-wiki: needs django.contrib.humanize in INSTALLED_APPS') - -if not apps.is_installed('django.contrib.contenttypes'): - raise ImproperlyConfigured( - 'django-wiki: needs django.contrib.contenttypes in INSTALLED_APPS') - -if not apps.is_installed('django.contrib.sites'): - raise ImproperlyConfigured( - 'django-wiki: needs django.contrib.sites in INSTALLED_APPS') - -# Need to handle Django 1.8 'TEMPLATES', recognizing that users may still be -# using 1.7 conventions/settings with 1.8. -TEMPLATE_CONTEXT_PROCESSORS = getattr(django_settings, 'TEMPLATE_CONTEXT_PROCESSORS', []) -if hasattr(django_settings, 'TEMPLATES'): - # Django 1.8 compat - backends = [b for b in django_settings.TEMPLATES if b.get('BACKEND', '') == 'django.template.backends.django.DjangoTemplates'] - if len(backends) == 1: - TEMPLATE_CONTEXT_PROCESSORS = backends[0].get('OPTIONS', {}).get('context_processors', []) - -if 'django.contrib.auth.context_processors.auth' not in TEMPLATE_CONTEXT_PROCESSORS: - raise ImproperlyConfigured( - 'django-wiki: needs django.contrib.auth.context_processors.auth in TEMPLATE_CONTEXT_PROCESSORS') - -if not any(s in TEMPLATE_CONTEXT_PROCESSORS for s in ['django.core.context_processors.request', - 'django.template.context_processors.request']): - raise ImproperlyConfigured( - 'django-wiki: needs django.core.context_processors.request or django.template.context_processors.request in TEMPLATE_CONTEXT_PROCESSORS') - -if apps.is_installed('django_notify'): - raise ImproperlyConfigured( - 'django-wiki: You need to change from django_notify to django_nyt in INSTALLED_APPS and your urlconfig.') - original_django_reverse = urls.reverse diff --git a/tests/core/test_checks.py b/tests/core/test_checks.py new file mode 100644 index 00000000..449eea30 --- /dev/null +++ b/tests/core/test_checks.py @@ -0,0 +1,38 @@ +import copy + +from django.conf import settings +from django.test import TestCase +from django.core.checks import Error, registry +from wiki.checks import REQUIRED_CONTEXT_PROCESSORS, REQUIRED_INSTALLED_APPS, OBSOLETE_INSTALLED_APPS, Tags + + +class CheckTests(TestCase): + def test_required_installed_apps(self): + for app in REQUIRED_INSTALLED_APPS: + with self.modify_settings(INSTALLED_APPS={'remove': [app[0]]}): + errors = registry.run_checks(tags=[Tags.required_installed_apps]) + expected_errors = [ + Error( + 'needs %s in INSTALLED_APPS' % app[1], + id='wiki.%s' % app[2], + ) + ] + self.assertEqual(errors, expected_errors) + + def test_required_context_processors(self): + for context_processor in REQUIRED_CONTEXT_PROCESSORS: + TEMPLATES = copy.deepcopy(settings.TEMPLATES) + TEMPLATES[0]['OPTIONS']['context_processors'] = [ + cp + for cp in TEMPLATES[0]['OPTIONS']['context_processors'] + if cp != context_processor[0] + ] + with self.settings(TEMPLATES=TEMPLATES): + errors = registry.run_checks(tags=[Tags.context_processors]) + expected_errors = [ + Error( + "needs %s in TEMPLATE['OPTIONS']['context_processors']" % context_processor[0], + id='wiki.%s' % context_processor[1], + ) + ] + self.assertEqual(errors, expected_errors) -- 2.45.2