@@ -21,6 +21,8 @@ Features
|
|||||||
- Add a ``missing_msg`` argument to ``SchemaNode``, allowing customization
|
- Add a ``missing_msg`` argument to ``SchemaNode``, allowing customization
|
||||||
of the error message used when the node is required and missing.
|
of the error message used when the node is required and missing.
|
||||||
|
|
||||||
|
- Add `NoneOf` validator wich succeeds if the value is none of the choices.
|
||||||
|
|
||||||
Bug Fixes
|
Bug Fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
@@ -443,6 +443,33 @@ class OneOf(object):
|
|||||||
mapping={'val':value, 'choices':choices})
|
mapping={'val':value, 'choices':choices})
|
||||||
raise Invalid(node, err)
|
raise Invalid(node, err)
|
||||||
|
|
||||||
|
|
||||||
|
class NoneOf(object):
|
||||||
|
""" Validator which succeeds if the value passed to it is none of a
|
||||||
|
fixed set of values.
|
||||||
|
|
||||||
|
``msg_err`` is used to form the ``msg`` of the :exc:`colander.Invalid`
|
||||||
|
error when reporting a validation failure. If ``msg_err`` is specified,
|
||||||
|
it must be a string. The string may contain the replacement targets
|
||||||
|
``${choices}`` and ``${val}``, representing the set of forbidden values
|
||||||
|
and the provided value respectively.
|
||||||
|
"""
|
||||||
|
_MSG_ERR = _('"${val}" must not be one of ${choices}')
|
||||||
|
|
||||||
|
def __init__(self, choices, msg_err=_MSG_ERR):
|
||||||
|
self.forbidden = choices
|
||||||
|
self.msg_err = msg_err
|
||||||
|
|
||||||
|
def __call__(self, node, value):
|
||||||
|
if value not in self.forbidden:
|
||||||
|
return
|
||||||
|
|
||||||
|
choices = ', '.join(['%s' % x for x in self.forbidden])
|
||||||
|
err = _(self.msg_err, mapping={'val': value, 'choices': choices})
|
||||||
|
|
||||||
|
raise Invalid(node, err)
|
||||||
|
|
||||||
|
|
||||||
class ContainsOnly(object):
|
class ContainsOnly(object):
|
||||||
""" Validator which succeeds if the value passed to is a sequence and each
|
""" Validator which succeeds if the value passed to is a sequence and each
|
||||||
element in the sequence is also in the sequence passed as ``choices``.
|
element in the sequence is also in the sequence passed as ``choices``.
|
||||||
|
@@ -490,6 +490,22 @@ class TestOneOf(unittest.TestCase):
|
|||||||
e = invalid_exc(validator, None, None)
|
e = invalid_exc(validator, None, None)
|
||||||
self.assertEqual(e.msg.interpolate(), '"None" is not one of 1, 2')
|
self.assertEqual(e.msg.interpolate(), '"None" is not one of 1, 2')
|
||||||
|
|
||||||
|
|
||||||
|
class TestNoneOf(unittest.TestCase):
|
||||||
|
def _makeOne(self, values):
|
||||||
|
from colander import NoneOf
|
||||||
|
return NoneOf(values)
|
||||||
|
|
||||||
|
def test_success(self):
|
||||||
|
validator = self._makeOne([1, 2])
|
||||||
|
self.assertEqual(validator(None, 3), None)
|
||||||
|
|
||||||
|
def test_failure(self):
|
||||||
|
validator = self._makeOne([1, 2])
|
||||||
|
e = invalid_exc(validator, None, 2)
|
||||||
|
self.assertEqual(e.msg.interpolate(), '"2" must not be one of 1, 2')
|
||||||
|
|
||||||
|
|
||||||
class TestContainsOnly(unittest.TestCase):
|
class TestContainsOnly(unittest.TestCase):
|
||||||
def _makeOne(self, values):
|
def _makeOne(self, values):
|
||||||
from colander import ContainsOnly
|
from colander import ContainsOnly
|
||||||
|
@@ -64,6 +64,8 @@ Validators
|
|||||||
|
|
||||||
.. autoclass:: OneOf
|
.. autoclass:: OneOf
|
||||||
|
|
||||||
|
.. autoclass:: NoneOf
|
||||||
|
|
||||||
.. autoclass:: ContainsOnly
|
.. autoclass:: ContainsOnly
|
||||||
|
|
||||||
.. autoclass:: Function
|
.. autoclass:: Function
|
||||||
|
Reference in New Issue
Block a user