''' Created on 2011-10-11 @author: jacekf Responsible for converting return values into cleanly serializable dict/tuples/lists for JSON/XML/YAML output ''' import collections import logging import json from twisted.python import log primitives = (int, float, bool, str,str) def convertForSerialization(obj): """Converts anything (clas,tuples,list) to the safe serializable equivalent""" try: if type(obj) in primitives: # no conversion return obj elif isinstance(obj, dict): return traverseDict(obj) elif isClassInstance(obj): return convertClassToDict(obj) elif isinstance(obj,collections.Iterable) and not isinstance(obj,str): # iterable values = [] for val in obj: values.append(convertForSerialization(val)) return values else: # return as-is return obj except AttributeError as ex: log.msg(ex,logLevel=logging.WARN) return obj def convertClassToDict(clazz): """Converts a class to a dictionary""" properties = {} for prop,val in clazz.__dict__.items(): #omit private fields if not prop.startswith("_"): properties[prop] = val return traverseDict(properties) def traverseDict(dictObject): """Traverses a dict recursively to convertForSerialization any nested classes""" newDict = {} for prop,val in dictObject.items(): newDict[prop] = convertForSerialization(val) return newDict def convertToJson(obj): """Converts to JSON, including Python classes that are not JSON serializable by default""" try: return json.dumps(obj) except Exception as ex: raise RuntimeError(str(ex)) def generateXml(obj): """Generates basic XML from an object that has already been converted for serialization""" if isinstance(obj, dict): return getXML_dict(obj, "item") elif isinstance(obj,collections.Iterable): return "%s" % getXML(obj, "item") else: raise RuntimeError("Unable to convert to XML: %s" % obj) def isClassInstance(obj): """Checks if a given obj is a class instance""" return getattr(obj, "__class__",None) != None and not isinstance(obj,dict) and not isinstance(obj,tuple) and not isinstance(obj,list) and not isinstance(obj,str) ## {{{ http://code.activestate.com/recipes/440595/ (r2) def getXML(obj, objname=None): """getXML(obj, objname=None) returns an object as XML where Python object names are the tags. >>> u={'UserID':10,'Name':'Mark','Group':['Admin','Webmaster']} >>> getXML(u,'User') '10MarkAdminWebmaster' """ if obj == None: return "" if not objname: objname = "item" adapt={ dict: getXML_dict, list: getXML_list, tuple: getXML_list, } if obj.__class__ in adapt: return adapt[obj.__class__](obj, objname) else: return "<%(n)s>%(o)s"%{'n':objname,'o':str(obj)} def getXML_dict(indict, objname=None): h = "<%s>"%objname for k, v in list(indict.items()): h += getXML(v, k) h += ""%objname return h def getXML_list(inlist, objname=None): h = "" for i in inlist: h += getXML(i, objname) return h ## end of http://code.activestate.com/recipes/440595/ }}}