Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ MANIFEST
dist/
build/
misc/
venv/
.vscode/
24 changes: 21 additions & 3 deletions tests/test_autoattrmeta.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from wtforms.validators import (
InputRequired,
Length,
NumberRange,
)

from . import (
Expand Down Expand Up @@ -40,21 +41,38 @@ def test_invalid(self):

def test_minmax(self):
# min
form = get_form(validators=[Length(min=3), ], use_meta=True)
form = get_form(validators=[NumberRange(min=3), ], use_meta=True)
field = get_field(form)
self.assertEqual(field.attrs['min'], '3')
self.assertNotIn('max', field.attrs)
# max
form = get_form(validators=[Length(max=8), ], use_meta=True)
form = get_form(validators=[NumberRange(max=8), ], use_meta=True)
field = get_field(form)
self.assertEqual(field.attrs['max'], '8')
self.assertNotIn('min', field.attrs)
# min + max
form = get_form(validators=[Length(min=3, max=8), ], use_meta=True)
form = get_form(validators=[NumberRange(min=3, max=8), ], use_meta=True)
field = get_field(form)
self.assertEqual(field.attrs['min'], '3')
self.assertEqual(field.attrs['max'], '8')

def test_minmaxlength(self):
# min
form = get_form(validators=[Length(min=3), ], use_meta=True)
field = get_field(form)
self.assertEqual(field.attrs['minlength'], '3')
self.assertNotIn('maxlength', field.attrs)
# max
form = get_form(validators=[Length(max=8), ], use_meta=True)
field = get_field(form)
self.assertEqual(field.attrs['maxlength'], '8')
self.assertNotIn('minlength', field.attrs)
# min + max
form = get_form(validators=[Length(min=3, max=8), ], use_meta=True)
field = get_field(form)
self.assertEqual(field.attrs['minlength'], '3')
self.assertEqual(field.attrs['maxlength'], '8')

def test_title(self):
form = get_form(description='Some help text', use_meta=True)
field = get_field(form)
Expand Down
60 changes: 56 additions & 4 deletions tests/test_get_html5_kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from wtforms_html5 import (
MINMAX_VALIDATORS,
MINMAXLENGTH_VALIDATORS,
get_html5_kwargs,
)

Expand Down Expand Up @@ -140,7 +141,7 @@ def test_auto_invalid(self):
self.assertTrue(form.validate())
res = get_html5_kwargs(form.test_field)
exp = {
'min': 5,
'minlength': 5,
}
self.assertEqual(res, exp)
# invalid input
Expand All @@ -152,7 +153,7 @@ def test_auto_invalid(self):
res = get_html5_kwargs(form.test_field)
exp = {
'class': 'invalid',
'min': 5,
'minlength': 5,
}
self.assertEqual(res, exp)

Expand All @@ -166,7 +167,7 @@ def test_auto_invalid_no_overwrite(self):
res = get_html5_kwargs(form.test_field, {'class': 'test'})
exp = {
'class': 'invalid test',
'min': 5,
'minlength': 5,
}
self.assertEqual(res, exp)
# add to class_
Expand All @@ -178,7 +179,7 @@ def test_auto_invalid_no_overwrite(self):
res = get_html5_kwargs(form.test_field, {'class_': 'test zwo'})
exp = {
'class': 'invalid test zwo',
'min': 5,
'minlength': 5,
}
self.assertEqual(res, exp)

Expand Down Expand Up @@ -232,3 +233,54 @@ def test_auto_minmax_no_overwrite(self):
form = get_form(validators=[Validator(max=5, min=2)])
res = get_html5_kwargs(form.test_field, render_kw)
self.assertEqual(res, exp)


@SkipIfNoSubtests
def test_auto_minmaxlength(self):
for Validator in MINMAXLENGTH_VALIDATORS:
with self.subTest(Validator=Validator):
# minlength
form = get_form(validators=[Validator(min=5)])
res = get_html5_kwargs(form.test_field)
exp = {
'minlength': 5,
}
self.assertEqual(res, exp)
# maxlength
form = get_form(validators=[Validator(max=5)])
res = get_html5_kwargs(form.test_field)
exp = {
'maxlength': 5,
}
self.assertEqual(res, exp)
# minlength + maxlength
form = get_form(validators=[Validator(max=5, min=2)])
res = get_html5_kwargs(form.test_field)
exp = {
'minlength': 2,
'maxlength': 5,
}
self.assertEqual(res, exp)


@SkipIfNoSubtests
def test_auto_minmaxlength_no_overwrite(self):
render_kw = {
'minlength': 10,
'maxlength': 20,
}
exp = render_kw.copy()
for Validator in MINMAXLENGTH_VALIDATORS:
with self.subTest(Validator=Validator):
# minlength
form = get_form(validators=[Validator(min=5)])
res = get_html5_kwargs(form.test_field, render_kw)
self.assertEqual(res, exp)
# maxlength
form = get_form(validators=[Validator(max=5)])
res = get_html5_kwargs(form.test_field, render_kw)
self.assertEqual(res, exp)
# minlength + maxlength
form = get_form(validators=[Validator(max=5, min=2)])
res = get_html5_kwargs(form.test_field, render_kw)
self.assertEqual(res, exp)
45 changes: 41 additions & 4 deletions wtforms_html5.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@

>>> f = form.test_field()
>>> exp = (
... '<input id="test_field" max="12" min="3" name="test_field" required '
... 'title="Just a test field." type="text" value="">'
... '<input id="test_field" maxlength="12" minlength="3" name="test_field" '
... 'required title="Just a test field." type="text" value="">'
... )
>>> assert f == exp

Expand All @@ -86,7 +86,7 @@
>>> form.validate()
False
>>> exp = (
... '<input class="invalid" id="test_field" max="12" min="3" '
... '<input class="invalid" id="test_field" maxlength="12" minlength="3" '
... 'name="test_field" required title="Just a test field." type="text" '
... 'value="">'
... )
Expand Down Expand Up @@ -116,10 +116,13 @@


MINMAX_VALIDATORS = (
Length,
NumberRange,
)

MINMAXLENGTH_VALIDATORS = (
Length,
)


def set_required(field, render_kw=None, force=False):
"""
Expand Down Expand Up @@ -190,6 +193,38 @@ def set_minmax(field, render_kw=None, force=False):
return render_kw


def set_minmaxlength(field, render_kw=None, force=False):
"""
Returns *render_kw* with *minlength* and *maxlength* set if validators use
them.

Sets *minlength* and / or *maxlength* keys if there is a `Length` validator
present and the corresponding parameters (i.e. `min` or `max`) are set.

..note::

This won't change keys already present unless *force* is used.

"""
if render_kw is None:
render_kw = {}
for validator in field.validators:
if isinstance(validator, MINMAXLENGTH_VALIDATORS):
if 'minlength' not in render_kw or force:
v_min = getattr(validator, 'min', -1)
if v_min not in (-1, None):
render_kw['minlength'] = v_min
if 'maxlength' not in render_kw or force:
v_max = getattr(validator, 'max', -1)
if v_max not in (-1, None):
render_kw['maxlength'] = v_max
# Inconsistency: Length validator uses min and max for specifying
# length limits while HTML5 uses minlength and
# maxlength (attributes of input element) for the
# same purpose.
return render_kw


def set_title(field, render_kw=None):
"""
Returns *render_kw* with *min* and *max* set if required.
Expand Down Expand Up @@ -250,6 +285,8 @@ def get_html5_kwargs(field, render_kw=None, force=False):
kwargs = set_required(field, kwargs, force) # is field required?
kwargs = set_invalid(field, kwargs) # is field invalid?
kwargs = set_minmax(field, kwargs, force) # check validators for min/max
kwargs = set_minmaxlength(field, kwargs, force)
# check validators for minlength/maxlength
kwargs = set_title(field, kwargs) # missing tile?
return kwargs

Expand Down