Skip to content

Commit

Permalink
Merge pull request #410 from wtforms/field-callable-validator-check
Browse files Browse the repository at this point in the history
Validators are checked to see if they are callable and not a class
  • Loading branch information
ftm authored Jun 12, 2018
2 parents 014012a + 647113c commit 8d90488
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
14 changes: 14 additions & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,20 @@ def test_required_flag(self):
form = self.F()
self.assertEqual(form.b(), u'<input id="b" name="b" required type="text" value="">')

def test_check_validators(self):
v1 = "Not callable"
v2 = validators.DataRequired

with self.assertRaisesRegexp(TypeError, "{} is not a valid validator because "
"it is not callable".format(v1)):
Field(validators=[v1])


with self.assertRaisesRegexp(TypeError, "{} is not a valid validator because "
"it is a class, it should be an "
"instance".format(v2)):
Field(validators=[v2])


class PrePostTestField(StringField):
def pre_validate(self, form):
Expand Down
23 changes: 22 additions & 1 deletion wtforms/fields/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import datetime
import decimal
import itertools
import inspect

from markupsafe import Markup, escape

Expand Down Expand Up @@ -104,7 +105,9 @@ def __init__(self, label=None, validators=None, filters=tuple(),
self.name = _prefix + _name
self.short_name = _name
self.type = type(self).__name__
self.validators = validators or list(self.validators)

self.check_validators(validators)
self.validators = validators or self.validators

self.id = id or self.name
self.label = Label(self.id, label if label is not None else self.gettext(_name.replace('_', ' ').title()))
Expand Down Expand Up @@ -154,6 +157,18 @@ def __call__(self, **kwargs):
"""
return self.meta.render_field(self, kwargs)

@classmethod
def check_validators(cls, validators):
if validators is not None:
for validator in validators:
if not callable(validator):
raise TypeError("{} is not a valid validator because it is not "
"callable".format(validator))

if inspect.isclass(validator):
raise TypeError("{} is not a valid validator because it is a class, "
"it should be an instance".format(validator))

def gettext(self, string):
"""
Get a translation for the given message.
Expand Down Expand Up @@ -190,6 +205,9 @@ def validate(self, form, extra_validators=tuple()):
self.errors = list(self.process_errors)
stop_validation = False

# Check the type of extra_validators
self.check_validators(extra_validators)

# Call pre_validate
try:
self.pre_validate(form)
Expand Down Expand Up @@ -340,6 +358,9 @@ def __init__(self, field_class, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.creation_counter = UnboundField.creation_counter
validators = kwargs.get('validators')
if validators:
self.field_class.check_validators(validators)

def bind(self, form, name, prefix='', translations=None, **kwargs):
kw = dict(
Expand Down

0 comments on commit 8d90488

Please sign in to comment.