From 4c9cae36dcee2fbf4b80e62e57c25e027f228c29 Mon Sep 17 00:00:00 2001 From: Martin Koistinen Date: Sat, 7 Jan 2017 16:55:15 -0500 Subject: [PATCH] Adds Django 1.10 compatibility while maintaining Django 1.7 compatibility --- password_policies/middleware.py | 20 ++++++- password_policies/tests/test_settings.py | 75 ++++++++++++++++++------ password_policies/tests/test_views.py | 3 +- password_policies/tests/urls.py | 19 ++++-- password_policies/urls.py | 53 ++++++++++------- password_policies/views.py | 8 ++- requirements.txt | 2 +- tox.ini | 3 + 8 files changed, 131 insertions(+), 52 deletions(-) diff --git a/password_policies/middleware.py b/password_policies/middleware.py index 2f49db4..74a16a3 100644 --- a/password_policies/middleware.py +++ b/password_policies/middleware.py @@ -4,13 +4,17 @@ Resolver404 from django.http import HttpResponseRedirect from django.utils import timezone +try: + from django.utils.deprecation import MiddlewareMixin +except ImportError: + MiddlewareMixin = object from password_policies.conf import settings from password_policies.models import PasswordChangeRequired, PasswordHistory from password_policies.utils import PasswordCheck -class PasswordChangeMiddleware(object): +class PasswordChangeMiddleware(MiddlewareMixin): """ A middleware to force a password change. @@ -33,7 +37,19 @@ class PasswordChangeMiddleware(object): 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'password_policies.middleware.PasswordChangeMiddleware', - # ... other middlewares ... + # ... other middleware ... + ) + + +or ``MIDDLEWARE`` if using Django 1.10 or higher: + + MIDDLEWARE = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'password_policies.middleware.PasswordChangeMiddleware', + # ... other middleware ... ) .. note:: diff --git a/password_policies/tests/test_settings.py b/password_policies/tests/test_settings.py index c29df70..a332a87 100644 --- a/password_policies/tests/test_settings.py +++ b/password_policies/tests/test_settings.py @@ -1,4 +1,8 @@ import os +from distutils.version import LooseVersion +from django import get_version + +django_version = get_version() DEBUG = False @@ -21,7 +25,7 @@ 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', - "password_policies", + 'password_policies', ] DATABASES = { @@ -39,25 +43,58 @@ SITE_ID = 1 -TEMPLATE_DIRS = ( - os.path.join(os.path.dirname(__file__), 'templates'), -) +# This is to maintain compatibility with Django 1.7 +if LooseVersion(django_version) < LooseVersion('1.8.0'): + TEMPLATE_DIRS = ( + os.path.join(os.path.dirname(__file__), 'templates'), + ) + TEMPLATE_CONTEXT_PROCESSORS = ( + 'django.contrib.auth.context_processors.auth', + 'django.core.context_processors.debug', + 'django.core.context_processors.i18n', + 'django.contrib.messages.context_processors.messages', + 'password_policies.context_processors.password_status', + ) -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'password_policies.middleware.PasswordChangeMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', -) +else: + TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(os.path.dirname(__file__), 'templates'), ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.contrib.messages.context_processors.messages', + 'password_policies.context_processors.password_status', + ], + }, + }, + ] + +print(os.path.join(os.path.dirname(__file__), 'templates')) + +# This is to maintain compatibility with Django < 1.10 +if LooseVersion(django_version) < LooseVersion('1.10.0'): + MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'password_policies.middleware.PasswordChangeMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + ) +else: + MIDDLEWARE = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'password_policies.middleware.PasswordChangeMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + ) -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.contrib.messages.context_processors.messages', - 'password_policies.context_processors.password_status', -) SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' diff --git a/password_policies/tests/test_views.py b/password_policies/tests/test_views.py index 338297e..0d4a6a9 100644 --- a/password_policies/tests/test_views.py +++ b/password_policies/tests/test_views.py @@ -60,7 +60,6 @@ def test_password_change_success(self): response = self.client.post(reverse('password_change'), data=data) self.assertEqual(PasswordHistory.objects.count(), 1) obj = PasswordHistory.objects.get() - self.assertRedirects(response, - 'http://testserver%s' % reverse('password_change_done')) + self.assertTrue(response.url.endswith(reverse('password_change_done'))) obj.delete() self.client.logout() diff --git a/password_policies/tests/urls.py b/password_policies/tests/urls.py index c0ac3d2..1d03e5a 100644 --- a/password_policies/tests/urls.py +++ b/password_policies/tests/urls.py @@ -1,9 +1,18 @@ -from django.conf.urls import include, patterns, url + + +from django.conf.urls import include, url +try: + from django.conf.urls import patterns +except ImportError: + patterns = False from password_policies.tests.views import TestHomeView -urlpatterns = patterns('', - url(r'^password/', include('password_policies.urls')), - url(r'^$', TestHomeView.as_view(), name='home'), - ) +urlpatterns = [ + url(r'^password/', include('password_policies.urls')), + url(r'^$', TestHomeView.as_view(), name='home'), +] + +if patterns: + urlpatterns = patterns('', *urlpatterns) # noqa diff --git a/password_policies/urls.py b/password_policies/urls.py index a2e5c50..f43f154 100644 --- a/password_policies/urls.py +++ b/password_policies/urls.py @@ -1,4 +1,11 @@ -from django.conf.urls import patterns, url +from django.conf.urls import url + +try: + # patterns was deprecated in Django 1.8 + from django.conf.urls import patterns +except ImportError: + # patterns is unavailable in Django 1.10+ + patterns = False from password_policies.views import PasswordChangeFormView from password_policies.views import PasswordChangeDoneView @@ -8,23 +15,27 @@ from password_policies.views import PasswordResetDoneView -urlpatterns = patterns('', - url(r'^change/done/$', - PasswordChangeDoneView.as_view(), - name="password_change_done"), - url(r'^change/$', - PasswordChangeFormView.as_view(), - name="password_change"), - url(r'^reset/$', - PasswordResetFormView.as_view(), - name="password_reset"), - url(r'^reset/complete/$', - PasswordResetCompleteView.as_view(), - name="password_reset_complete"), - url(r'^reset/confirm/([0-9A-Za-z_\-]+)/([0-9A-Za-z]{1,13})/([0-9A-Za-z-=_]{1,32})/$', - PasswordResetConfirmView.as_view(), - name="password_reset_confirm"), - url(r'^reset/done/$', - PasswordResetDoneView.as_view(), - name="password_reset_done"), - ) +urlpatterns = [ + url(r'^change/done/$', + PasswordChangeDoneView.as_view(), + name="password_change_done"), + url(r'^change/$', + PasswordChangeFormView.as_view(), + name="password_change"), + url(r'^reset/$', + PasswordResetFormView.as_view(), + name="password_reset"), + url(r'^reset/complete/$', + PasswordResetCompleteView.as_view(), + name="password_reset_complete"), + url(r'^reset/confirm/([0-9A-Za-z_\-]+)/([0-9A-Za-z]{1,13})/([0-9A-Za-z-=_]{1,32})/$', + PasswordResetConfirmView.as_view(), + name="password_reset_confirm"), + url(r'^reset/done/$', + PasswordResetDoneView.as_view(), + name="password_reset_done"), +] + +if patterns: + # Django 1.7 + urlpatterns = patterns('', *urlpatterns) diff --git a/password_policies/views.py b/password_policies/views.py index 8fb297e..db43146 100644 --- a/password_policies/views.py +++ b/password_policies/views.py @@ -78,7 +78,9 @@ def form_valid(self, form): form.save() return super(PasswordChangeFormView, self).form_valid(form) - def get_form(self, form_class): + def get_form(self, form_class=None): + if form_class is None: + form_class = self.get_form_class() return form_class(self.request.user, **self.get_form_kwargs()) def get_success_url(self): @@ -184,7 +186,9 @@ def get_context_data(self, **kwargs): kwargs['validlink'] = self.validlink return super(PasswordResetConfirmView, self).get_context_data(**kwargs) - def get_form(self, form_class): + def get_form(self, form_class=None): + if form_class is None: + form_class = self.get_form_class() return form_class(self.user, **self.get_form_kwargs()) def get_success_url(self): diff --git a/requirements.txt b/requirements.txt index 0b8967c..34bfac6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -django>=1.7,<1.10 +django>=1.7,<1.11 django-easysettings>=1.0 diff --git a/tox.ini b/tox.ini index f682635..a561b1e 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,7 @@ envlist = py27-django17, py27-django18, py27-django19, + py27-django110, py33-django17, py33-django18, py34-django17, @@ -10,9 +11,11 @@ envlist = py34-django19, py35-django18, py35-django19, + py35-django110, [testenv] deps = django17: Django >= 1.7, < 1.8 django18: Django >= 1.8, < 1.9 django19: Django >= 1.9, < 1.10 + django110: Django >= 1.10, < 1.11 commands = python setup.py test