"cereal" name already taken on pypi.

This commit is contained in:
Chris McDonough
2010-03-14 15:40:26 +00:00
parent 30b5593be4
commit 85513067db
10 changed files with 273 additions and 264 deletions

View File

@@ -1,5 +1,5 @@
cereal
======
colander
========
An extensible package which can be used to:

View File

@@ -9,7 +9,7 @@ class Invalid(Exception):
the value for a particular structure was not valid.
The constructor receives a mandatory ``struct`` argument. This
must be an instance of the :class:`cereal.Structure` class.
must be an instance of the :class:`colander.Structure` class.
The constructor also receives an optional ``msg`` keyword
argument, defaulting to ``None``. The ``msg`` argument is a
@@ -26,7 +26,7 @@ class Invalid(Exception):
def add(self, exc):
""" Add a child exception; ``exc`` must be an instance of
:class:`cereal.Invalid`"""
:class:`colander.Invalid`"""
exc.parent = self
self.children.append(exc)
@@ -68,7 +68,7 @@ class Invalid(Exception):
class All(object):
""" Composite validator which succeeds if none of its
subvalidators raises an :class:`cereal.Invalid` exception"""
subvalidators raises an :class:`colander.Invalid` exception"""
def __init__(self, *validators):
self.validators = validators
@@ -119,8 +119,8 @@ class OneOf(object):
class Mapping(object):
""" A type which represents a mapping of names to structures.
The substructures of the :class:`cereal.Structure` that wraps this
type imply the named keys and values in the mapping.
The substructures of the :class:`colander.Structure` that wraps
this type imply the named keys and values in the mapping.
The constructor of a mapping type accepts a single optional
keyword argument named ``unknown_keys``. By default, this
@@ -132,8 +132,8 @@ class Mapping(object):
associated with this type will be ignored during
deserialization.
- ``raise`` will cause a :exc:`cereal.Invalid` exception to
be raised when unknown keys are present during deserialization.
- ``raise`` will cause a :exc:`colander.Invalid` exception to be
raised when unknown keys are present during deserialization.
- ``preserve`` will preserve the 'raw' unknown keys and values in
the returned data structure during deserialization.
@@ -215,9 +215,9 @@ class Positional(object):
class Tuple(Positional):
""" A type which represents a fixed-length sequence of structures.
The substructures of the :class:`cereal.Structure` that wraps this
type imply the positional elements of the tuple in the order they
are added.
The substructures of the :class:`colander.Structure` that wraps
this type imply the positional elements of the tuple in the order
they are added.
This type is willing to serialize and deserialized iterables that,
when converted to a tuple, have the same number of elements as the
@@ -270,14 +270,14 @@ class Tuple(Positional):
class Sequence(Positional):
"""
A type which represents a variable-length sequence of structures,
all of which must be of the same type. This type is defined by the
the :class:`cereal.Structure` instance passed to the constructor
as ``struct``.
all of which must be of the same type. This type is defined by
the the :class:`colander.Structure` instance passed to the
constructor as ``struct``.
The ``struct`` argument to this type's constructor is required.
The substructures of the :class:`cereal.Structure` that wraps this
type are ignored.
The substructures of the :class:`colander.Structure` that wraps
this type are ignored.
"""
def __init__(self, struct):
self.struct = struct
@@ -326,8 +326,8 @@ class String(object):
which should be applied to object serialization. It defaults to
``utf-8`` if not provided.
The substructures of the :class:`cereal.Structure` that wraps this
type are ignored.
The substructures of the :class:`colander.Structure` that wraps
this type are ignored.
"""
def __init__(self, encoding=None):
self.encoding = encoding
@@ -353,8 +353,8 @@ Str = String
class Integer(object):
""" A type representing an integer.
The substructures of the :class:`cereal.Structure` that wraps this
type are ignored.
The substructures of the :class:`colander.Structure` that wraps
this type are ignored.
"""
def deserialize(self, struct, value):
try:
@@ -373,8 +373,8 @@ Int = Integer
class Float(object):
""" A type representing a float.
The substructures of the :class:`cereal.Structure` that wraps this
type are ignored.
The substructures of the :class:`colander.Structure` that wraps
this type are ignored.
"""
def deserialize(self, struct, value):
try:
@@ -400,8 +400,8 @@ class Boolean(object):
Serialization will produce ``true`` or ``false`` based on the
value.
The substructures of the :class:`cereal.Structure` that wraps this
type are ignored.
The substructures of the :class:`colander.Structure` that wraps
this type are ignored.
"""
def deserialize(self, struct, value):
@@ -448,11 +448,11 @@ class GlobalObject(object):
argument to this type was passed the ``xml`` module object, the
resulting import would be for ``xml.minidom``. If a relative
package name is supplied to ``deserialize``, and no ``package``
was supplied to the constructor, an :exc:`cereal.Invalid` error
was supplied to the constructor, an :exc:`colander.Invalid` error
will be raised.
The substructures of the :class:`cereal.Structure` that wraps this
type are ignored.
The substructures of the :class:`colander.Structure` that wraps
this type are ignored.
"""
def __init__(self, package):
self.package = package
@@ -533,7 +533,7 @@ class Structure(object):
- ``typ`` (required): The 'type' for this structure. It should be
an instance of a class that implements the
:class:`cereal.interfaces.Type` interface.
:class:`colander.interfaces.Type` interface.
- ``structs``: a sequence of substructures. If the substructures
of this structure are not known at construction time, they can
@@ -545,9 +545,9 @@ class Structure(object):
provided, this structure has no default value and it will be
considered 'required' (the ``required`` attribute will be True).
- ``validator``: Optional validator for this structure. It should be
an object that implements the
:class:`cereal.interfaces.Validator` interface.
- ``validator``: Optional validator for this structure. It should
be an object that implements the
:class:`colander.interfaces.Validator` interface.
"""
_counter = itertools.count()

View File

@@ -2,10 +2,10 @@ def Validator(struct, value):
"""
A validator is called after deserialization of a value.
If ``value`` is not valid, raise a :class:`cereal.Invalid`
If ``value`` is not valid, raise a :class:`colander.Invalid`
instance as an exception after.
``struct`` is a :class:`cereal.Structure` instance which
``struct`` is a :class:`colander.Structure` instance which
contains, among other things, the default value, the name of the
value, and a ``required`` flag indicating whether this value is
required. It is often ignored in simple validators.
@@ -17,18 +17,18 @@ class Type(object):
Serialize the object represented by ``value`` to a
data structure. The serialization should be composed of one or
more objects which can be deserialized by the
:meth:`cereal.interfaces.Type.deserialize` method of this
:meth:`colander.interfaces.Type.deserialize` method of this
type.
This method should also do type validation of ``value``.
``struct`` is a :class:`cereal.Structure` instance which
``struct`` is a :class:`colander.Structure` instance which
contains, among other things, the default value, the name of
the value, and a ``required`` flag indicating whether this
value is required.
If the object cannot be serialized, or type validation for
``value`` fails, a :exc:`cereal.Invalid` exception should be
``value`` fails, a :exc:`colander.Invalid` exception should be
raised.
"""
@@ -38,18 +38,18 @@ class Type(object):
Deserialze the serialization represented by ``value`` to a
data structure. The deserialization should be composed of one
or more objects which can be serialized by the
:meth:`cereal.interfaces.Type.serialize` method of this
:meth:`colander.interfaces.Type.serialize` method of this
type.
This method should also do type validation of ``value``.
``struct`` is a :class:`cereal.Structure` instance which
``struct`` is a :class:`colander.Structure` instance which
contains, among other things, the default value, the name of
the value, and a ``required`` flag indicating whether this
value is required.
If the object cannot be deserialized, or type validation for
``value`` fails, a :exc:`cereal.Invalid` exception should be
``value`` fails, a :exc:`colander.Invalid` exception should be
raised.
"""

View File

@@ -1,7 +1,7 @@
import unittest
def invalid_exc(func, *arg, **kw):
from cereal import Invalid
from colander import Invalid
try:
func(*arg, **kw)
except Invalid, e:
@@ -11,7 +11,7 @@ def invalid_exc(func, *arg, **kw):
class TestInvalid(unittest.TestCase):
def _makeOne(self, struct, msg=None, pos=None):
from cereal import Invalid
from colander import Invalid
exc = Invalid(struct, msg)
exc.pos = pos
return exc
@@ -36,7 +36,7 @@ class TestInvalid(unittest.TestCase):
self.assertEqual(exc._keyname(), 'name')
def test__keyname_positional_parent(self):
from cereal import Positional
from colander import Positional
parent = Dummy()
parent.struct = DummyStructure(Positional())
exc = self._makeOne(None, '')
@@ -65,7 +65,7 @@ class TestInvalid(unittest.TestCase):
self.assertEqual(paths, [(exc1, exc2, exc3), (exc1, exc4)])
def test_asdict(self):
from cereal import Positional
from colander import Positional
struct1 = DummyStructure(None, 'struct1')
struct2 = DummyStructure(Positional(), 'struct2')
struct3 = DummyStructure(Positional(), 'struct3')
@@ -84,7 +84,7 @@ class TestInvalid(unittest.TestCase):
class TestAll(unittest.TestCase):
def _makeOne(self, validators):
from cereal import All
from colander import All
return All(*validators)
def test_success(self):
@@ -102,7 +102,7 @@ class TestAll(unittest.TestCase):
class TestRange(unittest.TestCase):
def _makeOne(self, min=None, max=None):
from cereal import Range
from colander import Range
return Range(min=min, max=max)
def test_success_no_bounds(self):
@@ -133,7 +133,7 @@ class TestRange(unittest.TestCase):
class TestOneOf(unittest.TestCase):
def _makeOne(self, values):
from cereal import OneOf
from colander import OneOf
return OneOf(values)
def test_success(self):
@@ -147,7 +147,7 @@ class TestOneOf(unittest.TestCase):
class TestMapping(unittest.TestCase):
def _makeOne(self, unknown_keys='ignore'):
from cereal import Mapping
from colander import Mapping
return Mapping(unknown_keys=unknown_keys)
def test_ctor_bad_unknown_keys(self):
@@ -295,7 +295,7 @@ class TestMapping(unittest.TestCase):
class TestTuple(unittest.TestCase):
def _makeOne(self):
from cereal import Tuple
from colander import Tuple
return Tuple()
def test_deserialize_not_iterable(self):
@@ -398,12 +398,12 @@ class TestTuple(unittest.TestCase):
class TestSequence(unittest.TestCase):
def _makeOne(self, substruct):
from cereal import Sequence
from colander import Sequence
return Sequence(substruct)
def test_alias(self):
from cereal import Seq
from cereal import Sequence
from colander import Seq
from colander import Sequence
self.assertEqual(Seq, Sequence)
def test_deserialize_not_iterable(self):
@@ -466,12 +466,12 @@ class TestSequence(unittest.TestCase):
class TestString(unittest.TestCase):
def _makeOne(self, encoding='utf-8'):
from cereal import String
from colander import String
return String(encoding)
def test_alias(self):
from cereal import Str
from cereal import String
from colander import Str
from colander import String
self.assertEqual(Str, String)
def test_deserialize_uncooperative(self):
@@ -529,12 +529,12 @@ class TestString(unittest.TestCase):
class TestInteger(unittest.TestCase):
def _makeOne(self):
from cereal import Integer
from colander import Integer
return Integer()
def test_alias(self):
from cereal import Int
from cereal import Integer
from colander import Int
from colander import Integer
self.assertEqual(Int, Integer)
def test_deserialize_fails(self):
@@ -567,7 +567,7 @@ class TestInteger(unittest.TestCase):
class TestFloat(unittest.TestCase):
def _makeOne(self):
from cereal import Float
from colander import Float
return Float()
def test_deserialize_fails(self):
@@ -600,12 +600,12 @@ class TestFloat(unittest.TestCase):
class TestBoolean(unittest.TestCase):
def _makeOne(self):
from cereal import Boolean
from colander import Boolean
return Boolean()
def test_alias(self):
from cereal import Bool
from cereal import Boolean
from colander import Bool
from colander import Boolean
self.assertEqual(Bool, Boolean)
def test_deserialize(self):
@@ -633,37 +633,37 @@ class TestBoolean(unittest.TestCase):
class TestGlobalObject(unittest.TestCase):
def _makeOne(self, package=None):
from cereal import GlobalObject
from colander import GlobalObject
return GlobalObject(package)
def test_zope_dottedname_style_resolve_absolute(self):
typ = self._makeOne()
result = typ._zope_dottedname_style(None,
'cereal.tests.TestGlobalObject')
'colander.tests.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test_zope_dottedname_style_irrresolveable_absolute(self):
typ = self._makeOne()
self.assertRaises(ImportError, typ._zope_dottedname_style, None,
'cereal.tests.nonexisting')
'colander.tests.nonexisting')
def test__zope_dottedname_style_resolve_relative(self):
import cereal
typ = self._makeOne(package=cereal)
import colander
typ = self._makeOne(package=colander)
result = typ._zope_dottedname_style(None, '.tests.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__zope_dottedname_style_resolve_relative_leading_dots(self):
import cereal
typ = self._makeOne(package=cereal.tests)
import colander
typ = self._makeOne(package=colander.tests)
result = typ._zope_dottedname_style(None, '..tests.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__zope_dottedname_style_resolve_relative_is_dot(self):
import cereal.tests
typ = self._makeOne(package=cereal.tests)
import colander.tests
typ = self._makeOne(package=colander.tests)
result = typ._zope_dottedname_style(None, '.')
self.assertEqual(result, cereal.tests)
self.assertEqual(result, colander.tests)
def test__zope_dottedname_style_irresolveable_relative_is_dot(self):
typ = self._makeOne()
@@ -679,57 +679,57 @@ class TestGlobalObject(unittest.TestCase):
e.msg, "relative name '.whatever' irresolveable without package")
def test_zope_dottedname_style_irrresolveable_relative(self):
import cereal.tests
typ = self._makeOne(package=cereal)
import colander.tests
typ = self._makeOne(package=colander)
self.assertRaises(ImportError, typ._zope_dottedname_style, None,
'.notexisting')
def test__zope_dottedname_style_resolveable_relative(self):
import cereal
typ = self._makeOne(package=cereal)
import colander
typ = self._makeOne(package=colander)
result = typ._zope_dottedname_style(None, '.tests')
from cereal import tests
from colander import tests
self.assertEqual(result, tests)
def test__zope_dottedname_style_irresolveable_absolute(self):
typ = self._makeOne()
self.assertRaises(ImportError,
typ._zope_dottedname_style, None, 'cereal.fudge.bar')
typ._zope_dottedname_style, None, 'colander.fudge.bar')
def test__zope_dottedname_style_resolveable_absolute(self):
typ = self._makeOne()
result = typ._zope_dottedname_style(None,
'cereal.tests.TestGlobalObject')
'colander.tests.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_resolve_absolute(self):
typ = self._makeOne()
result = typ._pkg_resources_style(None,
'cereal.tests:TestGlobalObject')
'colander.tests:TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_irrresolveable_absolute(self):
typ = self._makeOne()
self.assertRaises(ImportError, typ._pkg_resources_style, None,
'cereal.tests:nonexisting')
'colander.tests:nonexisting')
def test__pkg_resources_style_resolve_relative_startswith_colon(self):
import cereal.tests
typ = self._makeOne(package=cereal.tests)
import colander.tests
typ = self._makeOne(package=colander.tests)
result = typ._pkg_resources_style(None, ':TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_resolve_relative_startswith_dot(self):
import cereal
typ = self._makeOne(package=cereal)
import colander
typ = self._makeOne(package=colander)
result = typ._pkg_resources_style(None, '.tests:TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_resolve_relative_is_dot(self):
import cereal.tests
typ = self._makeOne(package=cereal.tests)
import colander.tests
typ = self._makeOne(package=colander.tests)
result = typ._pkg_resources_style(None, '.')
self.assertEqual(result, cereal.tests)
self.assertEqual(result, colander.tests)
def test__pkg_resources_style_resolve_relative_nocurrentpackage(self):
typ = self._makeOne()
@@ -737,8 +737,8 @@ class TestGlobalObject(unittest.TestCase):
'.whatever')
def test__pkg_resources_style_irrresolveable_relative(self):
import cereal.tests
typ = self._makeOne(package=cereal)
import colander.tests
typ = self._makeOne(package=colander)
self.assertRaises(ImportError, typ._pkg_resources_style, None,
':notexisting')
@@ -749,12 +749,12 @@ class TestGlobalObject(unittest.TestCase):
def test_deserialize_using_pkgresources_style(self):
typ = self._makeOne()
result = typ.deserialize(None, 'cereal.tests:TestGlobalObject')
result = typ.deserialize(None, 'colander.tests:TestGlobalObject')
self.assertEqual(result, self.__class__)
def test_deserialize_using_zope_dottedname_style(self):
typ = self._makeOne()
result = typ.deserialize(None, 'cereal.tests.TestGlobalObject')
result = typ.deserialize(None, 'colander.tests.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test_deserialize_style_raises(self):
@@ -764,10 +764,10 @@ class TestGlobalObject(unittest.TestCase):
"The dotted name 'cant.be.found' cannot be imported")
def test_serialize_ok(self):
import cereal.tests
import colander.tests
typ = self._makeOne()
result = typ.serialize(None, cereal.tests)
self.assertEqual(result, 'cereal.tests')
result = typ.serialize(None, colander.tests)
self.assertEqual(result, 'colander.tests')
def test_serialize_fail(self):
typ = self._makeOne()
@@ -776,7 +776,7 @@ class TestGlobalObject(unittest.TestCase):
class TestStructure(unittest.TestCase):
def _makeOne(self, *arg, **kw):
from cereal import Structure
from colander import Structure
return Structure(*arg, **kw)
def test_new_sets_order(self):
@@ -825,50 +825,50 @@ class TestStructure(unittest.TestCase):
class TestSchema(unittest.TestCase):
def test_alias(self):
from cereal import Schema
from cereal import MappingSchema
from colander import Schema
from colander import MappingSchema
self.assertEqual(Schema, MappingSchema)
def test_it(self):
import cereal
class MySchema(cereal.Schema):
thing = cereal.Structure(cereal.String())
import colander
class MySchema(colander.Schema):
thing = colander.Structure(colander.String())
structure = MySchema(unknown_keys='raise')
self.failUnless(hasattr(structure, '_order'))
self.assertEqual(structure.__class__, cereal.Structure)
self.assertEqual(structure.typ.__class__, cereal.Mapping)
self.assertEqual(structure.__class__, colander.Structure)
self.assertEqual(structure.typ.__class__, colander.Mapping)
self.assertEqual(structure.typ.unknown_keys, 'raise')
self.assertEqual(structure.structs[0].typ.__class__, cereal.String)
self.assertEqual(structure.structs[0].typ.__class__, colander.String)
class TestSequenceSchema(unittest.TestCase):
def test_it(self):
import cereal
class MySchema(cereal.SequenceSchema):
import colander
class MySchema(colander.SequenceSchema):
pass
inner = cereal.Structure(cereal.String())
inner = colander.Structure(colander.String())
structure = MySchema(inner)
self.failUnless(hasattr(structure, '_order'))
self.assertEqual(structure.__class__, cereal.Structure)
self.assertEqual(structure.typ.__class__, cereal.Sequence)
self.assertEqual(structure.__class__, colander.Structure)
self.assertEqual(structure.typ.__class__, colander.Sequence)
self.assertEqual(structure.typ.struct, inner)
class TestTupleSchema(unittest.TestCase):
def test_it(self):
import cereal
class MySchema(cereal.TupleSchema):
thing = cereal.Structure(cereal.String())
import colander
class MySchema(colander.TupleSchema):
thing = colander.Structure(colander.String())
structure = MySchema()
self.failUnless(hasattr(structure, '_order'))
self.assertEqual(structure.__class__, cereal.Structure)
self.assertEqual(structure.typ.__class__, cereal.Tuple)
self.assertEqual(structure.structs[0].typ.__class__, cereal.String)
self.assertEqual(structure.__class__, colander.Structure)
self.assertEqual(structure.typ.__class__, colander.Tuple)
self.assertEqual(structure.structs[0].typ.__class__, colander.String)
class TestFunctional(object):
def test_deserialize_ok(self):
import cereal.tests
import colander.tests
data = {
'int':'10',
'ob':'cereal.tests',
'ob':'colander.tests',
'seq':[('1', 's'),('2', 's'), ('3', 's'), ('4', 's')],
'seq2':[{'key':'1', 'key2':'2'}, {'key':'3', 'key2':'4'}],
'tup':('1', 's'),
@@ -876,7 +876,7 @@ class TestFunctional(object):
schema = self._makeSchema()
result = schema.deserialize(data)
self.assertEqual(result['int'], 10)
self.assertEqual(result['ob'], cereal.tests)
self.assertEqual(result['ob'], colander.tests)
self.assertEqual(result['seq'],
[(1, 's'), (2, 's'), (3, 's'), (4, 's')])
self.assertEqual(result['seq2'],
@@ -911,47 +911,47 @@ class TestFunctional(object):
class TestImperative(unittest.TestCase, TestFunctional):
def _makeSchema(self):
import cereal
import colander
integer = cereal.Structure(
cereal.Integer(),
integer = colander.Structure(
colander.Integer(),
name='int',
validator=cereal.Range(0, 10)
validator=colander.Range(0, 10)
)
ob = cereal.Structure(
cereal.GlobalObject(package=cereal),
ob = colander.Structure(
colander.GlobalObject(package=colander),
name='ob',
)
tup = cereal.Structure(
cereal.Tuple(),
cereal.Structure(
cereal.Integer(),
tup = colander.Structure(
colander.Tuple(),
colander.Structure(
colander.Integer(),
name='tupint',
),
cereal.Structure(
cereal.String(),
colander.Structure(
colander.String(),
name='tupstring',
),
name='tup',
)
seq = cereal.Structure(
cereal.Sequence(tup),
seq = colander.Structure(
colander.Sequence(tup),
name='seq',
)
seq2 = cereal.Structure(
cereal.Sequence(
cereal.Structure(
cereal.Mapping(),
cereal.Structure(
cereal.Integer(),
seq2 = colander.Structure(
colander.Sequence(
colander.Structure(
colander.Mapping(),
colander.Structure(
colander.Integer(),
name='key',
),
cereal.Structure(
cereal.Integer(),
colander.Structure(
colander.Integer(),
name='key2',
),
name='mapping',
@@ -960,8 +960,8 @@ class TestImperative(unittest.TestCase, TestFunctional):
name='seq2',
)
schema = cereal.Structure(
cereal.Mapping(),
schema = colander.Structure(
colander.Mapping(),
integer,
ob,
tup,
@@ -974,22 +974,23 @@ class TestDeclarative(unittest.TestCase, TestFunctional):
def _makeSchema(self):
import cereal
import colander
class TupleSchema(cereal.TupleSchema):
tupint = cereal.Structure(cereal.Int())
tupstring = cereal.Structure(cereal.String())
class TupleSchema(colander.TupleSchema):
tupint = colander.Structure(colander.Int())
tupstring = colander.Structure(colander.String())
class MappingSchema(cereal.MappingSchema):
key = cereal.Structure(cereal.Int())
key2 = cereal.Structure(cereal.Int())
class MappingSchema(colander.MappingSchema):
key = colander.Structure(colander.Int())
key2 = colander.Structure(colander.Int())
class MainSchema(cereal.MappingSchema):
int = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 10))
ob = cereal.Structure(cereal.GlobalObject(package=cereal))
seq = cereal.Structure(cereal.Sequence(TupleSchema()))
class MainSchema(colander.MappingSchema):
int = colander.Structure(colander.Int(),
validator=colander.Range(0, 10))
ob = colander.Structure(colander.GlobalObject(package=colander))
seq = colander.Structure(colander.Sequence(TupleSchema()))
tup = TupleSchema()
seq2 = cereal.SequenceSchema(MappingSchema())
seq2 = colander.SequenceSchema(MappingSchema())
schema = MainSchema()
return schema
@@ -1007,13 +1008,13 @@ class DummyStructure(object):
self.structs = []
def deserialize(self, val):
from cereal import Invalid
from colander import Invalid
if self.exc:
raise Invalid(self, self.exc)
return val
def serialize(self, val):
from cereal import Invalid
from colander import Invalid
if self.exc:
raise Invalid(self, self.exc)
return val
@@ -1023,7 +1024,7 @@ class DummyValidator(object):
self.msg = msg
def __call__(self, struct, value):
from cereal import Invalid
from colander import Invalid
if self.msg:
raise Invalid(struct, self.msg)

View File

@@ -1,10 +1,10 @@
Cereal API
Colander API
----------
Exceptions
~~~~~~~~~~
.. automodule:: cereal
.. automodule:: colander
.. autoclass:: Invalid
:members:

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# cereal documentation build configuration file
# colander documentation build configuration file
#
# This file is execfile()d with the current directory set to its containing
# dir.
@@ -45,7 +45,7 @@ source_suffix = '.rst'
master_doc = 'index'
# General substitutions.
project = 'cereal'
project = 'colander'
copyright = '2010, Repoze Developers <repoze-dev@lists.repoze.org>'
# The default replacements for |version| and |release|, also used in various
@@ -172,7 +172,7 @@ htmlhelp_basename = 'atemplatedoc'
# (source start file, target name, title,
# author, document class [howto/manual]).
latex_documents = [
('index', 'atemplate.tex', 'cereal Documentation',
('index', 'atemplate.tex', 'colander Documentation',
'Repoze Developers', 'manual'),
]

View File

@@ -1,9 +1,9 @@
Cereal
======
Colander
========
Cereal is useful as a system for validating and deserializing data
Colander is useful as a system for validating and deserializing data
obtained via XML, JSON, an HTML form post or any other equally simple
data serialization. Cereal can be used to:
data serialization. Colander can be used to:
- Define a data schema
@@ -14,8 +14,8 @@ data serialization. Cereal can be used to:
- Serialize an arbitrary Python structure to a data structure composed
of strings, mappings, and lists.
Out of the box, Cereal can serialize and deserialize various types of
objects, including:
Out of the box, Colander can serialize and deserialize various types
of objects, including:
- A mapping object (e.g. dictionary)
@@ -35,11 +35,11 @@ objects, including:
- An importable Python object (to a dotted Python object path).
Cereal allows additional data structures to be serialized and
Colander allows additional data structures to be serialized and
deserialized by allowing a developer to define new "types".
Defining A Cereal Schema
------------------------
Defining A Colander Schema
--------------------------
Imagine you want to deserialize and validate a serialization of data
you've obtained by reading a YAML document. An example of such a data
@@ -69,22 +69,24 @@ different types.
.. code-block:: python
:linenos:
import cereal
import colander
class Friend(cereal.TupleSchema):
rank = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 9999))
name = cereal.Structure(cereal.String())
class Friend(colander.TupleSchema):
rank = colander.Structure(colander.Int(),
validator=colander.Range(0, 9999))
name = colander.Structure(colander.String())
class Phone(cereal.MappingSchema):
location = cereal.Structure(cereal.String(),
validator=cereal.OneOf(['home', 'work']))
number = cereal.Structure(cereal.String())
class Phone(colander.MappingSchema):
location = colander.Structure(colander.String(),
validator=colander.OneOf(['home', 'work']))
number = colander.Structure(colander.String())
class Person(cereal.MappingSchema):
name = cereal.Structure(cereal.String())
age = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 200))
friends = cereal.Structure(cereal.Sequence(Friend()))
phones = cereal.Structure(cereal.Sequence(Phone()))
class Person(colander.MappingSchema):
name = colander.Structure(colander.String())
age = colander.Structure(colander.Int(),
validator=colander.Range(0, 200))
friends = colander.Structure(colander.Sequence(Friend()))
phones = colander.Structure(colander.Sequence(Phone()))
For ease of reading, we've actually defined *three* schemas above, but
we coalesce them all into a single ``Person`` schema. As the result
@@ -115,12 +117,12 @@ optional deserialization *validator*, an optional *default*, and a
slightly less optional *name*.
The *type* of a structure indicates its data type (such as
``cereal.Int`` or ``cereal.String``).
``colander.Int`` or ``colander.String``).
The *validator* of a structure is called after deserialization; it
makes sure the deserialized value matches a constraint. An example of
such a validator is provided in the schema above:
``validator=cereal.Range(0, 200)``. A validator is not called after
``validator=colander.Range(0, 200)``. A validator is not called after
serialization, only after deserialization.
The *default* of a structure indicates its default value if a value
@@ -131,35 +133,35 @@ If a structure does not have a default, it is considered required.
The *name* of a structure appears in error reports.
The name of a structure that is introduced as a class-level attribute
of a ``cereal.MappingSchema`` or ``cereal.TupleSchema`` is its class
attribute name. For example:
of a ``colander.MappingSchema`` or ``colander.TupleSchema`` is its
class attribute name. For example:
.. code-block:: python
:linenos:
import cereal
import colander
class Phone(cereal.MappingSchema):
location = cereal.Structure(cereal.String(),
validator=cereal.OneOf(['home', 'work']))
number = cereal.Structure(cereal.String())
class Phone(colander.MappingSchema):
location = colander.Structure(colander.String(),
validator=colander.OneOf(['home', 'work']))
number = colander.Structure(colander.String())
The name of the structure defined via ``location =
cereal.Structure(..)`` within the schema above is ``location``.
colander.Structure(..)`` within the schema above is ``location``.
Schema Objects
~~~~~~~~~~~~~~
The result of creating an instance of a ``cereal.MappingSchema`` or
``cereal.TupleSchema`` object is also a *structure* object.
The result of creating an instance of a ``colander.MappingSchema`` or
``colander.TupleSchema`` object is also a *structure* object.
Instantiating a ``cereal.MappingSchema`` creates a structure which has
a *type* value of ``cereal.Mapping``. Instantiating a
``cereal.TupleSchema`` creates a structure which has a *type* value of
``cereal.Tuple``.
Instantiating a ``colander.MappingSchema`` creates a structure which
has a *type* value of ``colander.Mapping``. Instantiating a
``colander.TupleSchema`` creates a structure which has a *type* value
of ``colander.Tuple``.
A structure defined by instantiating a ``cereal.MappingSchema`` or a
``cereal.TupleSchema`` usually has no validator, and has the empty
A structure defined by instantiating a ``colander.MappingSchema`` or a
``colander.TupleSchema`` usually has no validator, and has the empty
string as its name.
Deserializing A Data Structure Using a Schema
@@ -170,22 +172,24 @@ Earlier we defined a schema:
.. code-block:: python
:linenos:
import cereal
import colander
class Friend(cereal.TupleSchema):
rank = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 9999))
name = cereal.Structure(cereal.String())
class Friend(colander.TupleSchema):
rank = colander.Structure(colander.Int(),
validator=colander.Range(0, 9999))
name = colander.Structure(colander.String())
class Phone(cereal.MappingSchema):
location = cereal.Structure(cereal.String(),
validator=cereal.OneOf(['home', 'work']))
number = cereal.Structure(cereal.String())
class Phone(colander.MappingSchema):
location = colander.Structure(colander.String(),
validator=colander.OneOf(['home', 'work']))
number = colander.Structure(colander.String())
class Person(cereal.MappingSchema):
name = cereal.Structure(cereal.String())
age = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 200))
friends = cereal.Structure(cereal.Sequence(Friend()))
phones = cereal.Structure(cereal.Sequence(Phone()))
class Person(colander.MappingSchema):
name = colander.Structure(colander.String())
age = colander.Structure(colander.Int(),
validator=colander.Range(0, 200))
friends = colander.Structure(colander.Sequence(Friend()))
phones = colander.Structure(colander.Sequence(Phone()))
Let's now use this schema to try to deserialize some concrete data
structures.
@@ -237,7 +241,7 @@ or a validation error?
.. code-block:: python
:linenos:
import cereal
import colander
data = {
'name':'keith',
@@ -249,7 +253,7 @@ or a validation error?
schema = Person()
try:
schema.deserialize(data)
except cereal.Invalid, e:
except colander.Invalid, e:
print e.asdict()
The ``deserialize`` method will raise an exception, and the ``except``
@@ -278,53 +282,56 @@ Defining A Schema Imperatively
The above schema we defined was defined declaratively via a set of
``class`` statements. It's often useful to create schemas more
dynamically. For this reason, Cereal offers an "imperative" mode of
dynamically. For this reason, Colander offers an "imperative" mode of
schema configuration. Here's our previous declarative schema:
.. code-block:: python
:linenos:
import cereal
import colander
class Friend(cereal.TupleSchema):
rank = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 9999))
name = cereal.Structure(cereal.String())
class Friend(colander.TupleSchema):
rank = colander.Structure(colander.Int(),
validator=colander.Range(0, 9999))
name = colander.Structure(colander.String())
class Phone(cereal.MappingSchema):
location = cereal.Structure(cereal.String(),
validator=cereal.OneOf(['home', 'work']))
number = cereal.Structure(cereal.String())
class Phone(colander.MappingSchema):
location = colander.Structure(colander.String(),
validator=colander.OneOf(['home', 'work']))
number = colander.Structure(colander.String())
class Person(cereal.MappingSchema):
name = cereal.Structure(cereal.String())
age = cereal.Structure(cereal.Int(), validator=cereal.Range(0, 200))
friends = cereal.Structure(cereal.Sequence(Friend()))
phones = cereal.Structure(cereal.Sequence(Phone()))
class Person(colander.MappingSchema):
name = colander.Structure(colander.String())
age = colander.Structure(colander.Int(),
validator=colander.Range(0, 200))
friends = colander.Structure(colander.Sequence(Friend()))
phones = colander.Structure(colander.Sequence(Phone()))
We can imperatively construct a completely equivalent schema like so:
.. code-block:: python
:linenos:
import cereal
import colander
friend = cereal.Structure(Tuple())
friend.add(cereal.Structure(cereal.Int(), validator=cereal.Range(0, 9999),
friend = colander.Structure(Tuple())
friend.add(colander.Structure(colander.Int(),
validator=colander.Range(0, 9999),
name='rank'))
friend.add(cereal.Structure(cereal.String()), name='name')
friend.add(colander.Structure(colander.String()), name='name')
phone = cereal.Structure(Mapping())
phone.add(cereal.Structure(cereal.String(),
validator=cereal.OneOf(['home', 'work']),
name='location'))
phone.add(cereal.Structure(cereal.String(), name='number'))
phone = colander.Structure(Mapping())
phone.add(colander.Structure(colander.String(),
validator=colander.OneOf(['home', 'work']),
name='location'))
phone.add(colander.Structure(colander.String(), name='number'))
schema = cereal.Structure(Mapping())
schema.add(cereal.Structure(cereal.String(), name='name'))
schema.add(cereal.Structure(cereal.Int(), name='age'),
validator=cereal.Range(0, 200))
schema.add(cereal.Structure(cereal.Sequence(friend), name='friends'))
schema.add(cereal.Structure(cereal.Sequence(phone), name='phones'))
schema = colander.Structure(Mapping())
schema.add(colander.Structure(colander.String(), name='name'))
schema.add(colander.Structure(colander.Int(), name='age'),
validator=colander.Range(0, 200))
schema.add(colander.Structure(colander.Sequence(friend), name='friends'))
schema.add(colander.Structure(colander.Sequence(phone), name='phones'))
Defining a schema imperatively is a lot uglier than defining a schema
declaratively, but it's often more useful when you need to define a
@@ -385,10 +392,10 @@ Here's how you would use the resulting class as part of a schema:
.. code-block:: python
:linenos:
import cereal
import colander
class Schema(cereal.MappingSchema):
interested = cereal.Structure(Boolean())
class Schema(colander.MappingSchema):
interested = colander.Structure(Boolean())
The above schema has a member named ``interested`` which will now be
serialized and deserialized as a boolean, according to the logic
@@ -399,15 +406,16 @@ Note that the only real constraint of a type class is that its
by its ``deserialize`` method and vice versa.
For a more formal definition of a the interface of a type, see
:class:`cereal.interfaces.Type`.
:class:`colander.interfaces.Type`.
Defining a New Validator
------------------------
A validator is a callable which accepts two positional arguments:
``struct`` and ``value``. It returns ``None`` if the value is valid.
It raises a ``cereal.Invalid`` exception if the value is not valid.
Here's a validator that checks if the value is a valid credit card number.
It raises a ``colander.Invalid`` exception if the value is not valid.
Here's a validator that checks if the value is a valid credit card
number.
.. code-block:: python
:linenos:
@@ -438,18 +446,18 @@ schema:
.. code-block:: python
:linenos:
import cereal
import colander
class Schema(cereal.MappingSchema):
cc_number = cereal.Structure(cereal.String(), validator=lunhnok)
class Schema(colander.MappingSchema):
cc_number = colander.Structure(colander.String(), validator=lunhnok)
Note that the validator doesn't need to check if the ``value`` is a
string: this has already been done as the result of the type of the
``cc_number`` structure being ``cereal.String``. Validators are always
passed the *deserialized* value when they are invoked.
``cc_number`` structure being ``colander.String``. Validators are
always passed the *deserialized* value when they are invoked.
For a more formal definition of a the interface of a validator, see
:class:`cereal.interfaces.Validator`.
:class:`colander.interfaces.Validator`.
Interface and API Documentation
-------------------------------

View File

@@ -1,7 +1,7 @@
Interfaces
----------
.. automodule:: cereal.interfaces
.. automodule:: colander.interfaces
.. autofunction:: Validator

View File

@@ -3,8 +3,8 @@ zip_ok = false
[nosetests]
match=^test
where=cereal
where=colander
nocapture=1
cover-package=cereal
cover-package=colander
cover-erase=1

View File

@@ -23,7 +23,7 @@ CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
requires = []
setup(name='cereal',
setup(name='colander',
version='0.0',
description=('A simple schema-based serialization and deserialization '
'library'),
@@ -35,13 +35,13 @@ setup(name='cereal',
keywords='serialize deserialize validate schema validation',
author="Agendaless Consulting",
author_email="repoze-dev@lists.repoze.org",
url="http://docs.repoze.org/cereal",
url="http://docs.repoze.org/colander",
license="BSD-derived (http://www.repoze.org/LICENSE.txt)",
packages=find_packages(),
include_package_data=True,
zip_safe=False,
tests_require = requires,
install_requires = requires,
test_suite="cereal",
test_suite="colander",
)