From 0141614dde0714e0977fc66a6eeb358c7110b897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 26 Jan 2018 16:44:29 +0100 Subject: [PATCH 1/9] fix skipping migration for all Django versions --- runtests.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/runtests.py b/runtests.py index 6654597..9fc686e 100755 --- a/runtests.py +++ b/runtests.py @@ -7,6 +7,14 @@ from django.conf import settings +class DisableMigrations(object): + def __contains__(self, item): + return True + + def __getitem__(self, item): + return 'notmigrations' + + if not settings.configured: settings.configure( DATABASES={ @@ -68,7 +76,7 @@ # https://docs.djangoproject.com/en/1.11/ref/settings/#migration-modules 'scribbler': 'scribbler.tests.migrations' if django_version < (1, 9) else None, 'dayslog': 'dayslog.tests.migrations' if django_version < (1, 9) else None, - }, + } if django_version >= (1, 9) else DisableMigrations(), MEDIA_ROOT='', MEDIA_URL='/media/', STATIC_ROOT='', From 2aee5f1bc6372a9ed32414d3d99e5b6b030c586e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Tue, 23 Jan 2018 15:33:52 +0100 Subject: [PATCH 2/9] Travis tests on all branches --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 99b064c..589d9cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,9 +41,6 @@ install: script: - tox -branches: - only: - - master after_success: - coveralls From d76ee8ede645910430c3c1a1741a6f3f2ae9c0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 26 Jan 2018 17:56:18 +0100 Subject: [PATCH 3/9] fix views tests by waiting before getting response --- scribbler/tests/test_views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scribbler/tests/test_views.py b/scribbler/tests/test_views.py index a7ff5f2..26a2f71 100644 --- a/scribbler/tests/test_views.py +++ b/scribbler/tests/test_views.py @@ -469,4 +469,5 @@ def test_editor(self): action = ActionChains(self.browser) action.send_keys(Keys.F11) action.perform() + self.browser.implicitly_wait(10) self.assertTrue(self.browser.find_element_by_class_name("CodeMirror-fullscreen")) From bcf23e0788dfa38c3398bfa64d242c09c01215d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Thu, 31 Aug 2017 22:01:18 +0200 Subject: [PATCH 4/9] fix unicode URL error + test --- scribbler/conf.py | 2 +- scribbler/tests/migrations/__init__.py | 0 scribbler/tests/test_templatetags.py | 12 ++++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 scribbler/tests/migrations/__init__.py diff --git a/scribbler/conf.py b/scribbler/conf.py index 2ebd155..ebce048 100644 --- a/scribbler/conf.py +++ b/scribbler/conf.py @@ -15,7 +15,7 @@ def default_cache_key(slug, url): "Construct a cache key for a given slug/url pair." - sha = hashlib.sha1('{0}#{1}'.format(url, slug).encode('ascii')) + sha = hashlib.sha1('{0}#{1}'.format(url, slug).encode('utf8')) return '{0}:{1}'.format(CACHE_PREFIX, sha.hexdigest()) diff --git a/scribbler/tests/migrations/__init__.py b/scribbler/tests/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scribbler/tests/test_templatetags.py b/scribbler/tests/test_templatetags.py index 43f65d8..fdcde30 100644 --- a/scribbler/tests/test_templatetags.py +++ b/scribbler/tests/test_templatetags.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + "Test for template tags." from __future__ import unicode_literals @@ -12,6 +14,16 @@ from .base import ScribblerDataTestCase from scribbler.conf import CACHE_TIMEOUT +class UnicodeURLTestCase(ScribblerDataTestCase): + "Test, that unicode characters in url got cached" + + def testUnicodeURL(self): + scribble = self.create_scribble( + url='/foo/čřžžýü', slug='sidebar', + content='

Scribble content.

' + ) + self.assertEquals(scribble.url, "/foo/čřžžýü") + class RenderScribbleTestCase(ScribblerDataTestCase): "Tag to render a scribble for the current page." From d40613357fa3c2767682204e344242350f40c2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 26 Jan 2018 18:28:51 +0100 Subject: [PATCH 5/9] fixes for Django 2.0 --- README.rst | 2 +- runtests.py | 16 +++++++++------- scribbler/forms.py | 15 +++++++++++---- scribbler/tests/base.py | 4 ++-- scribbler/tests/jinja2.py | 5 ++++- scribbler/tests/test_views.py | 5 ++++- scribbler/tests/urls.py | 11 ++++++++--- scribbler/views.py | 8 ++++---- 8 files changed, 43 insertions(+), 23 deletions(-) diff --git a/README.rst b/README.rst index 166884e..4b146c7 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,7 @@ Features Installation -------------------------------------- -django-scribbler requires Django 1.8, 1.10, or 1.11, and Python 2.7 or >= 3.4. +django-scribbler requires Django 1.8, 1.10, 1.11, or 2.0, and Python 2.7 or >= 3.4. To install from PyPi:: diff --git a/runtests.py b/runtests.py index 9fc686e..541cc53 100755 --- a/runtests.py +++ b/runtests.py @@ -6,6 +6,13 @@ from django import VERSION as django_version from django.conf import settings +MIDDLEWARES=( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', +) class DisableMigrations(object): def __contains__(self, item): @@ -30,13 +37,8 @@ def __getitem__(self, item): 'django.contrib.staticfiles', 'scribbler', ), - MIDDLEWARE_CLASSES=( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - ), + MIDDLEWARE_CLASSES=MIDDLEWARES, + MIDDLEWARE=MIDDLEWARES, SITE_ID=1, SECRET_KEY='super-secret', diff --git a/scribbler/forms.py b/scribbler/forms.py index 98090c1..2d3bd54 100644 --- a/scribbler/forms.py +++ b/scribbler/forms.py @@ -5,9 +5,16 @@ from django import forms from django.db.models import ObjectDoesNotExist, FieldDoesNotExist -from django.template import StringOrigin -from django.core.urlresolvers import reverse +try: + from django.template import Origin +except ImportError: # Django<2.0 + from django.template import StringOrigin as Origin +try: + from django.urls import reverse +except ImportError: # Django<2.0 + from django.core.urlresolvers import reverse from django.contrib.contenttypes.models import ContentType +from django.utils.encoding import force_text from .models import Scribble @@ -17,7 +24,7 @@ class ScribbleFormMixin(object): def clean_content(self): content = self.cleaned_data.get('content', '') if content: - origin = StringOrigin(content) + origin = Origin(content) try: from django.template.debug import DebugLexer, DebugParser @@ -27,7 +34,7 @@ def clean_content(self): from django.template import Template # Try to create a Template try: - template = Template(template_string=origin) + template = Template(template_string=force_text(origin)) # This is an error with creating the template except Exception as e: self.exc_info = { diff --git a/scribbler/tests/base.py b/scribbler/tests/base.py index 15009d1..1f3801d 100644 --- a/scribbler/tests/base.py +++ b/scribbler/tests/base.py @@ -5,12 +5,12 @@ import string from django.contrib.auth.models import User -from django.test import TestCase +from django.test import TransactionTestCase from scribbler.models import Scribble -class ScribblerDataTestCase(TestCase): +class ScribblerDataTestCase(TransactionTestCase): "Base test case for creating scribbler models." def get_random_string(self, length=10): diff --git a/scribbler/tests/jinja2.py b/scribbler/tests/jinja2.py index 6c2db3a..ad28cd3 100644 --- a/scribbler/tests/jinja2.py +++ b/scribbler/tests/jinja2.py @@ -1,7 +1,10 @@ from __future__ import absolute_import # Python 2 only from django.contrib.staticfiles.storage import staticfiles_storage -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: # Django<2.0 + from django.core.urlresolvers import reverse from jinja2 import Environment diff --git a/scribbler/tests/test_views.py b/scribbler/tests/test_views.py index 26a2f71..ac6f507 100644 --- a/scribbler/tests/test_views.py +++ b/scribbler/tests/test_views.py @@ -9,7 +9,10 @@ from django.contrib.auth.models import Permission, User from django.contrib.contenttypes.models import ContentType -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except ImportError: # Django<2.0 + from django.core.urlresolvers import reverse from django.contrib.staticfiles.testing import StaticLiveServerTestCase from django.test import override_settings diff --git a/scribbler/tests/urls.py b/scribbler/tests/urls.py index 1806430..8734714 100644 --- a/scribbler/tests/urls.py +++ b/scribbler/tests/urls.py @@ -1,20 +1,25 @@ from django.conf.urls import include, url, handler404, handler500 from django.http import HttpResponseNotFound, HttpResponseServerError from django.contrib.auth import views as auth_views -from django.views.i18n import javascript_catalog +try: + from django.views.i18n import JavaScriptCatalog + javascript_catalog = JavaScriptCatalog.as_view() +except ImportError: # Django<1.10 + from django.views.i18n import javascript_catalog handler404 = 'scribbler.tests.urls.test_404' handler500 = 'scribbler.tests.urls.test_500' -def test_404(request): +def test_404(request, exception=None): return HttpResponseNotFound() -def test_500(request): +def test_500(request, exception=None): return HttpResponseServerError() + js_info_dict = { 'packages': ('scribbler', ), } diff --git a/scribbler/views.py b/scribbler/views.py index 5d5fbbf..1a1005c 100644 --- a/scribbler/views.py +++ b/scribbler/views.py @@ -29,7 +29,7 @@ def build_scribble_context(scribble): @require_POST def preview_scribble(request, ct_pk): "Render scribble content or return error information." - if not request.user.is_authenticated(): + if not request.user.is_authenticated: return HttpResponseForbidden() content_type = get_object_or_404(ContentType, pk=ct_pk) change_scribble = '{0}.change_{1}'.format( @@ -83,7 +83,7 @@ def preview_scribble(request, ct_pk): @require_POST def create_edit_scribble(request, scribble_id=None): "Create a new Scribble or edit an existing one." - if not request.user.is_authenticated(): + if not request.user.is_authenticated: return HttpResponseForbidden() if scribble_id is not None: scribble = get_object_or_404(Scribble, pk=scribble_id) @@ -107,7 +107,7 @@ def create_edit_scribble(request, scribble_id=None): @require_POST def edit_scribble_field(request, ct_pk, instance_pk, field_name): - if not request.user.is_authenticated(): + if not request.user.is_authenticated: return HttpResponseForbidden() content_type = get_object_or_404(ContentType, pk=ct_pk) perm_name = '{0}.change_{1}'.format(content_type.app_label, content_type.model) @@ -133,7 +133,7 @@ def edit_scribble_field(request, ct_pk, instance_pk, field_name): @require_POST def delete_scribble(request, scribble_id): "Delete an existing scribble." - if not request.user.is_authenticated(): + if not request.user.is_authenticated: return HttpResponseForbidden() scribble = get_object_or_404(Scribble, pk=scribble_id) if not request.user.has_perm('scribbler.delete_scribble'): From e4111bcb0cd62d7b04f7784fb9b2720f15af5b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 26 Jan 2018 15:26:40 +0100 Subject: [PATCH 6/9] add possibility to specifiy args for runtests.py --- runtests.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/runtests.py b/runtests.py index 541cc53..dd02eab 100755 --- a/runtests.py +++ b/runtests.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import sys import os +from optparse import OptionParser import django from django import VERSION as django_version @@ -90,18 +91,23 @@ def __getitem__(self, item): from django.test.utils import get_runner -def runtests(): +def runtests(*test_args, **kwargs): if django_version < (1, 11): # Try lots of ports until we find one we can use os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = 'localhost:8099-9999' if hasattr(django, 'setup'): django.setup() + if not test_args: + test_args = ['scribbler', ] TestRunner = get_runner(settings) test_runner = TestRunner(verbosity=1, interactive=True, failfast=False) - failures = test_runner.run_tests(['scribbler', ]) + failures = test_runner.run_tests(test_args) sys.exit(failures) if __name__ == '__main__': - runtests() + parser = OptionParser() + + (options, args) = parser.parse_args() + runtests(*args) From a423d67cfa254b7c60e215dfac37ddf82a755309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 26 Jan 2018 15:55:15 +0100 Subject: [PATCH 7/9] add Django2.0 to Travis and Tox --- .travis.yml | 20 +++++++++++++++++--- tox.ini | 9 ++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 589d9cc..6ffa67a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,9 +23,23 @@ python: - "3.6" env: - - TOXENV=py27-1.8.X,py34-1.8.X,py35-1.8.X - - TOXENV=py27-1.10.X,py34-1.10.X,py35-1.10.X - - TOXENV=py27-1.11.X,py34-1.11.X,py36-1.11.X + - TOXENV=py27-1.8.X + - TOXENV=py34-1.8.X + - TOXENV=py35-1.8.X + + - TOXENV=py27-1.10.X + - TOXENV=py34-1.10.X + - TOXENV=py35-1.10.X + + - TOXENV=py27-1.11.X + - TOXENV=py34-1.11.X + - TOXENV=py35-1.11.X + - TOXENV=py36-1.11.X + + - TOXENV=py34-2.0.X + - TOXENV=py35-2.0.X + - TOXENV=py36-2.0.X + - TOXENV=coverage - TOXENV=docs - TOXENV=qunit diff --git a/tox.ini b/tox.ini index b1a8314..429fb7c 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,15 @@ # 1.8: 2.7, 3.2, 3.3, 3.4, 3.5 # 1.10: 2.7, 3.4, 3.5 # 1.11: 2.7, 3.4, 3.5, 3.6 +# 2.0: 3.4, 3.5, 3.6 [tox] -envlist = {py27,py34,py35}-1.8.X,{py27,py34,py35}-1.10.X,{py27,py34,py36}-1.11.X,coverage,docs,qunit +envlist = + {py27,py34,py35}-1.8.X, + {py27,py34,py35}-1.10.X, + {py27,py34,py35,py36}-1.11.X, + {py34,py35,py36}-{2.0}.X, + coverage,docs,qunit [testenv] passenv = TRAVIS DISPLAY @@ -18,6 +24,7 @@ deps = 1.8.X: Django>=1.8,<1.9 1.10.X: Django>=1.10,<1.11 1.11.X: Django>=1.11,<2.0 + 2.0.X: Django>=2.0,<2.1 Jinja2 selenium whitelist_externals = make From f50d712393f55f67297a04597ee4e64c4158575a Mon Sep 17 00:00:00 2001 From: Yaroslav Klyuyev Date: Sat, 16 Jun 2018 18:57:57 +0300 Subject: [PATCH 8/9] fix ScribbleFormMixin.clean_content for unicode content on Django>1.9 --- scribbler/forms.py | 2 +- scribbler/tests/test_templatetags.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/scribbler/forms.py b/scribbler/forms.py index 2d3bd54..287d255 100644 --- a/scribbler/forms.py +++ b/scribbler/forms.py @@ -34,7 +34,7 @@ def clean_content(self): from django.template import Template # Try to create a Template try: - template = Template(template_string=force_text(origin)) + template = Template(template_string=force_text(content), origin=origin) # This is an error with creating the template except Exception as e: self.exc_info = { diff --git a/scribbler/tests/test_templatetags.py b/scribbler/tests/test_templatetags.py index fdcde30..1a82408 100644 --- a/scribbler/tests/test_templatetags.py +++ b/scribbler/tests/test_templatetags.py @@ -82,6 +82,16 @@ def test_default_rendering(self): result = self.render_template_tag(slug='"sidebar"') self.assertTrue('

Default.

' in result) + def test_unicode_rendering(self): + "Render with unicode defaults when no scribbles exist." + # On Django>=1.9 ScribbleFormMixin.clean_content directly uses django.template.Template + # and also uses force_text that may fail for non-string objects that have __str__ with + # unicode output. + self.scribble.delete() + unicode_default = '

\u0422\u0435\u043a\u0441\u0442.

' + result = self.render_template_tag(slug='"sidebar"', default=unicode_default) + self.assertTrue(unicode_default in result) + def test_no_slug_given(self): "Slug is required by the tag." self.assertRaises(TemplateSyntaxError, self.render_template_tag, slug='') From e087167be4087d65b061c122afccf1cd8b34fdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Fri, 31 Aug 2018 00:28:50 +0200 Subject: [PATCH 9/9] fixes and testing for Django 2.1 --- .travis.yml | 3 +++ package.json | 4 ++-- scribbler/models.py | 12 +++++++----- scribbler/templatetags/scribbler_tags.py | 17 ++++++++++++++--- scribbler/tests/urls.py | 7 ++++++- tox.ini | 2 ++ 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ffa67a..939202b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,9 @@ env: - TOXENV=py35-2.0.X - TOXENV=py36-2.0.X + - TOXENV=py35-2.1.X + - TOXENV=py36-2.1.X + - TOXENV=coverage - TOXENV=docs - TOXENV=qunit diff --git a/package.json b/package.json index 0625714..06d9919 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,9 @@ }, "dependencies": { "backbone": ">=1.2 <1.3", - "codemirror": ">=5.10 <6.0", + "codemirror": "^5.40.0", "jquery": ">=2.2 <2.3", - "jshint": "^2.9.5", + "jshint": "^2.9.6", "less": "^2.7.3", "phantomjs-prebuilt": "^2.1.16", "underscore": ">=1.8 <1.9" diff --git a/scribbler/models.py b/scribbler/models.py index b9a2ccf..f0787df 100644 --- a/scribbler/models.py +++ b/scribbler/models.py @@ -5,6 +5,10 @@ from django.db import models from django.db.models.signals import post_save, post_delete, pre_save from django.dispatch import receiver +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse try: from django.utils.six import PY3 except ImportError: @@ -35,16 +39,14 @@ def __str__(self): class Meta(object): unique_together = ('slug', 'url') - @models.permalink def get_save_url(self): if self.pk: - return ('edit-scribble', (), {'scribble_id': self.pk}) + return reverse('edit-scribble', kwargs={'scribble_id': self.pk}) else: - return ('create-scribble', (), {}) + return reverse('create-scribble') - @models.permalink def get_delete_url(self): - return ('delete-scribble', (), {'scribble_id': self.pk}) + return reverse('delete-scribble', kwargs={'scribble_id': self.pk}) @receiver(post_save, sender=Scribble) diff --git a/scribbler/templatetags/scribbler_tags.py b/scribbler/templatetags/scribbler_tags.py index c2b660e..af17c46 100644 --- a/scribbler/templatetags/scribbler_tags.py +++ b/scribbler/templatetags/scribbler_tags.py @@ -14,6 +14,16 @@ from scribbler.views import build_scribble_context +try: + TOKEN_VAR = template_base.TokenType.VAR + TOKEN_BLOCK = template_base.TokenType.BLOCK + TOKEN_COMMENT = template_base.TokenType.COMMENT +except AttributeError: + TOKEN_VAR = template_base.TOKEN_VAR + TOKEN_BLOCK = template_base.TOKEN_BLOCK + TOKEN_COMMENT = template_base.TOKEN_COMMENT + + register = template.Library() @@ -88,24 +98,25 @@ def render(self, context): return wrapper_template.render(context_data, request) + def rebuild_template_string(tokens): "Reconstruct the original template from a list of tokens." result = '' for token in tokens: value = token.contents - if token.token_type == template_base.TOKEN_VAR: + if token.token_type == TOKEN_VAR: value = '{0} {1} {2}'.format( template_base.VARIABLE_TAG_START, value, template_base.VARIABLE_TAG_END, ) - elif token.token_type == template_base.TOKEN_BLOCK: + elif token.token_type == TOKEN_BLOCK: value = '{0} {1} {2}'.format( template_base.BLOCK_TAG_START, value, template_base.BLOCK_TAG_END, ) - elif token.token_type == template_base.TOKEN_COMMENT: + elif token.token_type == TOKEN_COMMENT: value = '{0} {1} {2}'.format( template_base.COMMENT_TAG_START, value, diff --git a/scribbler/tests/urls.py b/scribbler/tests/urls.py index 8734714..4fd1b87 100644 --- a/scribbler/tests/urls.py +++ b/scribbler/tests/urls.py @@ -24,8 +24,13 @@ def test_500(request, exception=None): 'packages': ('scribbler', ), } +try: + login_url = url(r'^test/', auth_views.LoginView.as_view(template_name='test.html')) +except AttributeError: + login_url = url(r'^test/', auth_views.login, {'template_name': 'test.html'}) + urlpatterns = [ url(r'^scribble/', include('scribbler.urls')), url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='jsi18n'), - url(r'^test/', auth_views.login, {'template_name': 'test.html'}), + login_url, ] diff --git a/tox.ini b/tox.ini index 429fb7c..571109b 100644 --- a/tox.ini +++ b/tox.ini @@ -11,6 +11,7 @@ envlist = {py27,py34,py35}-1.10.X, {py27,py34,py35,py36}-1.11.X, {py34,py35,py36}-{2.0}.X, + {py35,py36}-{2.1}.X, coverage,docs,qunit [testenv] @@ -25,6 +26,7 @@ deps = 1.10.X: Django>=1.10,<1.11 1.11.X: Django>=1.11,<2.0 2.0.X: Django>=2.0,<2.1 + 2.1.X: Django>=2.1,<2.2 Jinja2 selenium whitelist_externals = make