~netlandish/django-wiki

7bd46f2a1b15519c60ce1028ab094b61d4149cc3 — Benjamin Bach 6 years ago c6bb0ec + d9b5478
Merge pull request #807 from rsalmaso/checks

Move configuration check to django check framework
M src/wiki/apps.py => src/wiki/apps.py +8 -0
@@ 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)

A src/wiki/checks.py => src/wiki/checks.py +71 -0
@@ 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

M src/wiki/compat.py => src/wiki/compat.py +14 -0
@@ 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.')

M src/wiki/models/__init__.py => src/wiki/models/__init__.py +0 -54
@@ 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


A tests/core/test_checks.py => tests/core/test_checks.py +38 -0
@@ 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)