Source code for yael.jsonable

#!/usr/bin/env python
# coding=utf-8

"""
A generic object which
has a JSON object/string representation.

This class is "abstract",
assigning the task of implementing
the abstract function
:func:`yael.jsonable.JSONAble.json_object`
to each concrete subclass,
according to the suitable element semantics.
"""

import json

__author__ = "Alberto Pettarin"
__copyright__ = "Copyright 2015, Alberto Pettarin (www.albertopettarin.it)"
__license__ = "MIT"
__version__ = "0.0.6"
__email__ = "alberto@albertopettarin.it"
__status__ = "Development"

[docs]class JSONAble(object): """ A generic object which has a JSON object/string representation. """
[docs] def json_object(self, recursive=True): """ To be implemented in concrete subclasses. :param recursive: if True, append JSON sub-objects :type recursive: bool :returns: object that can be output as a JSON string :rtype: dict """ return
def __str__(self): return self.json_string(pretty=True)
[docs] def json_string( self, recursive=True, pretty=False, indent=4, sort=False, clean=False): """ Format a JSON string representation of the object. :param recursive: if True, append JSON sub-objects :type recursive: bool :param pretty: if True, pretty print the string :type pretty: bool :param indent: the number of spaces for each indentation level :type indent: integer :param sort: if True, sort the keys :type sort: bool :param clean: if True, remove None values and empty lists/dictionaries :type clean: bool :returns: a JSON representation of the object :rtype: str """ try: obj = self.json_object(recursive=recursive) if clean: obj = JSONAble.clean(obj) if pretty: return json.dumps( obj, sort_keys=sort, indent=indent, separators=(',', ': ')) else: return json.dumps(obj) except: pass return "{}"
@staticmethod
[docs] def safe(obj): """ Return a JSON-safe representation of the given object. If `obj` is a list, return a list whose elements are the safe(...) version of the original elements, otherwise return the result of :func:`yael.jsonable.JSONAble.json_object`. The result might be None, if `obj` is invalid. :param obj: the object to represent :type obj: (list of) :class:`yael.jsonable.JSONAble` :returs: a JSON-safe representation of the object :rtype: object """ if obj != None: try: if isinstance(obj, list): accumulator = [] for obj_elem in obj: accumulator.append(JSONAble.safe(obj_elem)) return accumulator else: return obj.json_object() except: pass return None # TODO find a better way of doing this
@staticmethod
[docs] def clean(obj): """ Recursively "clean" the given object by removing: 1. None values, 2. empty dictionaries, and 3. empty lists. Note that this function works on the given object, altering it in place. Pass a copy of the original object if you want to avoid side effects. :param obj: the object to clean :type obj: value, list or dict :returns: a cleaned version (possibly, None) of the given object :rtype: object """ if isinstance(obj, dict): if len(obj) < 1: obj = None return obj for key, value in obj.items(): if value is None: del obj[key] elif isinstance(value, dict) or isinstance(value, list): if JSONAble.clean(value) == None: del obj[key] elif isinstance(obj, list): if len(obj) < 1: obj = None return obj tmp = [] for value in obj: clean_value = JSONAble.clean(value) if clean_value != None: tmp.append(clean_value) if len(tmp) == 0: obj = None else: obj = tmp return obj