X-Git-Url: http://xvm.mit.edu/gitweb/invirt/packages/python-jsonrpclib.git/blobdiff_plain/ccb16ea1a5f000b5014f562467056e788ff7eed4..669c1369c82b5dec6fd7952dce27a41ac1690b11:/jsonrpclib/jsonclass.py diff --git a/jsonrpclib/jsonclass.py b/jsonrpclib/jsonclass.py new file mode 100644 index 0000000..298c3da --- /dev/null +++ b/jsonrpclib/jsonclass.py @@ -0,0 +1,145 @@ +import types +import inspect +import re +import traceback + +from jsonrpclib import config + +iter_types = [ + types.DictType, + types.ListType, + types.TupleType +] + +string_types = [ + types.StringType, + types.UnicodeType +] + +numeric_types = [ + types.IntType, + types.LongType, + types.FloatType +] + +value_types = [ + types.BooleanType, + types.NoneType +] + +supported_types = iter_types+string_types+numeric_types+value_types +invalid_module_chars = r'[^a-zA-Z0-9\_\.]' + +class TranslationError(Exception): + pass + +def dump(obj, serialize_method=None, ignore_attribute=None, ignore=[]): + if not serialize_method: + serialize_method = config.serialize_method + if not ignore_attribute: + ignore_attribute = config.ignore_attribute + obj_type = type(obj) + # Parse / return default "types"... + if obj_type in numeric_types+string_types+value_types: + return obj + if obj_type in iter_types: + if obj_type in (types.ListType, types.TupleType): + new_obj = [] + for item in obj: + new_obj.append(dump(item, serialize_method, + ignore_attribute, ignore)) + if obj_type is types.TupleType: + new_obj = tuple(new_obj) + return new_obj + # It's a dict... + else: + new_obj = {} + for key, value in obj.iteritems(): + new_obj[key] = dump(value, serialize_method, + ignore_attribute, ignore) + return new_obj + # It's not a standard type, so it needs __jsonclass__ + module_name = inspect.getmodule(obj).__name__ + class_name = obj.__class__.__name__ + json_class = class_name + if module_name not in ['', '__main__']: + json_class = '%s.%s' % (module_name, json_class) + return_obj = {"__jsonclass__":[json_class,]} + # If a serialization method is defined.. + if serialize_method in dir(obj): + # Params can be a dict (keyword) or list (positional) + # Attrs MUST be a dict. + serialize = getattr(obj, serialize_method) + params, attrs = serialize() + return_obj['__jsonclass__'].append(params) + return_obj.update(attrs) + return return_obj + # Otherwise, try to figure it out + # Obviously, we can't assume to know anything about the + # parameters passed to __init__ + return_obj['__jsonclass__'].append([]) + attrs = {} + ignore_list = getattr(obj, ignore_attribute, [])+ignore + for attr_name, attr_value in obj.__dict__.iteritems(): + if type(attr_value) in supported_types and \ + attr_name not in ignore_list and \ + attr_value not in ignore_list: + attrs[attr_name] = dump(attr_value, serialize_method, + ignore_attribute, ignore) + return_obj.update(attrs) + return return_obj + +def load(obj): + if type(obj) in string_types+numeric_types+value_types: + return obj + if type(obj) is types.ListType: + return_list = [] + for entry in obj: + return_list.append(load(entry)) + return return_list + # Othewise, it's a dict type + if '__jsonclass__' not in obj.keys(): + return_dict = {} + for key, value in obj.iteritems(): + new_value = load(value) + return_dict[key] = new_value + return return_dict + # It's a dict, and it's a __jsonclass__ + orig_module_name = obj['__jsonclass__'][0] + params = obj['__jsonclass__'][1] + if orig_module_name == '': + raise TranslationError('Module name empty.') + json_module_clean = re.sub(invalid_module_chars, '', orig_module_name) + if json_module_clean != orig_module_name: + raise TranslationError('Module name %s has invalid characters.' % + orig_module_name) + json_module_parts = json_module_clean.split('.') + json_class = None + if len(json_module_parts) == 1: + # Local class name -- probably means it won't work + if json_module_parts[0] not in config.classes.keys(): + raise TranslationError('Unknown class or module %s.' % + json_module_parts[0]) + json_class = config.classes[json_module_parts[0]] + else: + json_class_name = json_module_parts.pop() + json_module_tree = '.'.join(json_module_parts) + try: + temp_module = __import__(json_module_tree) + except ImportError: + raise TranslationError('Could not import %s from module %s.' % + (json_class_name, json_module_tree)) + json_class = getattr(temp_module, json_class_name) + # Creating the object... + new_obj = None + if type(params) is types.ListType: + new_obj = json_class(*params) + elif type(params) is types.DictType: + new_obj = json_class(**params) + else: + raise TranslationError('Constructor args must be a dict or list.') + for key, value in obj.iteritems(): + if key == '__jsonclass__': + continue + setattr(new_obj, key, value) + return new_obj