implement, document and test the 'instantiate' decorator

This commit is contained in:
Chris Withers
2011-05-25 11:50:46 +01:00
parent 183a9d4a73
commit 5d12249f74
5 changed files with 113 additions and 0 deletions

View File

@@ -6,6 +6,9 @@ Features
- Add ``colander.ContainsOnly`` and ``colander.url`` validators.
- Add ``colander.instantiate`` to help define schemas containing
mappings and sequences more succinctly.
1.0a1 (2013-01-10)
------------------

View File

@@ -2089,3 +2089,18 @@ def _unflatten_mapping(node, paths, fstruct,
appstruct[curname] = subnode.typ.unflatten(
subnode, subpaths, subfstruct)
return appstruct
class instantiate(object):
"""
A decorator which can be used to instantiate :class:`SchemaNode`
elements inline within a class definition.
All parameters passed to the decorator and passed along to the
:class:`SchemaNode` during instantiation.
"""
def __init__(self,*args,**kw):
self.args,self.kw = args,kw
def __call__(self,class_):
return class_(*self.args,**self.kw)

View File

@@ -3337,6 +3337,42 @@ class TestUltraDeclarative(unittest.TestCase, TestFunctional):
schema = MainSchema()
return schema
class TestDeclarativeWithInstantiate(unittest.TestCase, TestFunctional):
def _makeSchema(self, name='schema'):
import colander
# an unlikely usage, but goos to test passing
# parameters to instantiation works
@colander.instantiate(name=name)
class schema(colander.MappingSchema):
int = colander.SchemaNode(colander.Int(),
validator=colander.Range(0, 10))
ob = colander.SchemaNode(colander.GlobalObject(package=colander))
@colander.instantiate()
class seq(colander.SequenceSchema):
@colander.instantiate()
class tup(colander.TupleSchema):
tupint = colander.SchemaNode(colander.Int())
tupstring = colander.SchemaNode(colander.String())
@colander.instantiate()
class tup(colander.TupleSchema):
tupint = colander.SchemaNode(colander.Int())
tupstring = colander.SchemaNode(colander.String())
@colander.instantiate()
class seq2(colander.SequenceSchema):
@colander.instantiate()
class mapping(colander.MappingSchema):
key = colander.SchemaNode(colander.Int())
key2 = colander.SchemaNode(colander.Int())
return schema
class Test_null(unittest.TestCase):
def test___nonzero__(self):
from colander import null

View File

@@ -132,6 +132,8 @@ Schema-Related
.. autoclass:: deferred
.. autoclass:: instantiate
.. attribute:: null
Represents a null value in colander-related operations.

View File

@@ -982,6 +982,63 @@ indeed be present in the child list of the ``schema`` instance
``title`` attribute will be ``Some Schema`` (``schema.title`` will return
``Some Schema``).
Defining A Schema Declaratively
-------------------------------
Previously, we defined the schema in such a way that the individual
sequences and mappings within the schema could be re-used in different
schemas. If all nodes within a schema are only likely to be used in that
schema, then the schema definition can be made more succinct using the
:class:`~colander.instantiate` class decorator as shown below:
.. code-block:: python
:linenos:
import colander
class Person(colander.MappingSchema):
name = colander.SchemaNode(colander.String())
age = colander.SchemaNode(colander.Int(),
validator=colander.Range(0, 200))
@colander.instantiate()
class friends(colander.SequenceSchema):
@colander.instantiate()
class friend(colander.TupleSchema):
rank = colander.SchemaNode(colander.Int(),
validator=colander.Range(0, 9999))
name = colander.SchemaNode(colander.String())
@colander.instantiate()
class phones(colander.SequenceSchema):
@colander.instantiate()
class phone(colander.MappingSchema):
location = colander.SchemaNode(colander.String(),
validator=colander.OneOf(['home', 'work']))
number = colander.SchemaNode(colander.String())
If you need to pass parameters when using this style of schema
definition, such as a ``missing`` value to a :class:`SchemaNode`
during instantiation, you can pass these as parameters to
:class:`~colander.instantiate`.
For example, if we wanted to limit the number of friends a person can
have, and cater for people who have no friends, we could adjust the
schema as shown below:
.. code-block:: python
:linenos:
class Person(colander.MappingSchema):
@colander.instantiate(missing=(),
validator=colander.Length(max=5))
class friends(colander.SequenceSchema):
@colander.instantiate()
class friend(colander.TupleSchema):
name = colander.SchemaNode(colander.String())
Defining A Schema Imperatively
------------------------------