Skip to content

Instantly share code, notes, and snippets.

@ojacobson
Created December 4, 2012 20:29
Show Gist options
  • Save ojacobson/4208345 to your computer and use it in GitHub Desktop.
Save ojacobson/4208345 to your computer and use it in GitHub Desktop.
def jsonizable(atoms=(), lists=(), objects=()):
"""Adds a `to_json` method to decorated classes:
>>> @jsonizable(atoms=['name', 'age'])
... class Example(object):
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
>>> e = Example('bob', 37)
>>> e.to_json()
{'age': 37, 'name': 'bob'}
JSON fields containing nested lists or collections must be handled specially:
>>> @jsonizable(atoms=['name'])
... class Person(object):
... def __init__(self, name):
... self.name = name
...
>>> @jsonizable(lists=['students'], objects=['teacher'])
... class Classroom(object):
... def __init__(self, students, teacher):
... self.students = students
... self.teacher = teacher
...
>>> students = [Person('bob'), Person('anne')]
>>> teacher = Person('clarice')
>>> classroom = Classroom(students, teacher)
>>> classroom.to_json()
{'students': [{'name': 'bob'}, {'name': 'anne'}], 'teacher': {'name': 'clarice'}}
The generated to_json method returns a `dict`, allowing callers to further
manipulate the JSON data before returning it.
The fields to include in the resulting `dict` are given by the optional
`atoms`, `lists`, and `objects` keyword arguments. Values from attributes
named in `atoms` will be included in the dict using the equivalent of
`getattr(self, atom_attr)`. Values of attributes named in `lists` will be
turned into lists using the equivalent of
`[v.to_json() for v in getattr(self, list_attr)]`. Values of attributes
named in `objects` will be turned into nested JSON values using the
equivalent of `getattr(self, obj_attr).to_json()`. Both `lists` and
`objects` attributes are checked for `None`, and will be included in the
resulting dict with `None`.
You can, additionally, overlay values or computed values onto the JSON
representation by passing the optional `overlay` parameter as a dictionary
of callables:
>>> @jsonizable(atoms=['name'])
... class Person(object):
... def __init__(self, name):
... self.name = name
...
>>> @jsonizable(lists=['students'], objects=['teacher'])
... class Classroom(object):
... def __init__(self, students, teacher):
... self.students = students
... self.teacher = teacher
...
>>> students = [Person('bob')]
>>> teacher = Person('clarice')
>>> classroom = Classroom(students, teacher)
>>> classroom.to_json(overlay=dict(
... address=lambda classroom: '1 Infinite Loop',
... students=dict(
... hat_size=lambda student: 'Large'
... )
... ))
{'students': [{'name': 'bob', 'hat_size': 'Large'}], 'teacher': {'name': 'clarice'}, 'address': '1 Infinite Loop'}
"""
def to_json(self, overlay=None):
"""Returns a JSON representation of this object."""
if overlay is None:
overlay = dict()
return _to_json(self, atoms, lists, objects, overlay)
def decorator(cls):
cls.to_json = to_json
return cls
return decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment