From c67b72e717bab632a37548cbd8486b24cd6e7ab3 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 2 Apr 2010 05:20:54 +0000 Subject: [PATCH] Remove the unknown/partial keyword parameters from serialize/deserialize; make pserialize/pdeserialize use unknown='ignore', partial=True. --- CHANGES.txt | 4 -- colander/__init__.py | 104 ++++++++++++++++++------------------------- colander/tests.py | 73 ++++++++++-------------------- 3 files changed, 67 insertions(+), 114 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0252ff7..2035d8a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -20,10 +20,6 @@ Next release - Allow ``colander.Mapping`` type to accept a new constructor argument: ``partial``. -- Allow ``colander.Mapping.serialize`` and - ``colander.Mapping.deserialize`` methods to accept ``unknown`` and - ``partial`` keyword arguments. - - New interface methods required by types and schema nodes: ``pserialize`` and ``pdeserialize``. These partially serialize or partially deserialize a value (the definition of "partial" is up to diff --git a/colander/__init__.py b/colander/__init__.py index 8dfc4cd..71ee952 100644 --- a/colander/__init__.py +++ b/colander/__init__.py @@ -205,6 +205,8 @@ class Mapping(Type): The constructor of this type accepts two extra optional keyword arguments that other types do not: ``unknown`` and ``partial``. + Attributes of the same name can be set on a type instance to + control the behavior after construction. unknown ``unknown`` controls the behavior of this type when an unknown @@ -224,6 +226,10 @@ class Mapping(Type): Default: ``ignore``. + Note that the ``pserialize`` and ``pdeserialize`` methods of + this type will override this behavior, behaving as if + ``unknown`` is ``ignore`` for the duration of those method calls. + partial ``partial`` controls the behavior of this type when a schema-expected key is missing from the value passed to the @@ -235,19 +241,28 @@ class Mapping(Type): ``True``, no exception is raised and a partial mapping will be serialized/deserialized. - Default: ``raise``. + Default: ``False``. + + Note that the ``pserialize`` and ``pdeserialize`` methods of + this type will override this behavior, behaving as if + ``partial`` is ``True`` for the duration of those method calls. """ def __init__(self, unknown='ignore', partial=False): + self.unknown = unknown self.partial = partial - self.unknown = self._check_unknown(unknown) - def _check_unknown(self, unknown): - if not unknown in ['ignore', 'raise', 'preserve']: + def _set_unknown(self, value): + if not value in ['ignore', 'raise', 'preserve']: raise ValueError( - 'unknown argument must be one of "ignore", "raise", ' + 'unknown attribute must be one of "ignore", "raise", ' 'or "preserve"') - return unknown + self._unknown = value + + def _get_unknown(self): + return self._unknown + + unknown = property(_get_unknown, _set_unknown) def _validate(self, node, value): try: @@ -255,14 +270,13 @@ class Mapping(Type): except Exception, e: raise Invalid(node, '%r is not a mapping type: %s' % (value, e)) - def _impl(self, node, value, callback, default_callback, unknown, partial): + def _impl(self, node, value, callback, default_callback, unknown=None, + partial=None): if partial is None: partial = self.partial if unknown is None: unknown = self.unknown - else: - unknown = self._check_unknown(unknown) value = self._validate(node, value) @@ -303,73 +317,41 @@ class Mapping(Type): return result - def deserialize(self, node, value, unknown=None, partial=None): - """ - Along with the normal ``node`` and ``value`` arguments, this - method implementation accepts two additional optional - arguments that other type implementations do not: ``unknown`` - and ``partial``. These arguments can be used to override the - instance defaults of the same name for the duration of a - particular serialization or deserialization. - - unknown - If this value is provided, it must be one of ``preserve``, - ``raise``, or ``ignore``, overriding the behavior implied by - the value set by the ``unknown`` argument to constructor of - this instance. It defaults to ``None``, which signifies - that the instance default should be used. - - partial - If this value is provided, it must be a boolean, overriding - the behavior implied by the value set by the ``partial`` - argument to constructor of this instance. It defaults to - ``None``, which signifies that the instance default should - be used. - - """ + def deserialize(self, node, value): def callback(subnode, subval): return subnode.deserialize(subval) def default_callback(subnode): return subnode.default - return self._impl( - node, value, callback, default_callback, unknown, partial) - def serialize(self, node, value, unknown=None, partial=None): - """ - Along with the normal ``node`` and ``value`` arguments, this - method implementation accepts two additional optional - arguments that other type implementations do not: ``unknown`` - and ``partial``. These arguments can be used to override the - instance defaults of the same name for the duration of a - particular serialization or deserialization. - - unknown - If this value is provided, it must be one of ``preserve``, - ``raise``, or ``ignore``, overriding the behavior implied by - the value set by the ``unknown`` argument to constructor of - this instance. It defaults to ``None``, which signifies - that the instance default should be used. + return self._impl(node, value, callback, default_callback) - partial - If this value is provided, it must be a boolean, overriding - the behavior implied by the value set by the ``partial`` - argument to constructor of this instance. It defaults to - ``None``, which signifies that the instance default should - be used. - """ + def serialize(self, node, value): def callback(subnode, subval): return subnode.serialize(subval) def default_callback(subnode): return subnode.serialize(subnode.default) - return self._impl( - node, value, callback, default_callback, unknown, partial) + return self._impl(node, value, callback, default_callback) def pserialize(self, node, value): - return self.serialize(node, value, partial=True) + def callback(subnode, subval): + return subnode.pserialize(subval) + def default_callback(subnode): + return subnode.default + + return self._impl( + node, value, callback, default_callback, unknown='ignore', + partial=True) def pdeserialize(self, node, value): - return self.serialize(node, value, partial=True) + def callback(subnode, subval): + return subnode.pdeserialize(subval) + def default_callback(subnode): + return subnode.default + + return self._impl( + node, value, callback, default_callback, unknown='ignore', + partial=True) class Positional(object): """ diff --git a/colander/tests.py b/colander/tests.py index e1cd9c0..3a4c0d4 100644 --- a/colander/tests.py +++ b/colander/tests.py @@ -278,20 +278,6 @@ class TestMapping(unittest.TestCase): result = typ.deserialize(node, {'a':1, 'b':2}) self.assertEqual(result, {'a':1, 'b':2}) - def test_deserialize_unknown_raise_override(self): - node = DummySchemaNode(None) - node.children = [DummySchemaNode(None, name='a')] - typ = self._makeOne() - e = invalid_exc(typ.deserialize, node, {'a':1, 'b':2}, 'raise') - self.assertEqual(e.msg, "Unrecognized keys in mapping: {'b': 2}") - - def test_deserialize_unknown_preserve_override(self): - node = DummySchemaNode(None) - node.children = [DummySchemaNode(None, name='a')] - typ = self._makeOne() - result = typ.deserialize(node, {'a':1, 'b':2}, 'preserve') - self.assertEqual(result, {'a':1, 'b':2}) - def test_deserialize_subnodes_raise(self): node = DummySchemaNode(None) node.children = [ @@ -333,16 +319,6 @@ class TestMapping(unittest.TestCase): result = typ.deserialize(node, {'a':1}) self.assertEqual(result, {'a':1}) - def test_deserialize_subnode_partial_ignore_override(self): - node = DummySchemaNode(None) - node.children = [ - DummySchemaNode(None, name='a'), - DummySchemaNode(None, name='b'), - ] - typ = self._makeOne() - result = typ.deserialize(node, {'a':1}, 'ignore', True) - self.assertEqual(result, {'a':1}) - def test_serialize_not_a_mapping(self): node = DummySchemaNode(None) typ = self._makeOne() @@ -377,20 +353,6 @@ class TestMapping(unittest.TestCase): result = typ.serialize(node, {'a':1, 'b':2}) self.assertEqual(result, {'a':1, 'b':2}) - def test_serialize_unknown_raise_override(self): - node = DummySchemaNode(None) - node.children = [DummySchemaNode(None, name='a')] - typ = self._makeOne() - e = invalid_exc(typ.serialize, node, {'a':1, 'b':2}, 'raise') - self.assertEqual(e.msg, "Unrecognized keys in mapping: {'b': 2}") - - def test_serialize_unknown_preserve_override(self): - node = DummySchemaNode(None) - node.children = [DummySchemaNode(None, name='a')] - typ = self._makeOne() - result = typ.serialize(node, {'a':1, 'b':2}, 'preserve') - self.assertEqual(result, {'a':1, 'b':2}) - def test_serialize_subnodes_raise(self): node = DummySchemaNode(None) node.children = [ @@ -432,16 +394,6 @@ class TestMapping(unittest.TestCase): result = typ.serialize(node, {'a':1}) self.assertEqual(result, {'a':1}) - def test_serialize_subnode_partial_ignore_override(self): - node = DummySchemaNode(None) - node.children = [ - DummySchemaNode(None, name='a'), - DummySchemaNode(None, name='b'), - ] - typ = self._makeOne() - result = typ.serialize(node, {'a':1}, 'ignore', True) - self.assertEqual(result, {'a':1}) - def test_pserialize(self): node = DummySchemaNode(None) node.children = [ @@ -452,6 +404,16 @@ class TestMapping(unittest.TestCase): result = typ.pserialize(node, {'a':1}) self.assertEqual(result, {'a':1}) + def test_pserialize_using_default(self): + node = DummySchemaNode(None) + node.children = [ + DummySchemaNode(None, name='a'), + DummySchemaNode(None, name='b', default='abc'), + ] + typ = self._makeOne() + result = typ.pserialize(node, {'a':1}) + self.assertEqual(result, {'a':1, 'b':'abc'}) + def test_pdeserialize(self): node = DummySchemaNode(None) node.children = [ @@ -462,6 +424,16 @@ class TestMapping(unittest.TestCase): result = typ.pdeserialize(node, {'a':1}) self.assertEqual(result, {'a':1}) + def test_pdeserialize_using_default(self): + node = DummySchemaNode(None) + node.children = [ + DummySchemaNode(None, name='a'), + DummySchemaNode(None, name='b', default='abc'), + ] + typ = self._makeOne() + result = typ.pdeserialize(node, {'a':1}) + self.assertEqual(result, {'a':1, 'b':'abc'}) + class TestTuple(unittest.TestCase): def _makeOne(self): from colander import Tuple @@ -1490,7 +1462,10 @@ class DummySchemaNode(object): if self.exc: raise Invalid(self, self.exc) return val - + + pserialize = serialize + pdeserialize = deserialize + class DummyValidator(object): def __init__(self, msg=None): self.msg = msg