Skip to content
Browse files

- Add ``colander.ContainsOnly`` and ``colander.url`` validators.

  • Loading branch information...
1 parent f6a14d2 commit 02f81f239fd7b089ae55779693009fd5cbdfe273 @mcdonc mcdonc committed Jan 29, 2013
Showing with 77 additions and 0 deletions.
  1. +8 −0 CHANGES.txt
  2. +24 −0 colander/__init__.py
  3. +39 −0 colander/tests/test_colander.py
  4. +6 −0 docs/api.rst
View
8 CHANGES.txt
@@ -1,3 +1,11 @@
+Next release
+------------
+
+Features
+~~~~~~~~
+
+- Add ``colander.ContainsOnly`` and ``colander.url`` validators.
+
1.0a1 (2013-01-10)
------------------
View
24 colander/__init__.py
@@ -1,3 +1,5 @@
+# coding=utf-8
+
import datetime
import decimal
import time
@@ -356,6 +358,24 @@ def __call__(self, node, value):
mapping={'val':value, 'choices':choices})
raise Invalid(node, err)
+class ContainsOnly(object):
+ """ Validator which succeeds if the value passed to is a sequence and each
+ element in the sequence is also in the sequence passed as ``acceptable``
+ """
+ err_template = _(
+ 'One or more of the choices you made was not acceptable'
+ )
+ def __init__(self, acceptable):
+ self.acceptable = set(acceptable)
+
+ def __call__(self, node, value):
+ if not set(value).issubset(self.acceptable):
+ err = _(
+ self.err_template,
+ mapping = {'val':value, 'acceptable':self.acceptable}
+ )
+ raise Invalid(node, err)
+
def luhnok(node, value):
""" Validator which checks to make sure that the value passes a luhn
mod-10 checksum (credit cards). ``value`` must be a string, not an
@@ -386,6 +406,10 @@ def _luhnok(value):
sum = sum + digit
return sum
+URL_REGEX = r"""(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))""" # "emacs!
+
+url = Regex(URL_REGEX, _('Must be a URL'))
+
class SchemaType(object):
""" Base class for all schema types """
def flatten(self, node, appstruct, prefix='', listitem=False):
View
39 colander/tests/test_colander.py
@@ -408,6 +408,30 @@ def test_failure(self):
e = invalid_exc(validator, None, None)
self.assertEqual(e.msg.interpolate(), '"None" is not one of 1, 2')
+class TestContainsOnly(unittest.TestCase):
+ def _makeOne(self, values):
+ from colander import ContainsOnly
+ return ContainsOnly(values)
+
+ def test_success(self):
+ validator = self._makeOne([1])
+ self.assertEqual(validator(None, [1]), None)
+
+ def test_failure(self):
+ validator = self._makeOne([1])
+ e = invalid_exc(validator, None, [2])
+ self.assertEqual(
+ e.msg.interpolate(),
+ 'One or more of the choices you made was not acceptable'
+ )
+
+ def test_failure_with_custom_error_template(self):
+ validator = self._makeOne([1])
+ from colander import _
+ validator.err_template = _('${val}: ${acceptable}')
+ e = invalid_exc(validator, None, [2])
+ self.assertTrue('[2]' in e.msg.interpolate())
+
class Test_luhnok(unittest.TestCase):
def _callFUT(self, node, value):
from colander import luhnok
@@ -432,6 +456,21 @@ def test_success(self):
val = '4111111111111111'
self.assertFalse(self._callFUT(None, val))
+class Test_url_validator(unittest.TestCase):
+ def _callFUT(self, val):
+ from colander import url
+ return url(None, val)
+
+ def test_it_success(self):
+ val = 'http://example.com'
+ result = self._callFUT(val)
+ self.assertEqual(result, None)
+
+ def test_it_failure(self):
+ val = 'not-a-url'
+ from colander import Invalid
+ self.assertRaises(Invalid, self._callFUT, val)
+
class TestSchemaType(unittest.TestCase):
def _makeOne(self, *arg, **kw):
from colander import SchemaType
View
6 docs/api.rst
@@ -59,6 +59,8 @@ Validators
.. autoclass:: OneOf
+ .. autoclass:: ContainsOnly
+
.. autoclass:: Function
.. autoclass:: Regex
@@ -67,6 +69,10 @@ Validators
.. autofunction:: luhnok
+ .. attribute:: url
+
+ A validator which ensures the value is a URL (via regex).
+
Types
~~~~~

0 comments on commit 02f81f2

Please sign in to comment.
Something went wrong with that request. Please try again.