Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae58c7f725 | ||
|
|
cf9a37a009 | ||
|
|
382c824cca | ||
|
|
63c3d7d2dc | ||
|
|
ea3800375c | ||
|
|
a42a9ca543 | ||
|
|
9e81795f99 | ||
|
|
7fe2560910 | ||
|
|
e92132349c |
66
.github/workflows/actions.yml
vendored
Normal file
66
.github/workflows/actions.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
name: Run Tests
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
django_version:
|
||||
- '2.2'
|
||||
- '3.2'
|
||||
- '4.0'
|
||||
python-version:
|
||||
- 3.6
|
||||
- 3.7
|
||||
- 3.8
|
||||
- 3.9
|
||||
- "3.10"
|
||||
exclude:
|
||||
- django_version: '2.2'
|
||||
python-version: '3.10'
|
||||
|
||||
- django_version: '4.0'
|
||||
python-version: '3.6'
|
||||
|
||||
- django_version: '4.0'
|
||||
python-version: '3.7'
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
# This path is specific to Ubuntu
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ matrix.django_version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e .
|
||||
pip install -U flake8 coveralls argparse
|
||||
pip install -U Django~=${{ matrix.django_version }}
|
||||
|
||||
- name: Lint with flake8
|
||||
run: flake8 --ignore=E501,W504 jsignature
|
||||
|
||||
- name: Test Django
|
||||
run: |
|
||||
python -W error::DeprecationWarning -W error::PendingDeprecationWarning \
|
||||
-m coverage run ./runtests.py
|
||||
|
||||
- name: Coverage
|
||||
if: ${{ success() }}
|
||||
run: |
|
||||
coveralls --service=github
|
||||
46
.travis.yml
46
.travis.yml
@@ -1,46 +0,0 @@
|
||||
language: python
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: DJANGO=master
|
||||
include:
|
||||
- python: 2.7
|
||||
env: DJANGO=1.11
|
||||
|
||||
- python: 3.5
|
||||
env: DJANGO=1.11
|
||||
- python: 3.5
|
||||
env: DJANGO=2.2
|
||||
|
||||
- python: 3.6
|
||||
env: DJANGO=1.11
|
||||
- python: 3.6
|
||||
env: DJANGO=2.2
|
||||
- python: 3.6
|
||||
env: DJANGO=3.0
|
||||
- python: 3.6
|
||||
env: DJANGO=master
|
||||
|
||||
- python: 3.7
|
||||
env: DJANGO=2.2
|
||||
- python: 3.7
|
||||
env: DJANGO=3.0
|
||||
- python: 3.7
|
||||
env: DJANGO=master
|
||||
|
||||
|
||||
- python: 3.8
|
||||
env: DJANGO=2.2
|
||||
- python: 3.8
|
||||
env: DJANGO=3.0
|
||||
- python: 3.8
|
||||
env: DJANGO=master
|
||||
|
||||
install:
|
||||
- pip install tox tox-travis
|
||||
script:
|
||||
- tox
|
||||
after_success:
|
||||
- pip install coveralls
|
||||
- coveralls
|
||||
12
CHANGES
12
CHANGES
@@ -2,6 +2,18 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.11 (2022-01-17)
|
||||
==================
|
||||
|
||||
** New **
|
||||
|
||||
- Django 4.0 compatibility.
|
||||
- Moved to Github Actions for testing.
|
||||
- Added flake8 in CI.
|
||||
- Dropped support for python < 3.6
|
||||
- Dropped support for Django 1.11, 2.0, 2.1, 3.0, 3.1.
|
||||
|
||||
|
||||
0.10 (2020-07-26)
|
||||
==================
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ class JSignatureField(Field):
|
||||
widget = JSignatureWidget()
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
Validates that the input can be red as a JSON object.
|
||||
Returns a Python list (JSON object unserialized).
|
||||
"""
|
||||
if value in JSIGNATURE_EMPTY_VALUES:
|
||||
return None
|
||||
try:
|
||||
return json.loads(value)
|
||||
except ValueError:
|
||||
raise ValidationError('Invalid JSON format.')
|
||||
"""
|
||||
Validates that the input can be red as a JSON object.
|
||||
Returns a Python list (JSON object unserialized).
|
||||
"""
|
||||
if value in JSIGNATURE_EMPTY_VALUES:
|
||||
return None
|
||||
try:
|
||||
return json.loads(value)
|
||||
except ValueError:
|
||||
raise ValidationError('Invalid JSON format.')
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from .fields import JSignatureField
|
||||
|
||||
|
||||
|
||||
@@ -15,25 +15,31 @@ def draw_signature(data, as_file=False):
|
||||
if `as_file` is True, a temp file is returned instead of Image instance
|
||||
"""
|
||||
|
||||
def _remove_empty_pts(pt):
|
||||
return {
|
||||
'x': list(filter(lambda n: n is not None, pt['x'])),
|
||||
'y': list(filter(lambda n: n is not None, pt['y']))
|
||||
}
|
||||
|
||||
if type(data) is str:
|
||||
drawing = json.loads(data)
|
||||
drawing = json.loads(data, object_hook=_remove_empty_pts)
|
||||
elif type(data) is list:
|
||||
drawing = data
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
# Compute box
|
||||
width = max(chain(*[d['x'] for d in drawing])) + 10
|
||||
height = max(chain(*[d['y'] for d in drawing])) + 10
|
||||
width = int(round(max(chain(*[d['x'] for d in drawing])))) + 10
|
||||
height = int(round(max(chain(*[d['y'] for d in drawing])))) + 10
|
||||
|
||||
# Draw image
|
||||
im = Image.new("RGBA", (width*AA, height*AA))
|
||||
im = Image.new("RGBA", (width * AA, height * AA))
|
||||
draw = ImageDraw.Draw(im)
|
||||
for line in drawing:
|
||||
len_line = len(line['x'])
|
||||
points = [(line['x'][i]*AA, line['y'][i]*AA)
|
||||
points = [(line['x'][i] * AA, line['y'][i] * AA)
|
||||
for i in range(0, len_line)]
|
||||
draw.line(points, fill="#000", width=2*AA)
|
||||
draw.line(points, fill="#000", width=2 * AA)
|
||||
im = ImageOps.expand(im)
|
||||
# Smart crop
|
||||
bbox = im.getbbox()
|
||||
|
||||
@@ -11,7 +11,7 @@ from django.core import validators
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from jsignature.settings import JSIGNATURE_DEFAULT_CONFIG
|
||||
|
||||
JSIGNATURE_EMPTY_VALUES = validators.EMPTY_VALUES + ('[]', )
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pillow
|
||||
pyquery
|
||||
pyquery<1.4.2; python_version<="2.7"
|
||||
pyquery>=1.4.2; python_version>"2.7"
|
||||
|
||||
4
setup.py
4
setup.py
@@ -5,7 +5,7 @@ here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
setup(
|
||||
name='django-jsignature',
|
||||
version='0.10',
|
||||
version='0.11',
|
||||
author='Florent Lebreton',
|
||||
author_email='florent.lebreton@makina-corpus.com',
|
||||
url='https://github.com/fle/django-jsignature',
|
||||
@@ -14,7 +14,7 @@ setup(
|
||||
long_description=open(os.path.join(here, 'README.rst')).read() + '\n\n' +
|
||||
open(os.path.join(here, 'CHANGES')).read(),
|
||||
license='LPGL, see LICENSE file.',
|
||||
install_requires=['Django>=1.11', 'pillow'],
|
||||
install_requires=['Django>=1.11', 'pillow', 'pyquery>=1.4.2'],
|
||||
packages=find_packages(exclude=['example_project*', 'tests']),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
|
||||
@@ -2,6 +2,8 @@ import os
|
||||
|
||||
DEBUG = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
SECRET_KEY = 'thisisntactuallysecretatall'
|
||||
|
||||
12
tests/test_faulty_signature.py
Normal file
12
tests/test_faulty_signature.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import json
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
from jsignature.templatetags.jsignature_filters import signature_base64
|
||||
|
||||
FAULTY_SIGNATURE = [{"x": [120.00675156801722, 116.11464070635179, 114.16858527551909], "y": [83.0316983821957, 76.54484694608666, 224.44505968937275]}, {"x": [161.52260075911508, 165.4147116207805, 173.84761848772226, 184.2265807854967, 201.0923945193802], "y": [84.97775381302841, 79.78827266414118, 72.00405094081033, 62.922458930257676, 56.43560749414864]}]
|
||||
DUMMY_STR_VALUE = json.dumps(FAULTY_SIGNATURE)
|
||||
|
||||
class TemplateFilterFailedTest(SimpleTestCase):
|
||||
def test_throw_error(self):
|
||||
output = signature_base64(DUMMY_STR_VALUE)
|
||||
@@ -24,13 +24,13 @@ class JSignatureFieldTest(SimpleTestCase):
|
||||
def test_to_python_correct_value_python(self):
|
||||
f = JSignatureField()
|
||||
val = [{"x": [1, 2], "y": [3, 4]}]
|
||||
self.assertEquals(val, f.to_python(val))
|
||||
self.assertEqual(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]}]'
|
||||
self.assertEquals(val, f.to_python(val_str))
|
||||
self.assertEqual(val, f.to_python(val_str))
|
||||
|
||||
def test_to_python_incorrect_value(self):
|
||||
f = JSignatureField()
|
||||
@@ -47,7 +47,7 @@ class JSignatureFieldTest(SimpleTestCase):
|
||||
val = [{"x": [1, 2], "y": [3, 4]}]
|
||||
val_prep = f.get_prep_value(val)
|
||||
self.assertIsInstance(val_prep, string_types)
|
||||
self.assertEquals(val, json.loads(val_prep))
|
||||
self.assertEqual(val, json.loads(val_prep))
|
||||
|
||||
def test_get_prep_value_correct_values_json(self):
|
||||
f = JSignatureField()
|
||||
@@ -55,7 +55,7 @@ class JSignatureFieldTest(SimpleTestCase):
|
||||
val_str = '[{"x":[1,2], "y":[3,4]}]'
|
||||
val_prep = f.get_prep_value(val_str)
|
||||
self.assertIsInstance(val_prep, string_types)
|
||||
self.assertEquals(val, json.loads(val_prep))
|
||||
self.assertEqual(val, json.loads(val_prep))
|
||||
|
||||
def test_get_prep_value_incorrect_values(self):
|
||||
f = JSignatureField()
|
||||
|
||||
@@ -19,7 +19,7 @@ class JSignatureFormFieldTest(SimpleTestCase):
|
||||
def test_to_python_correct_values(self):
|
||||
f = JSignatureField()
|
||||
val = '[{"x":[1,2], "y":[3,4]}]'
|
||||
self.assertEquals([{'x': [1, 2], 'y': [3, 4]}], f.to_python(val))
|
||||
self.assertEqual([{'x': [1, 2], 'y': [3, 4]}], f.to_python(val))
|
||||
|
||||
def test_to_python_incorrect_values(self):
|
||||
f = JSignatureField()
|
||||
|
||||
@@ -25,7 +25,7 @@ class JSignatureWidgetTest(SimpleTestCase):
|
||||
self.assertIn('jSignature.min.js', media_js_str)
|
||||
self.assertIn('django_jsignature.js', media_js_str)
|
||||
media_css = list(media.render_css())
|
||||
self.assertEquals([], media_css)
|
||||
self.assertEqual([], media_css)
|
||||
|
||||
@override_settings(JSIGNATURE_JQUERY='admin')
|
||||
def test_media_in_admin(self):
|
||||
@@ -43,10 +43,10 @@ class JSignatureWidgetTest(SimpleTestCase):
|
||||
|
||||
def test_init(self):
|
||||
w = JSignatureWidget()
|
||||
self.assertEquals({}, w.jsignature_attrs)
|
||||
self.assertEqual({}, w.jsignature_attrs)
|
||||
given_attrs = {'width': 300, 'height': 100}
|
||||
w = JSignatureWidget(jsignature_attrs=given_attrs)
|
||||
self.assertEquals(given_attrs, w.jsignature_attrs)
|
||||
self.assertEqual(given_attrs, w.jsignature_attrs)
|
||||
|
||||
def test_build_jsignature_id(self):
|
||||
w = JSignatureWidget()
|
||||
@@ -69,7 +69,7 @@ class JSignatureWidgetTest(SimpleTestCase):
|
||||
val = [{"x": [1, 2], "y": [3, 4]}]
|
||||
val_prep = w.prep_value(val)
|
||||
self.assertIsInstance(val_prep, string_types)
|
||||
self.assertEquals(val, json.loads(val_prep))
|
||||
self.assertEqual(val, json.loads(val_prep))
|
||||
|
||||
def test_prep_value_correct_values_json(self):
|
||||
w = JSignatureWidget()
|
||||
@@ -77,7 +77,7 @@ class JSignatureWidgetTest(SimpleTestCase):
|
||||
val_str = '[{"x":[1,2], "y":[3,4]}]'
|
||||
val_prep = w.prep_value(val_str)
|
||||
self.assertIsInstance(val_prep, string_types)
|
||||
self.assertEquals(val, json.loads(val_prep))
|
||||
self.assertEqual(val, json.loads(val_prep))
|
||||
|
||||
def test_prep_value_incorrect_values(self):
|
||||
w = JSignatureWidget()
|
||||
|
||||
26
tox.ini
26
tox.ini
@@ -1,23 +1,25 @@
|
||||
[tox]
|
||||
envlist =
|
||||
{py27,py35,py36}-django111,
|
||||
{py35,py36,py37,py38}-django22,
|
||||
{py36,py37,py38}-django{30,master}
|
||||
{py36,py37,py38,py39,py310}-django22,
|
||||
{py36,py37,py38,py39,py310}-django32,
|
||||
{py38,py39,py310}-django{40,master},
|
||||
py310-djangomaster
|
||||
|
||||
[testenv]
|
||||
deps=
|
||||
django111: Django>=1.11,<2.0
|
||||
django22: Django>=2.2,<3.0
|
||||
django30: Django>=3.0,<4.0
|
||||
djangomaster: https://github.com/django/django/archive/master.tar.gz
|
||||
django32: Django>=3.2,<4.0
|
||||
django40: Django>=4.0,<4.1
|
||||
djangomaster: https://github.com/django/django/archive/main.tar.gz
|
||||
-r requirements.txt
|
||||
coverage
|
||||
|
||||
commands= coverage run ./runtests.py
|
||||
|
||||
[travis:env]
|
||||
DJANGO =
|
||||
1.11: django111
|
||||
2.2: django22
|
||||
3.0: django30
|
||||
master: djangomaster
|
||||
[gh-actions]
|
||||
python =
|
||||
3.6: py36-django{22,32}
|
||||
3.7: py37-django{22,32}
|
||||
3.8: py38-django{22,32,40}
|
||||
3.9: py39-django{22,32,40}
|
||||
3.10: py310-django{22,32,40,master}
|
||||
|
||||
Reference in New Issue
Block a user