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:
str
unicode (Python2)
int
float
bool
dict
A SerialObject subclass
- Choice(val1, val2, ...) to form enumerations, values should be of a
native 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, str instances are automatically coerced to unicode strings.
Install
serialobj is registered on the PyPi. Simply type the following commands.
pip install serialobj
Alternatively, you can run the following commands after having cloned the source repository:
python setup.py install
Quick tutorial
Simple types and inheritance
Let 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 our Person, to define, for instance a TeamMate, which overrides the job field to allow it to be a dict and to add a new str field: role.
class TeamMate(Person):
__fields__ = {
'role': str,
'job': dict
}
Of course this is a silly example, but this allows us to demonstrate that inheriting a SerialObject class 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 actually checked against the model: let’s try and deserialize our teammate_data with the incompatible Person model.
>>> 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 objects
Let us spice it up a little bit. What if I want to define a field as a list 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 fancy
Of 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"}
Testing
You can trigger all tests using tox. Tests are currently run for python 2.7 and 3.5.
Metadata
Release files for serialobj 0.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| serialobj-0.8.1.tar.gz | 6.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| serialobj-0.8.1-py2.py3-none-any.whl | Python 2, Python 3 | none | any | Details |
Total release size: 16.3 kB
Release files / serialobj-0.8.1.tar.gz
| Download URL | serialobj-0.8.1.tar.gz |
|---|---|
| Size | 6.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a30da360e43169553133b29639fd868ebabf5e9cc38ee2a9ff0757d27ee8303d
|
|
BLAKE2b-256 checksum How to use checksums |
1657daa7187f0be25b2c5ec04f22bf4f38aca3346f8e75298c908e13705fa69c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Release files / serialobj-0.8.1-py2.py3-none-any.whl
| Download URL | serialobj-0.8.1-py2.py3-none-any.whl |
|---|---|
| Size | 9.6 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
9b428adb3523072c77aab01a2f92fdc29835aec9fd86fa2c4cc6f41d0fb37f42
|
|
BLAKE2b-256 checksum How to use checksums |
95ef222a6a7022ac747e3c35d9ac105f27e62aced63e1de8e51fa0f7dae3f1d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |