Add a declarative mode.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import pkg_resources
|
||||
import itertools
|
||||
|
||||
def resolve_dotted(dottedname, package=None):
|
||||
if dottedname.startswith('.') or dottedname.startswith(':'):
|
||||
@@ -310,6 +311,8 @@ class Integer(object):
|
||||
def deserialize(self, struct, value):
|
||||
return self._validate(struct, value)
|
||||
|
||||
Int = Integer
|
||||
|
||||
class GlobalObject(object):
|
||||
""" A type representing an importable Python object """
|
||||
def __init__(self, package):
|
||||
@@ -331,12 +334,19 @@ class GlobalObject(object):
|
||||
'The dotted name %r cannot be imported' % value)
|
||||
|
||||
class Structure(object):
|
||||
def __init__(self, name, typ, *structs, **kw):
|
||||
self.name = name
|
||||
_counter = itertools.count()
|
||||
|
||||
def __new__(cls, *arg, **kw):
|
||||
inst = object.__new__(cls)
|
||||
inst._order = cls._counter.next()
|
||||
return inst
|
||||
|
||||
def __init__(self, typ, *structs, **kw):
|
||||
self.typ = typ
|
||||
self.validator = kw.get('validator', None)
|
||||
self.default = kw.get('default', None)
|
||||
self.required = kw.get('required', True)
|
||||
self.name = kw.get('name', '')
|
||||
self.structs = list(structs)
|
||||
|
||||
def serialize(self, value):
|
||||
@@ -351,3 +361,44 @@ class Structure(object):
|
||||
def add(self, struct):
|
||||
self.structs.append(struct)
|
||||
|
||||
class _SchemaMeta(type):
|
||||
def __init__(cls, name, bases, clsattrs):
|
||||
structs = []
|
||||
for name, value in clsattrs.items():
|
||||
if isinstance(value, Structure):
|
||||
value.name = name
|
||||
structs.append((value._order, value))
|
||||
cls.__schema_structures__ = structs
|
||||
# Combine all attrs from this class and its subclasses.
|
||||
extended = []
|
||||
for c in cls.__mro__:
|
||||
extended.extend(getattr(c, '__schema_structures__', []))
|
||||
# Sort the attrs to maintain the order as defined, and assign to the
|
||||
# class.
|
||||
extended.sort()
|
||||
cls.structs = [x[1] for x in extended]
|
||||
|
||||
class Schema(object):
|
||||
struct_type = Mapping
|
||||
__metaclass__ = _SchemaMeta
|
||||
|
||||
def __new__(cls, *args, **kw):
|
||||
inst = object.__new__(Structure)
|
||||
inst.name = None
|
||||
inst._order = Structure._counter.next()
|
||||
struct = cls.struct_type(*args, **kw)
|
||||
inst.__init__(struct)
|
||||
for s in cls.structs:
|
||||
inst.add(s)
|
||||
return inst
|
||||
|
||||
MappingSchema = Schema
|
||||
|
||||
class SequenceSchema(Schema):
|
||||
struct_type = Sequence
|
||||
|
||||
class TupleSchema(Schema):
|
||||
struct_type = Tuple
|
||||
|
||||
|
||||
|
||||
|
150
cereal/tests.py
150
cereal/tests.py
@@ -1,67 +1,6 @@
|
||||
import unittest
|
||||
|
||||
class TestFunctional(unittest.TestCase):
|
||||
def _makeSchema(self):
|
||||
import cereal
|
||||
|
||||
integer = cereal.Structure(
|
||||
'int',
|
||||
cereal.Integer(),
|
||||
validator=cereal.Range(0, 10)
|
||||
)
|
||||
|
||||
ob = cereal.Structure(
|
||||
'ob',
|
||||
cereal.GlobalObject(package=cereal),
|
||||
)
|
||||
|
||||
tup = cereal.Structure(
|
||||
'tup',
|
||||
cereal.Tuple(),
|
||||
cereal.Structure(
|
||||
'tupint',
|
||||
cereal.Integer(),
|
||||
),
|
||||
cereal.Structure(
|
||||
'tupstring',
|
||||
cereal.String(),
|
||||
),
|
||||
)
|
||||
|
||||
seq = cereal.Structure(
|
||||
'seq',
|
||||
cereal.Sequence(tup),
|
||||
)
|
||||
|
||||
seq2 = cereal.Structure(
|
||||
'seq2',
|
||||
cereal.Sequence(
|
||||
cereal.Structure(
|
||||
'mapping',
|
||||
cereal.Mapping(),
|
||||
cereal.Structure(
|
||||
'key',
|
||||
cereal.Integer(),
|
||||
),
|
||||
cereal.Structure(
|
||||
'key2',
|
||||
cereal.Integer(),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
schema = cereal.Structure(
|
||||
None,
|
||||
cereal.Mapping(),
|
||||
integer,
|
||||
ob,
|
||||
tup,
|
||||
seq,
|
||||
seq2)
|
||||
|
||||
return schema
|
||||
|
||||
class TestFunctional(object):
|
||||
def test_deserialize_ok(self):
|
||||
import cereal.tests
|
||||
data = {
|
||||
@@ -108,3 +47,90 @@ class TestFunctional(unittest.TestCase):
|
||||
except cereal.Invalid, e:
|
||||
errors = e.asdict()
|
||||
self.assertEqual(errors, expected)
|
||||
|
||||
class TestImperative(unittest.TestCase, TestFunctional):
|
||||
|
||||
def _makeSchema(self):
|
||||
import cereal
|
||||
|
||||
integer = cereal.Structure(
|
||||
cereal.Integer(),
|
||||
name='int',
|
||||
validator=cereal.Range(0, 10)
|
||||
)
|
||||
|
||||
ob = cereal.Structure(
|
||||
cereal.GlobalObject(package=cereal),
|
||||
name='ob',
|
||||
)
|
||||
|
||||
tup = cereal.Structure(
|
||||
cereal.Tuple(),
|
||||
cereal.Structure(
|
||||
cereal.Integer(),
|
||||
name='tupint',
|
||||
),
|
||||
cereal.Structure(
|
||||
cereal.String(),
|
||||
name='tupstring',
|
||||
),
|
||||
name='tup',
|
||||
)
|
||||
|
||||
seq = cereal.Structure(
|
||||
cereal.Sequence(tup),
|
||||
name='seq',
|
||||
)
|
||||
|
||||
seq2 = cereal.Structure(
|
||||
cereal.Sequence(
|
||||
cereal.Structure(
|
||||
cereal.Mapping(),
|
||||
cereal.Structure(
|
||||
cereal.Integer(),
|
||||
name='key',
|
||||
),
|
||||
cereal.Structure(
|
||||
cereal.Integer(),
|
||||
name='key2',
|
||||
),
|
||||
name='mapping',
|
||||
)
|
||||
),
|
||||
name='seq2',
|
||||
)
|
||||
|
||||
schema = cereal.Structure(
|
||||
cereal.Mapping(),
|
||||
integer,
|
||||
ob,
|
||||
tup,
|
||||
seq,
|
||||
seq2)
|
||||
|
||||
return schema
|
||||
|
||||
class TestDeclarative(unittest.TestCase, TestFunctional):
|
||||
|
||||
def _makeSchema(self):
|
||||
|
||||
import cereal
|
||||
|
||||
class TupleSchema(cereal.TupleSchema):
|
||||
tupint = cereal.Structure(cereal.Int())
|
||||
tupstring = cereal.Structure(cereal.String())
|
||||
|
||||
class MappingSchema(cereal.MappingSchema):
|
||||
key = cereal.Structure(cereal.Int())
|
||||
key2 = cereal.Structure(cereal.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()))
|
||||
tup = TupleSchema()
|
||||
seq2 = cereal.SequenceSchema(MappingSchema())
|
||||
|
||||
schema = MainSchema()
|
||||
return schema
|
||||
|
||||
|
Reference in New Issue
Block a user