diff --git a/CHANGES.txt b/CHANGES.txt index c8c882e..741dc52 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,9 @@ Changes Next release ------------ +- Raise a ``colander.Invalid`` error if a ``colander.SequenceSchema`` + is created with more than one member. + - Add ``Function`` validator. - Fix bug in serialization of non-Unicode values in the ``String`` class. diff --git a/colander/__init__.py b/colander/__init__.py index 5f769b0..b02cd72 100644 --- a/colander/__init__.py +++ b/colander/__init__.py @@ -1018,8 +1018,23 @@ class Schema(object): MappingSchema = Schema -class SequenceSchema(Schema): +class SequenceSchema(object): schema_type = Sequence + node_type = SchemaNode + __metaclass__ = _SchemaMeta + + def __new__(cls, *args, **kw): + node = object.__new__(cls.node_type) + node.name = None + node._order = SchemaNode._counter.next() + typ = cls.schema_type() + node.__init__(typ, *args, **kw) + if not len(cls.nodes) == 1: + raise Invalid(node, + 'Sequence schemas must have exactly one child node') + for n in cls.nodes: + node.add(n) + return node class TupleSchema(Schema): schema_type = Tuple diff --git a/colander/tests.py b/colander/tests.py index 42698ba..6a121b8 100644 --- a/colander/tests.py +++ b/colander/tests.py @@ -1218,9 +1218,9 @@ class TestSchema(unittest.TestCase): self.assertEqual(node.children[0].typ.__class__, colander.String) self.assertEqual(node.children[0].title, 'Thing') self.assertEqual(node.children[1].title, 'bar') - + class TestSequenceSchema(unittest.TestCase): - def test_it(self): + def test_succeed(self): import colander _inner = colander.SchemaNode(colander.String()) class MySchema(colander.SequenceSchema): @@ -1231,6 +1231,27 @@ class TestSequenceSchema(unittest.TestCase): self.assertEqual(node.typ.__class__, colander.Sequence) self.assertEqual(node.children[0], _inner) + def test_fail_toomany(self): + import colander + thingnode = colander.SchemaNode(colander.String()) + thingnode2 = colander.SchemaNode(colander.String()) + class MySchema(colander.SequenceSchema): + thing = thingnode + thing2 = thingnode2 + e = invalid_exc(MySchema) + self.assertEqual( + e.msg, + 'Sequence schemas must have exactly one child node') + + def test_fail_toofew(self): + import colander + class MySchema(colander.SequenceSchema): + pass + e = invalid_exc(MySchema) + self.assertEqual( + e.msg, + 'Sequence schemas must have exactly one child node') + class TestTupleSchema(unittest.TestCase): def test_it(self): import colander