Merge pull request #5 from Gagaro/master

Python3 / Django1.7 support & better testing
This commit is contained in:
Florent Lebreton
2014-12-04 13:50:38 +01:00
10 changed files with 115 additions and 42 deletions

View File

@@ -1,19 +1,42 @@
language: python language: python
python: python:
- "2.7" - 2.6
- 2.7
- 3.2
- 3.3
- 3.4
env: env:
- DJANGO_VERSION=1.4 - DJANGO_VERSION=1.4 MODULE=jsignature
- DJANGO_VERSION=1.5 - DJANGO_VERSION=1.5 MODULE=jsignature
- DJANGO_VERSION=1.6 MODULE=jsignature.tests
- DJANGO_VERSION=1.7 MODULE=jsignature.tests
install: install:
- pip install -r requirements.txt --use-mirrors - pip install -r requirements.txt --use-mirrors
- pip install -q Django==$DJANGO_VERSION --use-mirrors - pip install -q Django==$DJANGO_VERSION --use-mirrors
- pip install coverage - pip install coverage
script: coverage run quicktest.py jsignature script: coverage run quicktest.py $MODULE
after_success: after_success:
- pip install coveralls - pip install coveralls
- coveralls - coveralls
# We need to exclude old versions of Django for tests with python 3.
# We need to exclude old versions of Python for tests with Django >= 1.7.
matrix:
exclude:
- python: 3.2
env: DJANGO_VERSION=1.4 MODULE=jsignature
- python: 3.3
env: DJANGO_VERSION=1.4 MODULE=jsignature
- python: 3.4
env: DJANGO_VERSION=1.4 MODULE=jsignature
- python: 3.4
env: DJANGO_VERSION=1.5 MODULE=jsignature
- python: 3.4
env: DJANGO_VERSION=1.6 MODULE=jsignature.tests
- python: 2.6
env: DJANGO_VERSION=1.7 MODULE=jsignature.tests

View File

@@ -3,19 +3,21 @@
with jSignature jQuery plugin with jSignature jQuery plugin
""" """
import json import json
import six
from django.db import models from django.db import models
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from .forms import ( from .forms import (
JSignatureField as JSignatureFormField, JSignatureField as JSignatureFormField,
JSIGNATURE_EMPTY_VALUES) JSIGNATURE_EMPTY_VALUES)
class JSignatureField(models.Field): class JSignatureField(six.with_metaclass(models.SubfieldBase, models.Field)):
""" """
A model field handling a signature captured with jSignature A model field handling a signature captured with jSignature
""" """
description = "A signature captured with jSignature" description = "A signature captured with jSignature"
__metaclass__ = models.SubfieldBase
def get_internal_type(self): def get_internal_type(self):
return 'TextField' return 'TextField'
@@ -37,7 +39,7 @@ class JSignatureField(models.Field):
def get_prep_value(self, value): def get_prep_value(self, value):
if value in JSIGNATURE_EMPTY_VALUES: if value in JSIGNATURE_EMPTY_VALUES:
return None return None
elif isinstance(value, basestring): elif isinstance(value, six.string_types):
return value return value
elif isinstance(value, list): elif isinstance(value, list):
return json.dumps(value) return json.dumps(value)

View File

@@ -1,4 +1,6 @@
import json import json
import six
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@@ -8,35 +10,49 @@ from ..forms import JSignatureField as JSignatureFormField
class JSignatureFieldTest(SimpleTestCase): class JSignatureFieldTest(SimpleTestCase):
def test_to_python(self): def test_to_python_empty(self):
f = JSignatureField() f = JSignatureField()
# Empty values
for val in ['', [], '[]']: for val in ['', [], '[]']:
self.assertIsNone(f.to_python(val)) self.assertIsNone(f.to_python(val))
# Correct values
def test_to_python_correct_value_python(self):
f = JSignatureField()
val = [{"x": [1, 2], "y": [3, 4]}] val = [{"x": [1, 2], "y": [3, 4]}]
self.assertEquals(val, f.to_python(val)) self.assertEquals(val, f.to_python(val))
def test_to_python_correct_value_json(self):
f = JSignatureField()
val = [{"x": [1, 2], "y": [3, 4]}]
val_str = '[{"x":[1,2], "y":[3,4]}]' val_str = '[{"x":[1,2], "y":[3,4]}]'
self.assertEquals(val, f.to_python(val_str)) self.assertEquals(val, f.to_python(val_str))
# Incorrect values
def test_to_python_incorrect_value(self):
f = JSignatureField()
val = 'foo' val = 'foo'
self.assertRaises(ValidationError, f.to_python, val) self.assertRaises(ValidationError, f.to_python, val)
def test_get_prep_value(self): def test_get_prep_value_empty(self):
f = JSignatureField() f = JSignatureField()
# Empty values
for val in ['', [], '[]']: for val in ['', [], '[]']:
self.assertIsNone(f.get_prep_value(val)) self.assertIsNone(f.get_prep_value(val))
# Correct values
def test_get_prep_value_correct_values_python(self):
f = JSignatureField()
val = [{"x": [1, 2], "y": [3, 4]}] val = [{"x": [1, 2], "y": [3, 4]}]
val_prep = f.get_prep_value(val) val_prep = f.get_prep_value(val)
self.assertIsInstance(val_prep, basestring) self.assertIsInstance(val_prep, six.string_types)
self.assertEquals(val, json.loads(val_prep)) self.assertEquals(val, json.loads(val_prep))
def test_get_prep_value_correct_values_json(self):
f = JSignatureField()
val = [{"x": [1, 2], "y": [3, 4]}]
val_str = '[{"x":[1,2], "y":[3,4]}]' val_str = '[{"x":[1,2], "y":[3,4]}]'
val_prep = f.get_prep_value(val_str) val_prep = f.get_prep_value(val_str)
self.assertIsInstance(val_prep, basestring) self.assertIsInstance(val_prep, six.string_types)
self.assertEquals(val, json.loads(val_prep)) self.assertEquals(val, json.loads(val_prep))
# Incorrect values
def test_get_prep_value_incorrect_values(self):
f = JSignatureField()
val = type('Foo') val = type('Foo')
self.assertRaises(ValidationError, f.get_prep_value, val) self.assertRaises(ValidationError, f.get_prep_value, val)

View File

@@ -11,14 +11,17 @@ class JSignatureFormFieldTest(SimpleTestCase):
f = JSignatureField() f = JSignatureField()
self.assertIsInstance(f.widget, JSignatureWidget) self.assertIsInstance(f.widget, JSignatureWidget)
def test_to_python(self): def test_to_python_empty_values(self):
f = JSignatureField() f = JSignatureField()
# Empty values
for val in ['', [], '[]']: for val in ['', [], '[]']:
self.assertIsNone(f.to_python(val)) self.assertIsNone(f.to_python(val))
# Correct values
def test_to_python_correct_values(self):
f = JSignatureField()
val = '[{"x":[1,2], "y":[3,4]}]' val = '[{"x":[1,2], "y":[3,4]}]'
self.assertEquals([{'x': [1, 2], 'y': [3, 4]}], f.to_python(val)) self.assertEquals([{'x': [1, 2], 'y': [3, 4]}], f.to_python(val))
# Incorrect values
def test_to_python_incorrect_values(self):
f = JSignatureField()
val = 'foo' val = 'foo'
self.assertRaises(ValidationError, f.to_python, val) self.assertRaises(ValidationError, f.to_python, val)

View File

@@ -19,7 +19,7 @@ class JSignatureFieldsMixinTest(SimpleTestCase):
def tearDown(self): def tearDown(self):
settings.INSTALLED_APPS = self.old_installed_apps settings.INSTALLED_APPS = self.old_installed_apps
def test_save(self): def test_save_create(self):
# If an object is created signed, signature date must be set # If an object is created signed, signature date must be set
signature_value = [{"x": [1, 2], "y": [3, 4]}] signature_value = [{"x": [1, 2], "y": [3, 4]}]
i = JSignatureTestModel(signature=signature_value) i = JSignatureTestModel(signature=signature_value)
@@ -27,16 +27,19 @@ class JSignatureFieldsMixinTest(SimpleTestCase):
i = JSignatureTestModel.objects.get(pk=i.pk) i = JSignatureTestModel.objects.get(pk=i.pk)
self.assertEqual(date.today(), i.signature_date.date()) self.assertEqual(date.today(), i.signature_date.date())
def test_save_no_change(self):
# If signature doesn't change, signature date must not be updated # If signature doesn't change, signature date must not be updated
signature_value = [{"x": [1, 2], "y": [3, 4]}]
i = JSignatureTestModel(signature=signature_value) i = JSignatureTestModel(signature=signature_value)
i.save() i.save()
i.signature_date = date(2013, 1, 1) i.signature_date = date(2013, 1, 1)
i.signature = signature_value
i.save() i.save()
i = JSignatureTestModel.objects.get(pk=i.pk) i = JSignatureTestModel.objects.get(pk=i.pk)
self.assertEqual(date(2013, 1, 1), i.signature_date.date()) self.assertEqual(date(2013, 1, 1), i.signature_date.date())
def test_save_change(self):
# If signature changes, signature date must be updated too # If signature changes, signature date must be updated too
signature_value = [{"x": [1, 2], "y": [3, 4]}]
new_signature_value = [{"x": [5, 6], "y": [7, 8]}] new_signature_value = [{"x": [5, 6], "y": [7, 8]}]
i = JSignatureTestModel(signature=signature_value, i = JSignatureTestModel(signature=signature_value,
signature_date=date(2013, 1, 1)) signature_date=date(2013, 1, 1))
@@ -47,7 +50,9 @@ class JSignatureFieldsMixinTest(SimpleTestCase):
i = JSignatureTestModel.objects.get(pk=i.pk) i = JSignatureTestModel.objects.get(pk=i.pk)
self.assertEqual(date.today(), i.signature_date.date()) self.assertEqual(date.today(), i.signature_date.date())
def test_save_none(self):
# If sinature is set to None, it must be the same for signature_date # If sinature is set to None, it must be the same for signature_date
signature_value = [{"x": [1, 2], "y": [3, 4]}]
i = JSignatureTestModel(signature=signature_value) i = JSignatureTestModel(signature=signature_value)
i.save() i.save()
i.signature = None i.signature = None

View File

@@ -13,22 +13,24 @@ DUMMY_STR_VALUE = json.dumps(DUMMY_VALUE)
class UtilsTest(SimpleTestCase): class UtilsTest(SimpleTestCase):
def test_inputs(self): def test_inputs_bad_str_value(self):
# Bad str value
self.assertRaises(ValueError, draw_signature, 'foo_bar') self.assertRaises(ValueError, draw_signature, 'foo_bar')
# Bad type value
def test_inputs_bad_type_value(self):
self.assertRaises(ValueError, draw_signature, object()) self.assertRaises(ValueError, draw_signature, object())
# Good list value
def test_inputs_good_list_value(self):
draw_signature(DUMMY_VALUE) draw_signature(DUMMY_VALUE)
# Good str value
def test_inputs_good_str_value(self):
draw_signature(DUMMY_STR_VALUE) draw_signature(DUMMY_STR_VALUE)
def test_outputs(self): def test_outputs_as_file(self):
# As a file
output = draw_signature(DUMMY_VALUE, as_file=True) output = draw_signature(DUMMY_VALUE, as_file=True)
self.assertTrue(os.path.isfile(output)) self.assertTrue(os.path.isfile(output))
self.assertIsNotNone(imghdr.what(output)) self.assertIsNotNone(imghdr.what(output))
# As an Image
def test_outputs_as_image(self):
output = draw_signature(DUMMY_VALUE) output = draw_signature(DUMMY_VALUE)
self.assertTrue(issubclass(output.__class__, Image.Image)) self.assertTrue(issubclass(output.__class__, Image.Image))
self.assertTrue(all(output.getbbox())) self.assertTrue(all(output.getbbox()))

View File

@@ -1,5 +1,6 @@
import json import json
from pyquery import PyQuery as pq from pyquery import PyQuery as pq
import six
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@@ -48,7 +49,7 @@ class JSignatureWidgetTest(SimpleTestCase):
w = JSignatureWidget() w = JSignatureWidget()
val = [{"x": [1, 2], "y": [3, 4]}] val = [{"x": [1, 2], "y": [3, 4]}]
val_prep = w.prep_value(val) val_prep = w.prep_value(val)
self.assertIsInstance(val_prep, basestring) self.assertIsInstance(val_prep, six.string_types)
self.assertEquals(val, json.loads(val_prep)) self.assertEquals(val, json.loads(val_prep))
def test_prep_value_correct_values_json(self): def test_prep_value_correct_values_json(self):
@@ -56,7 +57,7 @@ class JSignatureWidgetTest(SimpleTestCase):
val = [{"x": [1, 2], "y": [3, 4]}] val = [{"x": [1, 2], "y": [3, 4]}]
val_str = '[{"x":[1,2], "y":[3,4]}]' val_str = '[{"x":[1,2], "y":[3,4]}]'
val_prep = w.prep_value(val_str) val_prep = w.prep_value(val_str)
self.assertIsInstance(val_prep, basestring) self.assertIsInstance(val_prep, six.string_types)
self.assertEquals(val, json.loads(val_prep)) self.assertEquals(val, json.loads(val_prep))
def test_prep_value_incorrect_values(self): def test_prep_value_incorrect_values(self):

View File

@@ -3,11 +3,13 @@
with jSignature jQuery plugin with jSignature jQuery plugin
""" """
import json import json
import six
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.forms.widgets import HiddenInput from django.forms.widgets import HiddenInput
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from jsignature.settings import JSIGNATURE_DEFAULT_CONFIG from jsignature.settings import JSIGNATURE_DEFAULT_CONFIG
@@ -51,7 +53,7 @@ class JSignatureWidget(HiddenInput):
""" Prepare value before effectively render widget """ """ Prepare value before effectively render widget """
if value in JSIGNATURE_EMPTY_VALUES: if value in JSIGNATURE_EMPTY_VALUES:
return "[]" return "[]"
elif isinstance(value, basestring): elif isinstance(value, six.string_types):
return value return value
elif isinstance(value, list): elif isinstance(value, list):
return json.dumps(value) return json.dumps(value)

View File

@@ -3,6 +3,7 @@ import sys
import argparse import argparse
from django.conf import settings from django.conf import settings
class QuickDjangoTest(object): class QuickDjangoTest(object):
""" """
A quick way to run the Django test suite without a fully-configured project. A quick way to run the Django test suite without a fully-configured project.
@@ -16,8 +17,6 @@ class QuickDjangoTest(object):
""" """
DIRNAME = os.path.dirname(__file__) DIRNAME = os.path.dirname(__file__)
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.contenttypes',
'django.contrib.sessions',
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -29,7 +28,10 @@ class QuickDjangoTest(object):
Fire up the Django test suite developed for version 1.2 Fire up the Django test suite developed for version 1.2
""" """
settings.configure( settings.configure(
DATABASES={ TEMPLATE_DIRS = ('jsignature/templates/',),
ROOT_URLCONF = 'jsignature.tests',
DEBUG = True,
DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(self.DIRNAME, 'database.db'), 'NAME': os.path.join(self.DIRNAME, 'database.db'),
@@ -39,11 +41,27 @@ class QuickDjangoTest(object):
'PORT': '', 'PORT': '',
} }
}, },
INSTALLED_APPS=self.INSTALLED_APPS + self.apps, MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
),
INSTALLED_APPS = self.INSTALLED_APPS + self.apps
) )
from django.test.simple import DjangoTestSuiteRunner # Setup is needed for Django >= 1.7
failures = DjangoTestSuiteRunner().run_tests(self.apps, verbosity=1) import django
if failures: # pragma: no cover if hasattr(django, 'setup'):
django.setup()
try:
from django.test.runner import DiscoverRunner
failures = DiscoverRunner().run_tests(self.apps, verbosity=1)
except ImportError:
# DjangoTestSuiteRunner has been deprecated in Django 1.7
from django.test.simple import DjangoTestSuiteRunner
failures = DjangoTestSuiteRunner().run_tests(self.apps, verbosity=1)
if failures: # pragma: no cover
sys.exit(failures) sys.exit(failures)
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -1,2 +1,3 @@
pillow pillow
pyquery pyquery
six