Add 'colander.List' type, modeled on 'colander.Set'.
Preserves order, allows duplicates, deserializes to a Python 'list'.
This commit is contained in:
@@ -1,10 +1,19 @@
|
||||
Unreleased
|
||||
----------
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- ``iso8601.py``: Convert ``ValueError`` (raised by ``datetime``) into
|
||||
``ParseErrorr`` in ``parse_date``, so that the validation machinery
|
||||
upstream handles it properly.
|
||||
|
||||
Features
|
||||
~~~~~~~~
|
||||
|
||||
- Add ``colander.List`` type, modeled on ``deform.List``: this type
|
||||
preserves ordering, and allows duplicates.
|
||||
|
||||
1.0a5 (2013-05-31)
|
||||
------------------
|
||||
|
||||
|
@@ -808,6 +808,37 @@ class Set(SchemaType):
|
||||
return set(cstruct)
|
||||
|
||||
|
||||
class List(SchemaType):
|
||||
""" Type representing an ordered sequence of items.
|
||||
|
||||
Desrializes an iterable to a ``list`` object.
|
||||
|
||||
If the :attr:`colander.null` value is passed to the serialize
|
||||
method of this class, the :attr:`colander.null` value will be
|
||||
returned.
|
||||
|
||||
.. versionadded: 1.0a6
|
||||
"""
|
||||
|
||||
def serialize(self, node, appstruct):
|
||||
if appstruct is null:
|
||||
return null
|
||||
|
||||
return appstruct
|
||||
|
||||
def deserialize(self, node, cstruct):
|
||||
if cstruct is null:
|
||||
return null
|
||||
|
||||
if not is_nonstr_iter(cstruct):
|
||||
raise Invalid(
|
||||
node,
|
||||
_('${cstruct} is not iterable', mapping={'cstruct': cstruct})
|
||||
)
|
||||
|
||||
return list(cstruct)
|
||||
|
||||
|
||||
class SequenceItems(list):
|
||||
"""
|
||||
List marker subclass for use by Sequence.cstruct_children, which indicates
|
||||
|
@@ -1059,6 +1059,58 @@ class TestSet(unittest.TestCase):
|
||||
result = typ.deserialize(node, set())
|
||||
self.assertEqual(result, set())
|
||||
|
||||
|
||||
class TestList(unittest.TestCase):
|
||||
def _makeOne(self, **kw):
|
||||
from colander import List
|
||||
return List(**kw)
|
||||
|
||||
def test_serialize(self):
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
provided = []
|
||||
result = typ.serialize(node, provided)
|
||||
self.assertTrue(result is provided)
|
||||
|
||||
def test_serialize_null(self):
|
||||
from colander import null
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
result = typ.serialize(node, null)
|
||||
self.assertTrue(result is null)
|
||||
|
||||
def test_deserialize_no_iter(self):
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
e = invalid_exc(typ.deserialize, node, 1)
|
||||
self.assertEqual(e.msg, '${cstruct} is not iterable')
|
||||
|
||||
def test_deserialize_str_no_iter(self):
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
e = invalid_exc(typ.deserialize, node, "foo")
|
||||
self.assertEqual(e.msg, '${cstruct} is not iterable')
|
||||
|
||||
def test_deserialize_null(self):
|
||||
from colander import null
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
result = typ.deserialize(node, null)
|
||||
self.assertEqual(result, null)
|
||||
|
||||
def test_deserialize_valid(self):
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
result = typ.deserialize(node, ('a', 'z', 'b'))
|
||||
self.assertEqual(result, ['a', 'z', 'b'])
|
||||
|
||||
def test_deserialize_empty_set(self):
|
||||
import colander
|
||||
typ = self._makeOne()
|
||||
node = DummySchemaNode(typ)
|
||||
result = typ.deserialize(node, ())
|
||||
self.assertEqual(result, [])
|
||||
|
||||
class TestSequence(unittest.TestCase):
|
||||
def _makeOne(self, **kw):
|
||||
from colander import Sequence
|
||||
|
Reference in New Issue
Block a user