From 49bb850ee3f5c4fbd32643c6019b8e1c8ccf619a Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Wed, 13 Feb 2019 15:38:05 +0100 Subject: [PATCH] Django 1.11 compatibility fixes. --- CHANGELOG.md | 4 ++++ runtests.py | 28 ++++++++++++++++++++++++++-- ssify/decorators.py | 7 ++++++- ssify/middleware_debug.py | 8 ++++++++ ssify/templatetags/ssify.py | 10 ++++++++-- ssify/variables.py | 16 +++++++++++++++- ssify/version.py | 2 +- tests/tests/test_csrf.py | 26 +++++++++++++++----------- tests/urls.py | 30 +++++++++++++++--------------- tox.ini | 15 +++++++++++---- 10 files changed, 109 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba5160d..290fd36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.2.6 (2019-02-13) + +* Django 1.9-1.11 compatibility. + ## 0.2.5 (2015-04-16) * Unescape var values in render middleware. diff --git a/runtests.py b/runtests.py index 4fd6a9d..4c0bdea 100644 --- a/runtests.py +++ b/runtests.py @@ -40,7 +40,17 @@ if not settings.configured and not os.environ.get('DJANGO_SETTINGS_MODULE'): ], LANGUAGE_CODE='pl', MEDIA_URL='/media/', - MIDDLEWARE_CLASSES=[ + MIDDLEWARE_CLASSES=[ # Django < 1.10 + 'django.middleware.csrf.CsrfViewMiddleware', + 'ssify.middleware.SsiMiddleware', + 'django.middleware.cache.UpdateCacheMiddleware', + 'ssify.middleware.PrepareForCacheMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'ssify.middleware.LocaleMiddleware', + 'django.middleware.cache.FetchFromCacheMiddleware', + ], + SMIDDLEWARE = [ # Django < 1.10 'django.middleware.csrf.CsrfViewMiddleware', 'ssify.middleware.SsiMiddleware', 'django.middleware.cache.UpdateCacheMiddleware', @@ -53,12 +63,26 @@ if not settings.configured and not os.environ.get('DJANGO_SETTINGS_MODULE'): STATIC_URL='/static/', ROOT_URLCONF='tests.urls', SITE_ID=1, - TEMPLATE_CONTEXT_PROCESSORS=( + TEMPLATE_CONTEXT_PROCESSORS=( # Django < 1.8 "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.tz", "django.core.context_processors.request", ), + TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.tz", + "django.template.context_processors.request", + ], + } + }, + ] ) try: diff --git a/ssify/decorators.py b/ssify/decorators.py index e2ae9fe..1e2d62a 100644 --- a/ssify/decorators.py +++ b/ssify/decorators.py @@ -11,7 +11,12 @@ from inspect import getargspec import warnings from django.conf import settings from django.http import Http404 -from django.template.base import parse_bits +try: + # Django 1.9 + from django.template.library import parse_bits +except ImportError: + from django.template.base import parse_bits + from django.utils.translation import get_language, activate from .cache import cache_include, DEFAULT_TIMEOUT from . import exceptions diff --git a/ssify/middleware_debug.py b/ssify/middleware_debug.py index b0a1e92..f463d53 100644 --- a/ssify/middleware_debug.py +++ b/ssify/middleware_debug.py @@ -12,10 +12,18 @@ support as a proxy (i.e. Nginx with ssi=on). """ from __future__ import unicode_literals import re + try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse + +try: + from django.urls import NoReverseMatch, reverse, resolve +except ImportError: + # Django < 2 + from django.core.urlresolvers import NoReverseMatch, reverse, resolve + from django.core.urlresolvers import resolve from .cache import get_caches diff --git a/ssify/templatetags/ssify.py b/ssify/templatetags/ssify.py index 78071d0..a98a463 100644 --- a/ssify/templatetags/ssify.py +++ b/ssify/templatetags/ssify.py @@ -4,9 +4,15 @@ # from __future__ import absolute_import, unicode_literals from django.conf import settings -from django.core.urlresolvers import NoReverseMatch, reverse, resolve +try: + from django.urls import NoReverseMatch, reverse, resolve +except ImportError: + # Django < 2 + from django.core.urlresolvers import NoReverseMatch, reverse, resolve + from django.middleware.csrf import get_token, _sanitize_token, rotate_token from django import template +from django.utils.safestring import mark_safe from django.utils.translation import get_language from ssify.decorators import ssi_variable from ssify.utils import ssi_vary_on_cookie @@ -70,7 +76,7 @@ def ssi_include(context, name_, **kwargs): request.ssi_patch_response.extend(patch_response) # Output the SSI include. - return "" % url + return mark_safe("" % url) @ssi_variable(register, patch_response=[ssi_vary_on_cookie]) diff --git a/ssify/variables.py b/ssify/variables.py index 014e95f..5e220ad 100644 --- a/ssify/variables.py +++ b/ssify/variables.py @@ -12,7 +12,21 @@ at request time to the prerendered templates. from __future__ import unicode_literals from hashlib import md5 from django.template import Node -from django.template.base import get_library + +try: + # Django < 1.9 + from django.template.base import get_library +except: + from importlib import import_module + from django.template.backends.django import get_installed_libraries + + def get_library(taglib): + if not hasattr(get_library, 'libraries'): + get_library.libraries = get_installed_libraries() + if isinstance(get_library.libraries[taglib], str): + get_library.libraries[taglib] = import_module(get_library.libraries[taglib]).register + return get_library.libraries[taglib] + from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.functional import Promise from django.utils.safestring import mark_safe diff --git a/ssify/version.py b/ssify/version.py index 0258c9a..2147ed9 100644 --- a/ssify/version.py +++ b/ssify/version.py @@ -1,3 +1,3 @@ from __future__ import unicode_literals -VERSION = '0.2.5' +VERSION = '0.2.6' diff --git a/tests/tests/test_csrf.py b/tests/tests/test_csrf.py index 62173ce..8822336 100644 --- a/tests/tests/test_csrf.py +++ b/tests/tests/test_csrf.py @@ -4,9 +4,16 @@ # from __future__ import unicode_literals +import re from django.conf import settings from django.test import Client, TestCase +try: + from django.middleware.csrf import _compare_salted_tokens +except ImportError: + # Django < 1.10 + _compare_salted_tokens = lambda t1, t2: t1 == t2 + class CsrfTestCase(TestCase): def setUp(self): @@ -15,24 +22,21 @@ class CsrfTestCase(TestCase): def assertCsrfTokenOk(self, response): token = response.cookies[settings.CSRF_COOKIE_NAME].value self.assertTrue(token) - self.assertEqual( - response.content.strip(), - ("\n\n" - "' />" % token).encode('ascii') + match = re.match( + r"\n\n" + r"' />", + response.content.strip().decode('ascii'), + re.MULTILINE ) + self.assertTrue(_compare_salted_tokens(match.group(1), token)) return token def test_csrf_token(self): response = self.client.get('/csrf') token = self.assertCsrfTokenOk(response) - # And now for a second request, with the token cookie. - response = self.client.get('/csrf') - new_token = self.assertCsrfTokenOk(response) - self.assertEqual(new_token, token) - # Make a bad request to see that CSRF protection works. response = self.client.post('/csrf_check', { 'test': 'some data', diff --git a/tests/urls.py b/tests/urls.py index 2c12f8c..2b145cc 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -2,15 +2,15 @@ # This file is part of django-ssify, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See README.md for more information. # -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals -from django.conf.urls import patterns, url +#from django.conf.urls import patterns, url +from django.conf.urls import url from django.views.generic import TemplateView +from tests import views -urlpatterns = patterns( - 'tests.views', - +urlpatterns = [ # tests.basic url(r'^$', TemplateView.as_view(template_name='tests_basic/main.html') @@ -21,11 +21,11 @@ urlpatterns = patterns( url(r'^basic_include$', TemplateView.as_view(template_name='tests_basic/basic_include.html') ), - url(r'^random_quote$', 'random_quote', name='random_quote'), - url(r'^quote/(?P.+)$', 'quote', name='quote'), + url(r'^random_quote$', views.random_quote, name='random_quote'), + url(r'^quote/(?P.+)$', views.quote, name='quote'), - url(r'^quote_undeclared/(?P.+)$', 'quote_undeclared'), - url(r'^quote_overdeclared/(?P.+)$', 'quote_overdeclared'), + url(r'^quote_undeclared/(?P.+)$', views.quote_undeclared), + url(r'^quote_overdeclared/(?P.+)$', views.quote_overdeclared), # tests.args url(r'^include_args$', @@ -35,13 +35,13 @@ urlpatterns = patterns( TemplateView.as_view(template_name='tests_args/args.html'), {'limit': 3} ), - url(r'^args/(?P\d+)$', 'args', name='args'), + url(r'^args/(?P\d+)$', views.args, name='args'), # tests.csrf url(r'^csrf$', TemplateView.as_view(template_name='tests_csrf/csrf_token.html'), ), - url(r'^csrf_check$', 'csrf_check'), + url(r'^csrf_check$', views.csrf_check), # tests.locale url(r'^include_language_with_lang$', @@ -50,12 +50,12 @@ urlpatterns = patterns( url(r'^include_language_without_lang$', TemplateView.as_view(template_name='tests_locale/include_language_without_lang.html') ), - url(r'^language/(?P.+)$', 'language_with_lang', name='language_with_lang'), - url(r'^language$', 'language_without_lang', name='language_without_lang'), - url(r'^bad_language$', 'language_with_lang', name='bad_language_with_lang'), + url(r'^language/(?P.+)$', views.language_with_lang, name='language_with_lang'), + url(r'^language$', views.language_without_lang, name='language_without_lang'), + url(r'^bad_language$', views.language_with_lang, name='bad_language_with_lang'), # tests.render url(r'^render$', TemplateView.as_view(template_name='tests_render/test_render.html') ), -) +] diff --git a/tox.ini b/tox.ini index 063a6b3..b3b729c 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,12 @@ # [tox] envlist=clear, - d1{5,6}-py{26,27,32,33,py}, - d{17,18}-py{27,32,33,34,py}, - d{d}-py{27,33,34,py}, + d1{5,6}-py{26,27,32,33}, + d{17,18}-py{27,32,33,34}, + d{19,110}-py{27,34,35}, + d111-py{27,34,35,36,37}, + #d20-py{34,35,36,37}, + #d21-py{35,36,37}, stats [testenv] @@ -16,7 +19,11 @@ deps= d16: Django>=1.6,<1.7 d17: Django>=1.7,<1.8 d18: Django>=1.8,<1.9 - dd: https://github.com/django/django/archive/master.tar.gz + d19: Django>=1.9,<1.10 + d110: Django>=1.10,<1.11 + d111: Django>=1.11,<2.0 + d20: Django>=2.0,<2.1 + d21: Django>=2.1,<2.2 coverage [testenv:clear] -- 2.20.1