From a98318f5bf1b9515aa0b076e39b1048c887262ed Mon Sep 17 00:00:00 2001 From: Alexey Kotlyarov Date: Thu, 20 Apr 2017 21:33:28 +1000 Subject: [PATCH] Updates for Django 1.10 and 1.11 (#73) --- .travis.yml | 28 ++++++-- README.rst | 18 +++-- embed_video/tests/django_settings.py | 20 +++++- .../templatetags/tests_embed_video_tags.py | 71 ++++++++++++++++--- embed_video/tests/tests_admin.py | 14 ++-- example_project/README.rst | 4 ++ example_project/example_project/settings.py | 54 ++++++++++---- example_project/example_project/urls.py | 6 +- example_project/posts/urls.py | 6 +- 9 files changed, 171 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index acfb872..e6e2844 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,30 @@ language: python python: - "2.7" - "3.4" + - "3.6" cache: pip env: - - DJANGO_VERSION=1.5.2 - - DJANGO_VERSION=1.6.5 - - DJANGO_VERSION=1.7.0 - - DJANGO_VERSION=1.8.0 - - DJANGO_VERSION=1.8.6 - - DJANGO_VERSION=1.9.4 + - DJANGO_VERSION=1.5.* + - DJANGO_VERSION=1.6.* + - DJANGO_VERSION=1.7.* + - DJANGO_VERSION=1.8.* + - DJANGO_VERSION=1.9.* + - DJANGO_VERSION=1.10.* + - DJANGO_VERSION=1.11.* +matrix: + exclude: + - python: '3.6' + env: DJANGO_VERSION=1.5.* + - python: '3.6' + env: DJANGO_VERSION=1.6.* + - python: '3.6' + env: DJANGO_VERSION=1.7.* + - python: '3.6' + env: DJANGO_VERSION=1.8.* + - python: '3.6' + env: DJANGO_VERSION=1.9.* + - python: '3.6' + env: DJANGO_VERSION=1.10.* install: - pip install -q Django==$DJANGO_VERSION - pip install coveralls diff --git a/README.rst b/README.rst index d5c763d..5c56e54 100644 --- a/README.rst +++ b/README.rst @@ -37,14 +37,22 @@ Quick start #. Add ``embed_video`` to ``INSTALLED_APPS`` in your Django settings. #. If you want to detect HTTP/S in template tags, you have to set ``request`` - context processor in ``settings.TEMPLATE_CONTEXT_PROCESSORS``: + context processor in ``settings.TEMPLATES``: :: - TEMPLATE_CONTEXT_PROCESSORS = ( - ... - 'django.core.context_processors.request', - ) + TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + # ... + 'OPTIONS': { + 'context_processors': [ + # ... + 'django.template.context_processors.request', + ], + }, + }, + ] #. Usage of template tags: diff --git a/embed_video/tests/django_settings.py b/embed_video/tests/django_settings.py index a1c8acf..3a394f2 100644 --- a/embed_video/tests/django_settings.py +++ b/embed_video/tests/django_settings.py @@ -1,13 +1,29 @@ import os -from django.conf.global_settings import * - DEBUG = True SECRET_KEY = 'testing_key123' STATIC_ROOT = MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'static') STATIC_URL = MEDIA_URL = '/static/' +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + INSTALLED_APPS = ( 'django.contrib.contenttypes', 'django.contrib.auth', diff --git a/embed_video/tests/templatetags/tests_embed_video_tags.py b/embed_video/tests/templatetags/tests_embed_video_tags.py index 8ddb774..88587c7 100644 --- a/embed_video/tests/templatetags/tests_embed_video_tags.py +++ b/embed_video/tests/templatetags/tests_embed_video_tags.py @@ -1,9 +1,15 @@ from unittest import TestCase, skip from mock import Mock, patch +import sys import re +if sys.version_info.major == 3: + import urllib.parse as urlparse +else: + import urlparse + from django.template import TemplateSyntaxError -from django.http import HttpRequest +from django.http import HttpRequest, QueryDict from django.template.base import Template from django.template.context import RequestContext from django.test.client import RequestFactory @@ -15,10 +21,38 @@ URL_PATTERN = re.compile(r'src="?\'?([^"\'>]*)"') class EmbedTestCase(TestCase): - def assertRenderedTemplate(self, template_string, output, context=None): + def render_template(self, template_string, context=None): response = RequestContext(HttpRequest(), context) - rendered_output = Template(template_string).render(response) - self.assertEqual(rendered_output.strip(), output.strip()) + return Template(template_string).render(response).strip() + + def assertRenderedTemplate(self, template_string, output, context=None): + rendered_output = self.render_template(template_string, context=context) + self.assertEqual(rendered_output, output.strip()) + + def url_dict(self, url): + """ + Parse the URL into a format suitable for comparison, ignoring the query + parameter order. + """ + + parsed = urlparse.urlparse(url) + query = urlparse.parse_qs(parsed.query) + + return { + 'scheme': parsed.scheme, + 'netloc': parsed.netloc, + 'path': parsed.path, + 'params': parsed.params, + 'query': query, + 'fragment': parsed.fragment, + } + + def assertUrlEqual(self, actual, expected, msg=None): + """Assert two URLs are equal, ignoring the query parameter order.""" + actual_dict = self.url_dict(actual) + expected_dict = self.url_dict(expected) + + self.assertEqual(actual_dict, expected_dict, msg=msg) def test_embed(self): template = """ @@ -195,9 +229,11 @@ class EmbedTestCase(TestCase): {{ ytb.url }} {% endvideo %} """ - self.assertRenderedTemplate( - template, - 'http://www.youtube.com/embed/jsrRJyHBvzw?wmode=transparent&rel=1' + + output = self.render_template(template) + self.assertUrlEqual( + output, + 'http://www.youtube.com/embed/jsrRJyHBvzw?rel=1&wmode=transparent' ) def test_direct_embed_with_query(self): @@ -206,10 +242,25 @@ class EmbedTestCase(TestCase): {% video 'http://www.youtube.com/watch?v=jsrRJyHBvzw' query="rel=1&wmode=transparent" %} """ - self.assertRenderedTemplate( - template, + output = self.render_template(template) + + # The order of query parameters in the URL might change between Python + # versions. Compare the URL and the outer part separately. + + url_pattern = re.compile(r'http[^"]+') + url = url_pattern.search(output).group(0) + + self.assertUrlEqual( + url, + 'http://www.youtube.com/embed/jsrRJyHBvzw?rel=1&wmode=transparent' + ) + + output_without_url = url_pattern.sub('URL', output) + + self.assertEqual( + output_without_url, '' ) diff --git a/embed_video/tests/tests_admin.py b/embed_video/tests/tests_admin.py index 50b2c81..0feda69 100644 --- a/embed_video/tests/tests_admin.py +++ b/embed_video/tests/tests_admin.py @@ -1,11 +1,13 @@ from unittest import TestCase +from django.test import SimpleTestCase + from embed_video.admin import AdminVideoWidget, AdminVideoMixin from embed_video.backends import VimeoBackend from embed_video.fields import EmbedVideoField, EmbedVideoFormField -class AdminVideoWidgetTestCase(TestCase): +class AdminVideoWidgetTestCase(SimpleTestCase): def test_size(self): widget = AdminVideoWidget() self.assertTrue('size' in widget.attrs) @@ -21,15 +23,15 @@ class AdminVideoWidgetTestCase(TestCase): def test_render_empty_value(self): widget = AdminVideoWidget(attrs={'size': '0'}) - self.assertEqual(widget.render('foo'), - '') + self.assertHTMLEqual(widget.render('foo'), + '') def test_render(self): backend = VimeoBackend('https://vimeo.com/1') widget = AdminVideoWidget(attrs={'size': '0'}) widget.output_format = '{video}{input}' - self.assertEqual( + self.assertHTMLEqual( widget.render('foo', backend.url, size=(100, 100)), backend.get_embed_code(100, 100) + '' @@ -38,14 +40,14 @@ class AdminVideoWidgetTestCase(TestCase): def test_render_unknown_backend(self): widget = AdminVideoWidget() - self.assertEqual( + self.assertHTMLEqual( widget.render('foo', 'abcd'), '' ) def test_render_video_doesnt_exist(self): widget = AdminVideoWidget() - self.assertEqual( + self.assertHTMLEqual( widget.render('foo', 'https://soundcloud.com/xyz/foo'), '' ) diff --git a/example_project/README.rst b/example_project/README.rst index 8e98ab9..604c4c1 100644 --- a/example_project/README.rst +++ b/example_project/README.rst @@ -7,6 +7,10 @@ Running example project #. Create database:: + python manage.py migrate --run-syncdb --noinput + + Or, for older versions of Django:: + python manage.py syncdb --noinput #. Run testing server:: diff --git a/example_project/example_project/settings.py b/example_project/example_project/settings.py index 7e153ff..a14a08d 100644 --- a/example_project/example_project/settings.py +++ b/example_project/example_project/settings.py @@ -1,7 +1,7 @@ # Django settings for example_project project. +import django DEBUG = True -TEMPLATE_DEBUG = DEBUG DATABASES = { 'default': { @@ -14,21 +14,45 @@ SITE_ID = 1 SECRET_KEY = 'u%38dln@$1!7w#cxi4np504^sa3_skv5aekad)jy_u0v2mc+nr' -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.static', - 'django.core.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - '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.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -) +if django.VERSION >= (1, 10): + MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + ] +else: + MIDDLEWARE_CLASSES = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + ] APPEND_SLASH = True diff --git a/example_project/example_project/urls.py b/example_project/example_project/urls.py index 1b0c32d..cb7110d 100644 --- a/example_project/example_project/urls.py +++ b/example_project/example_project/urls.py @@ -1,11 +1,11 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import include, url from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib import admin admin.autodiscover() urlpatterns = staticfiles_urlpatterns() \ - + patterns('', + + [ url(r'^admin/', include(admin.site.urls)), url(r'^', include('posts.urls', namespace='posts')), - ) + ] diff --git a/example_project/posts/urls.py b/example_project/posts/urls.py index 122e793..bce5bd8 100644 --- a/example_project/posts/urls.py +++ b/example_project/posts/urls.py @@ -1,8 +1,8 @@ -from django.conf.urls import patterns, url +from django.conf.urls import url from .views import PostListView, PostDetailView -urlpatterns = patterns('', +urlpatterns = [ url(r'(?P\d+)/$', PostDetailView.as_view(), name='detail'), url(r'$', PostListView.as_view(), name='list'), -) +]