- Fix documentation: 0.9.2 requires `deserialize
` of types to explicitly
deal with the potential to receive ``colander.null``.
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
Changes
|
Changes
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
Next release
|
||||||
|
------------
|
||||||
|
|
||||||
|
- Fix documentation: 0.9.2 requires ``deserialize`` of types to explicitly
|
||||||
|
deal with the potential to receive ``colander.null``.
|
||||||
|
|
||||||
0.9.2 (2011-03-28)
|
0.9.2 (2011-03-28)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@@ -87,13 +87,12 @@ of our definitions, a ``Person`` represents:
|
|||||||
Schema Node Objects
|
Schema Node Objects
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
A schema is composed of one or more *schema node* objects, each
|
A schema is composed of one or more *schema node* objects, each typically of
|
||||||
typically of the class :class:`colander.SchemaNode`, usually in a
|
the class :class:`colander.SchemaNode`, usually in a nested arrangement.
|
||||||
nested arrangement. Each schema node object has a required *type*, an
|
Each schema node object has a required *type*, an optional deserialization
|
||||||
optional deserialization *validator*, an optional *default*, an
|
*validator*, an optional *default*, an optional *missing*, an optional
|
||||||
optional *missing*, an optional *title*, an optional *description*, an
|
*title*, an optional *description*, and a slightly less optional *name*. It
|
||||||
optional *widget*, and a slightly less optional *name*. It also
|
also accepts *arbitrary* keyword arguments, which are attached directly as
|
||||||
accepts *arbitrary* keyword arguments, which are attached directly as
|
|
||||||
attributes to the node instance.
|
attributes to the node instance.
|
||||||
|
|
||||||
The *type* of a schema node indicates its data type (such as
|
The *type* of a schema node indicates its data type (such as
|
||||||
@@ -126,19 +125,20 @@ of the *name*.
|
|||||||
The *description* of a schema node is metadata about a schema node
|
The *description* of a schema node is metadata about a schema node
|
||||||
that can be used by higher-level systems. By default, it is empty.
|
that can be used by higher-level systems. By default, it is empty.
|
||||||
|
|
||||||
The *widget* of a schema node is a concept used only by higher level
|
|
||||||
systems (such as form systems). By default it is ``None``. It won't
|
|
||||||
be discussed any further in the Colander documentation; it will
|
|
||||||
instead be explained in the context of the documentation of systems
|
|
||||||
which make use of it.
|
|
||||||
|
|
||||||
Any other keyword arguments to a schema node constructor will be
|
Any other keyword arguments to a schema node constructor will be
|
||||||
attached to the node unmolested (e.g. when ``foo=1`` is passed, the
|
attached to the node unmolested (e.g. when ``foo=1`` is passed, the
|
||||||
resulting schema node will have an attribute named ``foo`` with the
|
resulting schema node will have an attribute named ``foo`` with the
|
||||||
value ``1``).
|
value ``1``).
|
||||||
|
|
||||||
.. note:: Abitrary keyword arguments are allowed to a schema node
|
.. note:: You may see some higher-level systems (such as Deform) pass a
|
||||||
constructor in Colander 0.9+. Prior version disallow them.
|
``widget`` argument to a SchemaNode constructor. Such systems make use of
|
||||||
|
the fact that a SchemaNode can be passed arbitrary keyword arguments for
|
||||||
|
extension purposes. ``widget`` and other keyword arguments not enumerated
|
||||||
|
here but which are passed during schema node construction by someone
|
||||||
|
constructing a schema for a particular purpose are not used internally by
|
||||||
|
Colander; they are instead only meaningful to higher-level systems which
|
||||||
|
consume Colander schemas. Abitrary keyword arguments are allowed to a
|
||||||
|
schema node constructor in Colander 0.9+. Prior version disallow them.
|
||||||
|
|
||||||
The name of a schema node that is introduced as a class-level
|
The name of a schema node that is introduced as a class-level
|
||||||
attribute of a :class:`colander.MappingSchema`,
|
attribute of a :class:`colander.MappingSchema`,
|
||||||
@@ -193,7 +193,7 @@ Earlier we defined a schema:
|
|||||||
|
|
||||||
class Friend(colander.TupleSchema):
|
class Friend(colander.TupleSchema):
|
||||||
rank = colander.SchemaNode(colander.Int(),
|
rank = colander.SchemaNode(colander.Int(),
|
||||||
validator=colander.Range(0, 9999))
|
validator=colander.Range(0, 9999))
|
||||||
name = colander.SchemaNode(colander.String())
|
name = colander.SchemaNode(colander.String())
|
||||||
|
|
||||||
class Phone(colander.MappingSchema):
|
class Phone(colander.MappingSchema):
|
||||||
|
@@ -27,13 +27,15 @@ scope.
|
|||||||
What Is Schema Binding?
|
What Is Schema Binding?
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
- Values passed to a SchemaNode (e.g. ``description``, ``missing``,
|
- Any values passed as a keyword argument to a SchemaNode
|
||||||
etc.) may be an instance of the ``colander.deferred`` class.
|
(e.g. ``description``, ``missing``, etc.) may be an instance of the
|
||||||
Instances of the ``colander.deferred`` class are callables which
|
``colander.deferred`` class. Instances of the ``colander.deferred`` class
|
||||||
accept two positional arguments: a ``node`` and a ``kw`` dictionary.
|
are callables which accept two positional arguments: a ``node`` and a
|
||||||
|
``kw`` dictionary.
|
||||||
|
|
||||||
- When a schema node is bound, it is cloned, and any
|
- When a schema node is bound, it is cloned, and any ``colander.deferred``
|
||||||
``colander.deferred`` values it has as attributes will be resolved.
|
values it has as attributes will be resolved by invoking the callable
|
||||||
|
represented by the deferred value.
|
||||||
|
|
||||||
- A ``colander.deferred`` value is a callable that accepts two
|
- A ``colander.deferred`` value is a callable that accepts two
|
||||||
positional arguments: the schema node being bound and a set of
|
positional arguments: the schema node being bound and a set of
|
||||||
|
@@ -9,18 +9,19 @@ a new :term:`validator`.
|
|||||||
Defining a New Type
|
Defining a New Type
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
A new type is a class with two methods:: ``serialize`` and
|
A new type is a class with two methods:: ``serialize`` and ``deserialize``.
|
||||||
``deserialize``. ``serialize`` converts a Python data structure (an
|
``serialize`` converts a Python data structure (an :term:`appstruct`) into a
|
||||||
:term:`appstruct`) into a serialization (a :term:`cstruct`).
|
serialization (a :term:`cstruct`). ``deserialize`` converts a serialized
|
||||||
``deserialize`` converts a serialized value (a :term:`cstruct`) into a
|
value (a :term:`cstruct`) into a Python data structure (a :term:`appstruct`).
|
||||||
Python data structure (a :term:`appstruct`).
|
|
||||||
|
|
||||||
Here's a type which implements boolean serialization and
|
An Example
|
||||||
deserialization. It serializes a boolean to the string ``true`` or
|
~~~~~~~~~~
|
||||||
``false`` or the special :attr:`colander.null` sentinel; it then
|
|
||||||
deserializes a string (presumably ``true`` or ``false``, but allows
|
Here's a type which implements boolean serialization and deserialization. It
|
||||||
some wiggle room for ``t``, ``on``, ``yes``, ``y``, and ``1``) to a
|
serializes a boolean to the string ``true`` or ``false`` or the special
|
||||||
boolean value.
|
:attr:`colander.null` sentinel; it then deserializes a string (presumably
|
||||||
|
``true`` or ``false``, but allows some wiggle room for ``t``, ``on``,
|
||||||
|
``yes``, ``y``, and ``1``) to a boolean value.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:linenos:
|
:linenos:
|
||||||
@@ -36,6 +37,8 @@ boolean value.
|
|||||||
return appstruct and 'true' or 'false'
|
return appstruct and 'true' or 'false'
|
||||||
|
|
||||||
def deserialize(self, node, cstruct):
|
def deserialize(self, node, cstruct):
|
||||||
|
if cstruct is null:
|
||||||
|
return null
|
||||||
if not isinstance(cstruct, basestring):
|
if not isinstance(cstruct, basestring):
|
||||||
raise Invalid(node, '%r is not a string' % cstruct)
|
raise Invalid(node, '%r is not a string' % cstruct)
|
||||||
value = cstruct.lower()
|
value = cstruct.lower()
|
||||||
@@ -43,13 +46,6 @@ boolean value.
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
Note that the ``deserialize`` method of a type does not need to
|
|
||||||
explicitly deserialize the :attr:`colander.null` value.
|
|
||||||
Deserialization of the null value is dealt with at a higher level
|
|
||||||
(with the :meth:`colander.SchemaNode.deserialize` method); a type will
|
|
||||||
never receive an :attr:`colander.null` value as a ``cstruct`` argument
|
|
||||||
to its ``deserialize`` method.
|
|
||||||
|
|
||||||
Here's how you would use the resulting class as part of a schema:
|
Here's how you would use the resulting class as part of a schema:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -61,33 +57,60 @@ Here's how you would use the resulting class as part of a schema:
|
|||||||
interested = colander.SchemaNode(Boolean())
|
interested = colander.SchemaNode(Boolean())
|
||||||
|
|
||||||
The above schema has a member named ``interested`` which will now be
|
The above schema has a member named ``interested`` which will now be
|
||||||
serialized and deserialized as a boolean, according to the logic
|
serialized and deserialized as a boolean, according to the logic defined in
|
||||||
defined in the ``Boolean`` type class.
|
the ``Boolean`` type class.
|
||||||
|
|
||||||
Note that the only two real constraints of a type class are:
|
Implementing Type Classes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
- it must deal specially with the value :attr:`colander.null` within
|
The constraints of a type class implementation are:
|
||||||
``serialize``, translating it to a type-specific null value.
|
|
||||||
|
|
||||||
- its ``serialize`` method must be able to make sense of a value
|
- It must have both a ``serialize`` and ``deserialize`` method.
|
||||||
generated by its ``deserialize`` method and vice versa, except that
|
|
||||||
the ``deserialize`` method needn't deal with the
|
- it must deal specially with the value :attr:`colander.null` within both
|
||||||
:attr:`colander.null` value specially even if the ``serialize``
|
``serialize`` and ``deserialize``.
|
||||||
method returns it.
|
|
||||||
|
- its ``serialize`` method must be able to make sense of a value generated by
|
||||||
|
its ``deserialize`` method and vice versa.
|
||||||
|
|
||||||
The ``serialize`` method of a type accepts two values: ``node``, and
|
The ``serialize`` method of a type accepts two values: ``node``, and
|
||||||
``appstruct``. ``node`` will be the schema node associated with this
|
``appstruct``. ``node`` will be the schema node associated with this type.
|
||||||
type. It is used when the type must raise a :exc:`colander.Invalid`
|
The node is used when the type must raise a :exc:`colander.Invalid` error,
|
||||||
error, which expects a schema node as its first constructor argument.
|
which expects a schema node as its first constructor argument. ``appstruct``
|
||||||
``appstruct`` will be the :term:`appstruct` value that needs to be
|
will be the :term:`appstruct` value that needs to be serialized.
|
||||||
serialized.
|
|
||||||
|
|
||||||
The deserialize and method of a type accept two values: ``node``, and
|
The deserialize and method of a type accept two values: ``node``, and
|
||||||
``cstruct``. ``node`` will be the schema node associated with this
|
``cstruct``. ``node`` will be the schema node associated with this type.
|
||||||
type. It is used when the type must raise a :exc:`colander.Invalid`
|
The node is used when the type must raise a :exc:`colander.Invalid` error,
|
||||||
error, which expects a schema node as its first constructor argument.
|
which expects a schema node as its first constructor argument. ``cstruct``
|
||||||
``cstruct`` will be the :term:`cstruct` value that needs to be
|
will be the :term:`cstruct` value that needs to be deserialized.
|
||||||
deserialized.
|
|
||||||
|
Null Values
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
The framework requires that both the ``serialize`` method and the
|
||||||
|
``deserialize`` method of a type explicitly deal with the potential to
|
||||||
|
receive a :attr:`colander.null` value. :attr:`colander.null` will be sent to
|
||||||
|
the type during serialization and deserialization in circumstances where a
|
||||||
|
value has not been provided by the data structure being serialized or
|
||||||
|
deserialized. In the common case, when the ``serialize`` or ``deserialize``
|
||||||
|
method of type receives the :attr:`colander.null` value, it should just
|
||||||
|
return :attr:`colander.null` to its caller.
|
||||||
|
|
||||||
|
A type might also choose to return :attr:`colander.null` if the value it
|
||||||
|
receives is *logically* (but not literally) null. For example,
|
||||||
|
:class:`colander.String` type converts the empty string to ``colander.null``
|
||||||
|
within its ``deserialize`` method.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
def deserialize(self, node, cstruct):
|
||||||
|
if not cstruct:
|
||||||
|
return null
|
||||||
|
|
||||||
|
Type Constructors
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
A type class does not need to implement a constructor (``__init__``),
|
A type class does not need to implement a constructor (``__init__``),
|
||||||
but it isn't prevented from doing so if it needs to accept arguments;
|
but it isn't prevented from doing so if it needs to accept arguments;
|
||||||
|
@@ -17,8 +17,11 @@ that the :term:`cstruct` value corresponding to the node it's passed
|
|||||||
to is missing, and if possible, the value of the ``missing`` attribute
|
to is missing, and if possible, the value of the ``missing`` attribute
|
||||||
of the corresponding node should be used instead.
|
of the corresponding node should be used instead.
|
||||||
|
|
||||||
Note that :attr:`colander.null` has no relationship to the built-in
|
Note that :attr:`colander.null` has no relationship to the built-in Python
|
||||||
Python ``None`` value.
|
``None`` value. ``colander.null`` is used instead of ``None`` because
|
||||||
|
``None`` is a potentially valid value for some serializations and
|
||||||
|
deserializations, and using it as a sentinel would prevent ``None`` from
|
||||||
|
being used in this way.
|
||||||
|
|
||||||
.. _serializing_null:
|
.. _serializing_null:
|
||||||
|
|
||||||
@@ -206,15 +209,24 @@ When a :attr:`colander.null` sentinel marker is passed to the
|
|||||||
:meth:`colander.SchemaNode.deserialize` method of a particular node in
|
:meth:`colander.SchemaNode.deserialize` method of a particular node in
|
||||||
a schema, the node will take the following steps:
|
a schema, the node will take the following steps:
|
||||||
|
|
||||||
- If the schema node has an explicit ``missing`` attribute (the node's
|
- The *type* object's ``deserialize`` method will be called with the null
|
||||||
constructor was supplied with an explicit ``missing`` argument), the
|
value to allow the type to convert the null value to a type-specific
|
||||||
``missing`` value will be returned. Note that when this happens,
|
default. The resulting "appstruct" is used instead of the value passed
|
||||||
the ``missing`` value is not validated by any schema node validator:
|
directly to :meth:`colander.SchemaNode.deserialize` in subsequent
|
||||||
it is simply returned.
|
operations. Most types, when they receive the ``null`` value will simply
|
||||||
|
return it, however.
|
||||||
|
|
||||||
- If the schema node does *not* have an explicitly provided
|
- If the appstruct value computed by the type's ``deserialize`` method is
|
||||||
``missing`` attribute (the node's constructor was not supplied with
|
``colander.null`` and the schema node has an explicit ``missing`` attribute
|
||||||
an explicit ``missing`` value), a :exc:`colander.Invalid` exception
|
(the node's constructor was supplied with an explicit ``missing``
|
||||||
|
argument), the ``missing`` value will be returned. Note that when this
|
||||||
|
happens, the ``missing`` value is not validated by any schema node
|
||||||
|
validator: it is simply returned.
|
||||||
|
|
||||||
|
- If the appstruct value computed by the type's ``deserialize`` method is
|
||||||
|
``colander.null`` and the schema node does *not* have an explicitly
|
||||||
|
provided ``missing`` attribute (the node's constructor was not supplied
|
||||||
|
with an explicit ``missing`` value), a :exc:`colander.Invalid` exception
|
||||||
will be raised with a message indicating that the field is required.
|
will be raised with a message indicating that the field is required.
|
||||||
|
|
||||||
.. note:: There are differences between serialization and
|
.. note:: There are differences between serialization and
|
||||||
@@ -255,7 +267,7 @@ an ``age`` key of :attr:`colander.null`, the ``missing`` value of
|
|||||||
|
|
||||||
.. note:: Note that ``None`` can be used for the ``missing`` schema
|
.. note:: Note that ``None`` can be used for the ``missing`` schema
|
||||||
node value as required, as in the above example. It's no different
|
node value as required, as in the above example. It's no different
|
||||||
than any other value used as ``missing``. or ``colander.nuil`` can
|
than any other value used as ``missing``. The empty string can
|
||||||
also be used as the ``missing`` value if that is helpful.
|
also be used as the ``missing`` value if that is helpful.
|
||||||
|
|
||||||
The :attr:`colander.null` value is also the default, so it needn't be
|
The :attr:`colander.null` value is also the default, so it needn't be
|
||||||
|
Reference in New Issue
Block a user