Remove the unknown/partial keyword parameters from serialize/deserialize;
make pserialize/pdeserialize use unknown='ignore', partial=True.
This commit is contained in:
@@ -20,10 +20,6 @@ Next release
|
|||||||
- Allow ``colander.Mapping`` type to accept a new constructor
|
- Allow ``colander.Mapping`` type to accept a new constructor
|
||||||
argument: ``partial``.
|
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:
|
- New interface methods required by types and schema nodes:
|
||||||
``pserialize`` and ``pdeserialize``. These partially serialize or
|
``pserialize`` and ``pdeserialize``. These partially serialize or
|
||||||
partially deserialize a value (the definition of "partial" is up to
|
partially deserialize a value (the definition of "partial" is up to
|
||||||
|
|||||||
@@ -205,6 +205,8 @@ class Mapping(Type):
|
|||||||
|
|
||||||
The constructor of this type accepts two extra optional keyword
|
The constructor of this type accepts two extra optional keyword
|
||||||
arguments that other types do not: ``unknown`` and ``partial``.
|
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
|
||||||
``unknown`` controls the behavior of this type when an unknown
|
``unknown`` controls the behavior of this type when an unknown
|
||||||
@@ -224,6 +226,10 @@ class Mapping(Type):
|
|||||||
|
|
||||||
Default: ``ignore``.
|
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
|
||||||
``partial`` controls the behavior of this type when a
|
``partial`` controls the behavior of this type when a
|
||||||
schema-expected key is missing from the value passed to the
|
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
|
``True``, no exception is raised and a partial mapping will
|
||||||
be serialized/deserialized.
|
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):
|
def __init__(self, unknown='ignore', partial=False):
|
||||||
|
self.unknown = unknown
|
||||||
self.partial = partial
|
self.partial = partial
|
||||||
self.unknown = self._check_unknown(unknown)
|
|
||||||
|
|
||||||
def _check_unknown(self, unknown):
|
def _set_unknown(self, value):
|
||||||
if not unknown in ['ignore', 'raise', 'preserve']:
|
if not value in ['ignore', 'raise', 'preserve']:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'unknown argument must be one of "ignore", "raise", '
|
'unknown attribute must be one of "ignore", "raise", '
|
||||||
'or "preserve"')
|
'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):
|
def _validate(self, node, value):
|
||||||
try:
|
try:
|
||||||
@@ -255,14 +270,13 @@ class Mapping(Type):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
raise Invalid(node, '%r is not a mapping type: %s' % (value, 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:
|
if partial is None:
|
||||||
partial = self.partial
|
partial = self.partial
|
||||||
|
|
||||||
if unknown is None:
|
if unknown is None:
|
||||||
unknown = self.unknown
|
unknown = self.unknown
|
||||||
else:
|
|
||||||
unknown = self._check_unknown(unknown)
|
|
||||||
|
|
||||||
value = self._validate(node, value)
|
value = self._validate(node, value)
|
||||||
|
|
||||||
@@ -303,73 +317,41 @@ class Mapping(Type):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def deserialize(self, node, value, unknown=None, partial=None):
|
def deserialize(self, node, value):
|
||||||
"""
|
|
||||||
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 callback(subnode, subval):
|
def callback(subnode, subval):
|
||||||
return subnode.deserialize(subval)
|
return subnode.deserialize(subval)
|
||||||
def default_callback(subnode):
|
def default_callback(subnode):
|
||||||
return subnode.default
|
return subnode.default
|
||||||
return self._impl(
|
|
||||||
node, value, callback, default_callback, unknown, partial)
|
|
||||||
|
|
||||||
def serialize(self, node, value, unknown=None, partial=None):
|
return self._impl(node, value, callback, default_callback)
|
||||||
"""
|
|
||||||
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
|
def serialize(self, node, value):
|
||||||
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 callback(subnode, subval):
|
def callback(subnode, subval):
|
||||||
return subnode.serialize(subval)
|
return subnode.serialize(subval)
|
||||||
def default_callback(subnode):
|
def default_callback(subnode):
|
||||||
return subnode.serialize(subnode.default)
|
return subnode.serialize(subnode.default)
|
||||||
|
|
||||||
return self._impl(
|
return self._impl(node, value, callback, default_callback)
|
||||||
node, value, callback, default_callback, unknown, partial)
|
|
||||||
|
|
||||||
def pserialize(self, node, value):
|
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):
|
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):
|
class Positional(object):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -278,20 +278,6 @@ class TestMapping(unittest.TestCase):
|
|||||||
result = typ.deserialize(node, {'a':1, 'b':2})
|
result = typ.deserialize(node, {'a':1, 'b':2})
|
||||||
self.assertEqual(result, {'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):
|
def test_deserialize_subnodes_raise(self):
|
||||||
node = DummySchemaNode(None)
|
node = DummySchemaNode(None)
|
||||||
node.children = [
|
node.children = [
|
||||||
@@ -333,16 +319,6 @@ class TestMapping(unittest.TestCase):
|
|||||||
result = typ.deserialize(node, {'a':1})
|
result = typ.deserialize(node, {'a':1})
|
||||||
self.assertEqual(result, {'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):
|
def test_serialize_not_a_mapping(self):
|
||||||
node = DummySchemaNode(None)
|
node = DummySchemaNode(None)
|
||||||
typ = self._makeOne()
|
typ = self._makeOne()
|
||||||
@@ -377,20 +353,6 @@ class TestMapping(unittest.TestCase):
|
|||||||
result = typ.serialize(node, {'a':1, 'b':2})
|
result = typ.serialize(node, {'a':1, 'b':2})
|
||||||
self.assertEqual(result, {'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):
|
def test_serialize_subnodes_raise(self):
|
||||||
node = DummySchemaNode(None)
|
node = DummySchemaNode(None)
|
||||||
node.children = [
|
node.children = [
|
||||||
@@ -432,16 +394,6 @@ class TestMapping(unittest.TestCase):
|
|||||||
result = typ.serialize(node, {'a':1})
|
result = typ.serialize(node, {'a':1})
|
||||||
self.assertEqual(result, {'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):
|
def test_pserialize(self):
|
||||||
node = DummySchemaNode(None)
|
node = DummySchemaNode(None)
|
||||||
node.children = [
|
node.children = [
|
||||||
@@ -452,6 +404,16 @@ class TestMapping(unittest.TestCase):
|
|||||||
result = typ.pserialize(node, {'a':1})
|
result = typ.pserialize(node, {'a':1})
|
||||||
self.assertEqual(result, {'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):
|
def test_pdeserialize(self):
|
||||||
node = DummySchemaNode(None)
|
node = DummySchemaNode(None)
|
||||||
node.children = [
|
node.children = [
|
||||||
@@ -462,6 +424,16 @@ class TestMapping(unittest.TestCase):
|
|||||||
result = typ.pdeserialize(node, {'a':1})
|
result = typ.pdeserialize(node, {'a':1})
|
||||||
self.assertEqual(result, {'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):
|
class TestTuple(unittest.TestCase):
|
||||||
def _makeOne(self):
|
def _makeOne(self):
|
||||||
from colander import Tuple
|
from colander import Tuple
|
||||||
@@ -1491,6 +1463,9 @@ class DummySchemaNode(object):
|
|||||||
raise Invalid(self, self.exc)
|
raise Invalid(self, self.exc)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
pserialize = serialize
|
||||||
|
pdeserialize = deserialize
|
||||||
|
|
||||||
class DummyValidator(object):
|
class DummyValidator(object):
|
||||||
def __init__(self, msg=None):
|
def __init__(self, msg=None):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|||||||
Reference in New Issue
Block a user