Source code for bastio.mixin
# Copyright 2013 Databracket LLC
# See LICENSE file for details.
"""
:module: bastio.mixin
:synopsis: Mixins utilities used across the project.
:author: Amr Ali <amr@databracket.com>
.. rst-class:: html-toggle
Metaclasses
-----------
.. autoclass:: SingletonAbstractMeta
.. autoclass:: KindSingletonMeta
.. autoclass:: UniqueSingletonMeta
.. rst-class:: html-toggle
Data Structure Mixins
---------------------
.. autoclass:: Json
:members:
"""
__author__ = "Amr Ali"
__copyright__ = "Copyright 2013 Databracket LLC"
__license__ = "GPLv3+"
import json
from itertools import imap, ifilter
from ast import literal_eval
from collections import defaultdict
def public(obj):
"""A decorator to avoid retyping function/class names in __all__."""
import sys
_all = sys.modules[obj.__module__].__dict__.setdefault('__all__', [])
if obj.__name__ not in _all:
_all.append(obj.__name__)
return obj
@public
@public
@public
[docs]class Json(object):
"""A mixin to give objects the ability to serialize and deserialize to/from
JSON formatted string.
"""
[docs] def to_json(self):
"""Serialize current object's members to a JSON formatted string.
This function will only serialize members that don't start with ``_``
or a ``callable``.
:returns:
A JSON formatted string.
"""
res = {}
for key, value in self.__dict__.iteritems():
if key.startswith('_') or callable(value):
continue
if isinstance(value, self.__class__):
res.update({ key: literal_eval(value.to_json()) })
else:
res.update({ key: value })
return json.dumps(res)
[docs] def from_json(self, json_string):
"""Deserialize a JSON formatted string and populate the current object
with members of the name and value provided in the JSON string.
:returns:
``self``
"""
obj = json.loads(json_string)
for key, value in obj.iteritems():
if isinstance(value, dict):
self.__dict__[key] = Json()
self.__dict__[key].__dict__.update(value)
else:
self.__dict__[key] = value
return self
def __contains__(self, field):
"""Check whether a certain field exists in this object.
:param field:
The field name to be checked against __dict__.
:type field:
str
:returns:
bool
"""
return field in imap(lambda x: x[0], ifilter(
lambda x: not(x[0].startswith('_') or callable(x[1])),
self.__dict__.iteritems()))