Package: serialobj
A SerialObject is an object that supports serialization from/to json-like
objects (dicts and lists of builtin types).The serialization specification is taken from the__fields__class attribute,
which is on the form:__fields__: {
    FIELD_NAME: FIELD_SPEC
}A FIELD_NAME is a string, its only constraint is that it should be a valid
object attribute name.FIELD_SPEC can be:Any native type from:strunicode(Python2)intfloatbooldictASerialObjectsubclassChoice(val1, val2,...)to form enumerations, values should be of anative type (see above).[FIELD_SPEC]: a list of objects depicted by the above specs.Additionally, SerialObjects support a__strict__boolean class attribute
(False by default). When__strict__== True, an exhaustivity check is performed
during (de-)serialization and missing or unknown keys yield errors.On Python2,strinstances are automatically coerced to unicode strings.Installserialobjis registered on the PyPi. Simply type the following commands.pip install serialobjAlternatively, you can run the following commands after having cloned the
source repository:python setup.py installQuick tutorialSimple types and inheritanceLet us define a very basic Person type that defines two string fields:class Person(SerialObject):
    __fields__ = {
        'name': str,
        'job': str
    }Now we can simply deserialize json-compatible data to it, and/or serialize its
instances to a json-like structure:>>> person_data = {
...     'name': 'Bob',
...     'job': 'lumberjack'
... }
>>> bob = Person.deserialize(person_data)
>>> bob.name
'Bob'
>>> bob.job
'lumberjack'
>>> bob.serialize()
{'job': 'lumberjack', 'name': 'Bob'}Of course there is more to it than that. Let us subclass ourPerson, to
define, for instance aTeamMate, which overrides thejobfield to allow it
to be adictand to add a newstrfield:role.class TeamMate(Person):
    __fields__ = {
        'role': str,
        'job': dict
    }Of course this is a silly example, but this allows us to demonstrate that
inheriting aSerialObjectclass allows to inherit, override and specialize
the structure definition :>>> bob2 = TeamMate.deserialize(teammate_data)
>>> bob2.name
'Bob'
>>> bob2.job
{'all night': 'sleep', 'all day': 'work'}
>>> bob2.serialize()
{'role': 'lumberjack', 'name': 'Bob', 'job': {'all night': 'sleep', 'all day': 'work'}}It also allows us to demonstrate that the structure is actuallycheckedagainst the model: let’s try and deserialize ourteammate_datawith the
incompatiblePersonmodel.>>> Person.deserialize(teammate_data)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    Person.deserialize(teammate_data)
  File "/home/arnaud/work/serialobj/serialobj.py", line 242, in deserialize
    for key, val in data.items() if key in cls.__fields__
  File "/home/arnaud/work/serialobj/serialobj.py", line 242, in <dictcomp>
    for key, val in data.items() if key in cls.__fields__
  File "/home/arnaud/work/serialobj/serialobj.py", line 86, in deserialize
    .format(self.cls_.__name__, data))
serialobj.InvalidTypeError: Expected str, got {'all night': 'sleep', 'all day': 'work'}Isn’t it starting to get interesting?List of objectsLet us spice it up a little bit. What if I want to define a field as alist of
strings?Well, there is some sugar for this:class Task(SerialObject):
    __fields__ = {
        'title': str,
        'description': str,
        'checklist': [str]
    }See for yourself:>>> data = {
...     'title': 'timber some wood',
...     'description': '',
...     'checklist': [
...         'some wood is timbered',
...         'the lumberjack is okay',
...         'he sleeps all night and works all day'
...     ]
... }
>>> tsk = Task.deserialize(data)
>>> tsk.checklist
['some wood is timbered', 'the lumberjack is okay', 'he sleeps all night and works all day']
>>> tsk.checklist.append("... and that's it")
>>> pprint(tsk.serialize())
{'checklist': ['some wood is timbered',
               'the lumberjack is okay',
               'he sleeps all night and works all day',
               "... and that's it"],
 'description': '',
 'title': 'timber some wood'}Going fancyOf course, all these are the base building blocks to define arbitrarily
complex JSON-API structures:class Team(SerialObject):
    __fields__ = {
        'name': str,
        'manager': TeamMate,
        'members': [TeamMate],
        'backlog': [Task]
    }


COMPLEX_DATA = {
    'name': "The good ol' lumberjacks",
    'manager': {
        'name': 'Bob',
        'role': 'Be okay'
    },
    'members': [
        {
            'name': 'Jack',
            'role': 'sleep all night'
        },
        {
            'name': 'Barry',
            'role': 'work all day',
        }],
    'backlog': [
        {
            'title': 'timber some wood',
            'description': '',
            'checklist': [
                'some wood is timbered',
                'the lumberjack is okay',
                'he sleeps all night and works all day'
            ]
        }]
    }Here we go:>>> team = Team.deserialize(COMPLEX_DATA)
>>> team.manager.name
'Bob'
>>> team.manager
<__console__.TeamMate object at 0x7f34edd2c9a8>
>>> team.backlog[0]
<__console__.Task object at 0x7f34edd9b7c8>
>>> team.backlog[0].title
'timber some wood'
>>> pprint(team.serialize())
{'backlog': [{'checklist': ['some wood is timbered',
                            'the lumberjack is okay',
                            'he sleeps all night and works all day'],
              'description': '',
              'title': 'timber some wood'}],
 'manager': {'name': 'Bob', 'role': 'Be okay'},
 'members': [{'name': 'Jack', 'role': 'sleep all night'},
             {'name': 'Barry', 'role': 'work all day'}],
 'name': "The good ol' lumberjacks"}TestingYou can trigger all tests usingtox. Tests are currently run for python
2.7 and 3.5.