Remove the unknown/partial keyword parameters from serialize/deserialize;

make pserialize/pdeserialize use unknown='ignore', partial=True.
This commit is contained in:
Chris McDonough
2010-04-02 05:20:54 +00:00
parent b97ef0fba2
commit c67b72e717
3 changed files with 67 additions and 114 deletions

View File

@@ -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

View File

@@ -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):
"""

View File

@@ -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