Repository: level12/keg-elements

Issue:
Add an alphanumeric validator
Currently there is no validator for alphanumeric (Characters and numbers only). It would be nice to have one for reuse.

Discussion:

Patch:
diff --git a/docker-entry b/docker-entry
index b30f472..f933af4 100644
--- a/docker-entry
+++ b/docker-entry
@@ -22,7 +22,7 @@ export PIP_DISABLE_PIP_VERSION_CHECK=1
 # b/c it gives me control over what version of tox I'm using without having to rebuild the
 # docker image.
 python3.5 -m pip install --upgrade --force-reinstall \
-    --quiet --use-wheel --no-index --find-links=requirements/wheelhouse tox
+    --quiet --no-index --find-links=requirements/wheelhouse tox
 
 # Run the tests using our target python version.
 #
diff --git a/keg_elements/forms/validators.py b/keg_elements/forms/validators.py
index 35be03d..d060dc5 100644
--- a/keg_elements/forms/validators.py
+++ b/keg_elements/forms/validators.py
@@ -4,6 +4,34 @@ from decimal import Decimal
 
 import jinja2
 from wtforms import ValidationError
+import re
+
+
+class ValidateAlphaNumeric(object):
+    """
+        A validator to make sure than a form field contains only alphanumeric data
+
+        usage example:
+            import keg_elements.forms.validators as validators
+
+            wtforms.StringField('AlphaNumeric', validators=[
+                            validators.ValidateAlphaNumeric()
+                        ])
+    """
+    regex = re.compile(r'^[a-zA-Z0-9]+$')
+
+    def __init__(self, message=None):
+        self.message = message
+
+    def __call__(self, form, field):
+        value = field.data
+
+        message = self.message
+        if message is None:
+            message = field.gettext("Must only contain alphanumeric data.")
+
+        if not self.regex.match(value):
+            raise ValidationError(message)
 
 
 def numeric(form, field):


Test patch:
diff --git a/keg_elements/tests/test_forms/test_validators.py b/keg_elements/tests/test_forms/test_validators.py
index e390e5d..93c4a9f 100644
--- a/keg_elements/tests/test_forms/test_validators.py
+++ b/keg_elements/tests/test_forms/test_validators.py
@@ -1,3 +1,4 @@
+# coding=utf-8
 import jinja2
 import pytest
 import wtforms
@@ -65,3 +66,58 @@ class TestUniqueValidator(object):
         assert str(exc.value) == (
             'Form must provide either `obj` or `_obj` property for uniqueness validation.'
         )
+
+
+class TestAlphaNumericValidator(object):
+
+    def test_alphanumeric(self):
+        message = 'Must only contain alphanumeric data.'
+
+        class AlphaNumericMockForm(wtforms.Form):
+            alpha_numeric_field = wtforms.StringField('AlphaNumeric', validators=[
+                validators.ValidateAlphaNumeric()
+            ])
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456asb')
+        form.validate()
+        assert form.errors == {}
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456')
+        form.validate()
+        assert form.errors == {}
+
+        form = AlphaNumericMockForm(alpha_numeric_field='abcd')
+        form.validate()
+        assert form.errors == {}
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456!')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456!')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='!212')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field=' ')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123dsaf4 ')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field=' 123afd4')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='1 23fdas4')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field=u'åfasdf')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]