Skip to content

Commit e27ad9a

Browse files
authored
Merge pull request #80 from jproffitt/master
Support django 1.11
2 parents 9b223bc + bb135ae commit e27ad9a

File tree

10 files changed

+109
-23
lines changed

10 files changed

+109
-23
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ _build/
99
*.pyc
1010
test.db
1111
example/example/settings/local.py
12+
/.idea

.travis.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,27 @@ python:
44
- 2.7
55
- 3.4
66
- 3.5
7+
- 3.6
78

89
env:
910
- DJANGO='Django>=1.8,<1.9'
11+
- DJANGO='Django>=1.9,<1.10'
1012
- DJANGO='Django>=1.10,<1.11'
13+
- DJANGO='Django>=1.11,<2.0'
1114

1215
install:
1316
- pip install $DJANGO
1417
- pip install coverage coveralls
1518

1619
script: coverage run setup.py test
1720

21+
matrix:
22+
exclude:
23+
- python: 3.6
24+
env: DJANGO='Django>=1.8,<1.9'
25+
- python: 3.6
26+
env: DJANGO='Django>=1.9,<1.10'
27+
- python: 3.6
28+
env: DJANGO='Django>=1.10,<1.11'
29+
1830
after_success: coveralls

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
# Django-parsley changelog
22

3+
## 0.7
4+
5+
- Added support for django 1.10 and 1.11
6+
- Dropped support for django 1.3 - 1.7
7+
- Fixed issue where django version would be forced to 1.8 when installing django-parsley. More details <a href="https://github.com/agiliq/Django-parsley/issues/72" target="_blank">here</a>.
8+
- Added parsleyfy template tag
9+
310
## 0.6
411

512
- Added checkbox and radio button validation support.
613
- Updated parsley.js, included with this library, to 2.0.7
714
- Changed error message attributes to confirm with parsley.js 2.x. More details <a href="https://github.com/agiliq/Django-parsley/issues/56" target="_blank">here</a>.
8-
- Changed RegexField attributes to confirm with parsley.js 2.x. More details <a href="https://github.com/agiliq/Django-parsley/issues/46" target="_blank">here</a>.
15+
- Changed RegexField attributes to confirm with parsley.js 2.x. More details <a href="https://github.com/agiliq/Django-parsley/issues/46" target="_blank">here</a>.

parsley/decorators.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import re
2+
import types
23

34
from django import forms
45
from parsley.widgets import ParsleyChoiceFieldRendererMixin
@@ -24,10 +25,25 @@ def update_widget_attrs(field, prefix='data'):
2425
attrs = field.widget.attrs
2526
if field.required:
2627
if isinstance(field.widget, forms.widgets.RadioSelect):
27-
# Use a mixin, to try and support non-standard renderers if possible
28-
class ParsleyChoiceFieldRenderer(ParsleyChoiceFieldRendererMixin, field.widget.renderer):
29-
parsley_namespace = prefix
30-
field.widget.renderer = ParsleyChoiceFieldRenderer
28+
try:
29+
# django >= 1.11
30+
original_create_option = field.widget.create_option
31+
32+
def new_create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
33+
if index == len(self.choices) - 1:
34+
attrs = attrs or {}
35+
attrs["{prefix}-required".format(prefix=prefix)] = "true"
36+
37+
return original_create_option(name, value, label, selected, index, subindex, attrs)
38+
39+
field.widget.create_option = types.MethodType(new_create_option, field.widget)
40+
except AttributeError:
41+
# django < 1.11
42+
43+
# Use a mixin, to try and support non-standard renderers if possible
44+
class ParsleyChoiceFieldRenderer(ParsleyChoiceFieldRendererMixin, field.widget.renderer):
45+
parsley_namespace = prefix
46+
field.widget.renderer = ParsleyChoiceFieldRenderer
3147
else:
3248
attrs["{prefix}-required".format(prefix=prefix)] = "true"
3349
error_message = field.error_messages.get('required', None)
@@ -66,6 +82,7 @@ class ParsleyChoiceFieldRenderer(ParsleyChoiceFieldRendererMixin, field.widget.r
6682
if error_message:
6783
attrs["{prefix}-type-message".format(field_type, prefix=prefix)] = error_message
6884

85+
6986
def parsley_form(form):
7087
prefix = getattr(getattr(form, 'Meta', None), 'parsley_namespace', 'data-parsley')
7188
for _, field in form.fields.items():
@@ -84,8 +101,12 @@ def parsley_form(form):
84101
attrs["{prefix}-%s".format(prefix=prefix) % key] = value
85102
return form
86103

104+
87105
def parsleyfy(klass):
88-
"A decorator to add {prefix}-* attributes to your form.fields"
106+
"""
107+
A decorator to add {prefix}-* attributes to your form.fields
108+
"""
109+
89110
old_init = klass.__init__
90111

91112
def new_init(self, *args, **kwargs):

parsley/templatetags/parsley.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
from django import template
1+
from django import template, VERSION
2+
23
from ..decorators import parsley_form
34

45
register = template.Library()
56

7+
if VERSION[:2] >= (1, 9):
8+
# in django 1.9 and above, the simple_tag can do assignment
9+
tag_decorator = register.simple_tag
10+
else:
11+
# django 1.8 and below needs the assignment_tag
12+
tag_decorator = register.assignment_tag
13+
614

7-
@register.assignment_tag()
15+
@tag_decorator()
816
def parsleyfy(form):
917
return parsley_form(form)

parsley/tests/forms.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77

88
class TextForm(forms.Form):
9-
"A simple form"
109
name = forms.CharField(required=True,)
1110
university = forms.CharField(required=False)
1211

parsley/tests/tests.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import six
33

44
from django import forms
5+
from django.template import Context, Template
56
from django.test import TestCase
67
from django.utils.translation import ugettext_lazy as _
78

8-
from parsley.decorators import parsleyfy
9+
from parsley.decorators import parsleyfy, parsley_form
910

1011
from .forms import (TextForm, TextForm2, FieldTypeForm, ExtraDataForm,
1112
ExtraDataMissingFieldForm, FormWithWidgets, StudentModelForm,
@@ -35,8 +36,7 @@ def test_basic(self):
3536
form = TextForm()
3637
self.assertEqual(form.fields["name"].widget.attrs, {})
3738
self.assertEqual(form.fields["university"].widget.attrs, {})
38-
ParsleyForm = parsleyfy(TextForm)
39-
form = ParsleyForm()
39+
form = parsley_form(TextForm())
4040
self.assertAttrsEqual(form.fields["name"].widget.attrs, {
4141
"data-parsley-required": "true",
4242
"data-parsley-required-message": _("This field is required.")
@@ -117,17 +117,17 @@ def test_widgets(self):
117117
class TestMetadata(ParsleyTestCase):
118118
def test_docstring(self):
119119
form1 = TextForm()
120-
form2 = parsleyfy(TextForm)()
120+
form2 = parsley_form(TextForm())
121121
self.assertEqual(form1.__doc__, form2.__doc__)
122122

123123
def test_module(self):
124124
form1 = TextForm()
125-
form2 = parsleyfy(TextForm)()
125+
form2 = parsley_form(TextForm())
126126
self.assertEqual(form1.__module__, form2.__module__)
127127

128128
def test_name(self):
129129
form1 = TextForm()
130-
form2 = parsleyfy(TextForm)()
130+
form2 = parsley_form(TextForm())
131131
self.assertEqual(form1.__class__.__name__, form2.__class__.__name__)
132132

133133

@@ -270,14 +270,41 @@ def test_override_default_message(self):
270270
"data-parsley-required-message": "Favorite color is required"
271271
})
272272

273+
273274
class TestCustomPrefix(TestCase):
274275

275276
def test_default_prefix(self):
276-
form = TextForm()
277+
form = TextForm2()
277278
attrs = form.fields['name'].widget.attrs
278279
self.assertTrue('data-parsley-required' in attrs)
279280

280281
def test_custom_prefix(self):
281282
form = CustomPrefixForm()
282283
attrs = form.fields['name'].widget.attrs
283284
self.assertTrue('custom-required' in attrs)
285+
286+
287+
class TemplateTagTest(ParsleyTestCase):
288+
def test_basic(self):
289+
"""
290+
Tests that parsleyfy will work using the template tag
291+
"""
292+
293+
template = Template("{% load parsley %}")
294+
form = TextForm()
295+
context = Context({'form': form})
296+
template.render(context)
297+
298+
self.assertEqual(context['form'].fields["name"].widget.attrs, {})
299+
self.assertEqual(context['form'].fields["university"].widget.attrs, {})
300+
301+
template = Template("{% load parsley %}{% parsleyfy form as form %}")
302+
form = TextForm()
303+
context = Context({'form': form})
304+
template.render(context)
305+
306+
self.assertAttrsEqual(context['form'].fields["name"].widget.attrs, {
307+
"data-parsley-required": "true",
308+
"data-parsley-required-message": _("This field is required.")
309+
})
310+
self.assertEqual(context['form'].fields["university"].widget.attrs, {})

runtests.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from optparse import OptionParser
77

88
from django.conf import settings
9+
from django.test.runner import DiscoverRunner
910

1011
# For convenience configure settings if they are not pre-configured or if we
1112
# haven't been provided settings to use by environment variable.
@@ -19,16 +20,20 @@
1920
INSTALLED_APPS=[
2021
'parsley',
2122
],
22-
STATIC_URL = "/static/",
23+
STATIC_URL="/static/",
24+
TEMPLATES=[
25+
{
26+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
27+
'APP_DIRS': True,
28+
},
29+
]
2330
)
2431

2532
# Setup Django 1.7+ (AppRegistryNotReady).
2633
import django
2734
if hasattr(django, 'setup'):
2835
django.setup()
2936

30-
from django.test.runner import DiscoverRunner
31-
3237

3338
def runtests(*test_args, **kwargs):
3439
if not test_args:

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
VERSION = '0.6'
1+
VERSION = '0.7'
22

33
import os
44
import sys
55
from fnmatch import fnmatchcase
66
from distutils.util import convert_path
77
from setuptools import setup, find_packages
88

9+
910
def read(fname):
1011
try:
1112
return open(os.path.join(os.path.dirname(__file__), fname)).read()

tox.ini

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[tox]
2-
envlist = py{27,34,35}-dj{18,19}
2+
envlist =
3+
py{27,34,35}-dj{18,19,110}
4+
py{27,34,35,36}-dj{111}
35
skipsdist = True
46

57

@@ -9,7 +11,10 @@ basepython =
911
py27: python2.7
1012
py34: python3.4
1113
py35: python3.5
14+
py36: python3.6
1215
deps =
1316
coverage>=4
14-
dj18: django==1.8.13
15-
dj19: django==1.9.7
17+
dj18: django==1.8.18
18+
dj19: django==1.9.13
19+
dj110: django==1.10.7
20+
dj111: django==1.11.1

0 commit comments

Comments
 (0)