Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Trying to create an api for allowing a list of validators, deferred or n... #95

Open
wants to merge 1 commit into from

2 participants

Joe Dallago Tres Seaver
Joe Dallago
Collaborator

...ot.

Tres Seaver tseaver commented on the diff
colander/tests/test_colander.py
@@ -3363,6 +3385,11 @@ def __call__(self, node, value):
self.children and e.children.extend(self.children)
raise e
+from colander import deferred
Tres Seaver Owner
tseaver added a note

Please don't import the package at testcase module scope. Move this code inside a helper method, e.g.

def _makeDummyDeferredValidateor(self):
    from colander import deferred
    def _validator(node, kw):
        return DummyValidator(kw..get('message', 'Deferred'))
    return deferred(_validator)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Tres Seaver
Owner

Thank you for the patch. Can you please:

  • Add an entry to CHANGES.rst.
  • Add your name to CONTRIBUTORS.txt.
Tres Seaver
Owner

@jayd3e, could you merge with master and re-push as well?

Joe Dallago
Collaborator

Yeah definitely. I'll fit it in sometime this morning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 51 additions and 7 deletions.
  1. +24 −7 colander/__init__.py
  2. +27 −0 colander/tests/test_colander.py
31 colander/__init__.py
View
@@ -1813,10 +1813,10 @@ def deserialize(self, cstruct=null):
appstruct = self.typ.deserialize(self, cstruct)
if self.preparer is not None:
- # if the preparer is a function, call a single preparer
+ # if the preparer is a callable, call a single preparer
if hasattr(self.preparer, '__call__'):
appstruct = self.preparer(appstruct)
- # if the preparer is a list, call each separate preparer
+ # if the preparer is an iterable, call each separate preparer
elif is_nonstr_iter(self.preparer):
for preparer in self.preparer:
appstruct = preparer(appstruct)
@@ -1831,8 +1831,14 @@ def deserialize(self, cstruct=null):
return appstruct
if self.validator is not None:
- if not isinstance(self.validator, deferred): # unbound
- self.validator(self, appstruct)
+ # if the validator is not an iterable, turn it into one
+ if not is_nonstr_iter(self.validator):
+ self.validator = [self.validator]
+
+ for validator in self.validator:
+ if not isinstance(validator, deferred):
+ validator(self, appstruct)
+
return appstruct
def add(self, node):
@@ -1888,12 +1894,23 @@ def _bind(self, kw):
names = dir(self)
for k in names:
v = getattr(self, k)
- if isinstance(v, deferred):
- v = v(self, kw)
- setattr(self, k, v)
+ self._find_deferreds(kw, k, v)
if getattr(self, 'after_bind', None):
self.after_bind(self, kw)
+ def _find_deferreds(self, kw, k, v):
+ if isinstance(v, deferred):
+ v = v(self, kw)
+ setattr(self, k, v)
+ elif is_nonstr_iter(v):
+ new_v = []
+ for item in v:
+ if isinstance(v, deferred):
+ new_v.append(item(self, kw))
+ else:
+ new_v.append(item)
+ setattr(self, k, new_v)
+
def cstruct_children(self, cstruct):
""" Will call the node's type's ``cstruct_children`` method with this
node as a first argument, and ``cstruct`` as a second argument."""
27 colander/tests/test_colander.py
View
@@ -2242,6 +2242,28 @@ def test_deserialize_with_validator(self):
e = invalid_exc(node.deserialize, 1)
self.assertEqual(e.msg, 'Wrong')
+ def test_deserialize_deferred_validator(self):
+ typ = DummyType()
+ node = self._makeOne(typ, validator=DummyDeferredValidator)
+ node = node.bind(message='good')
+ e = invalid_exc(node.deserialize, 1)
+ self.assertEqual(e.msg, 'good')
+
+ def test_deserialize_all_with_deferred_validator(self):
+ typ = DummyType()
+ node = self._makeOne(typ, validator=[DummyDeferredValidator])
+ node = node.bind(message='good')
+ e = invalid_exc(node.deserialize, 1)
+ self.assertEqual(e.msg, 'good')
+
+ def test_deserialize_all_with_deferred_and_normal_validator(self):
+ typ = DummyType()
+ validator = DummyValidator(msg='Wrong')
+ node = self._makeOne(typ, validator=[DummyDeferredValidator, validator])
+ node = node.bind(message='good')
+ e = invalid_exc(node.deserialize, 1)
+ self.assertEqual(e.msg, 'good')
+
def test_deserialize_value_is_null_no_missing(self):
from colander import null
from colander import Invalid
@@ -3363,6 +3385,11 @@ def __call__(self, node, value):
self.children and e.children.extend(self.children)
raise e
+from colander import deferred
Tres Seaver Owner
tseaver added a note

Please don't import the package at testcase module scope. Move this code inside a helper method, e.g.

def _makeDummyDeferredValidateor(self):
    from colander import deferred
    def _validator(node, kw):
        return DummyValidator(kw..get('message', 'Deferred'))
    return deferred(_validator)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+@deferred
+def DummyDeferredValidator(node, kw):
+ return DummyValidator(kw.get('message', 'Deferred'))
+
class Uncooperative(object):
def __str__(self):
raise ValueError('I wont cooperate')
Something went wrong with that request. Please try again.