Repository: wtforms/wtforms
Pull request #410 (2018-06-12 22:28:26)

Validators are checked to see if they are callable and not a class
Following on from #298, this implements the requested changes in the PR.


Patch:
diff --git a/wtforms/fields/core.py b/wtforms/fields/core.py
index 3b39a61..65a1219 100644
--- a/wtforms/fields/core.py
+++ b/wtforms/fields/core.py
@@ -4,6 +4,7 @@ from copy import copy
 import datetime
 import decimal
 import itertools
+import inspect
 
 from markupsafe import Markup, escape
 
@@ -104,7 +105,9 @@ class Field(object):
         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()))
@@ -154,6 +157,18 @@ class Field(object):
         """
         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.
@@ -190,6 +205,9 @@ class Field(object):
         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)
@@ -340,6 +358,9 @@ class UnboundField(object):
         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(


Test patch:
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 26e107e..a150fb7 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -222,6 +222,20 @@ class FieldTest(TestCase):
         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):