# pylint: skip-file import types import inspect import operator import time """ Copied from Json Pickle: https://github.com/jsonpickle/jsonpickle/blob/master/jsonpickle/util.py """ SEQUENCES = (list, set, tuple) SEQUENCES_SET = set(SEQUENCES) PRIMITIVES = set((str, bool, float, int, int)) def is_type(obj): # use "isinstance" and not "is" to allow for metaclasses return isinstance(obj, type) def has_method(obj, name): # false if attribute doesn't exist if not hasattr(obj, name): return False func = getattr(obj, name) # builtin descriptors like __getnewargs__ if isinstance(func, types.BuiltinMethodType): return True # note that FunctionType has a different meaning in py2/py3 if not isinstance(func, (types.MethodType, types.FunctionType)): return False # need to go through __dict__'s since in py3 methods are essentially descriptors base_type = obj if is_type(obj) else obj.__class__ # __class__ for old-style classes original = None for subtype in inspect.getmro(base_type): # there is no .mro() for old-style classes original = vars(subtype).get(name) if original is not None: break # name not found in the mro if original is None: return False # static methods are always fine if isinstance(original, staticmethod): return True # at this point, the method has to be an instancemthod or a classmethod self_attr = '__self__' if not hasattr(func, self_attr): return False bound_to = getattr(func, self_attr) # class methods if isinstance(original, classmethod): return issubclass(base_type, bound_to) # bound methods return isinstance(obj, type(bound_to)) def is_object(obj): """Returns True is obj is a reference to an object instance. >>> is_object(1) True >>> is_object(object()) True >>> is_object(lambda x: 1) False """ return (isinstance(obj, object) and not isinstance(obj, (type, types.FunctionType))) def is_primitive(obj): """Helper method to see if the object is a basic data type. Unicode strings, integers, longs, floats, booleans, and None are considered primitive and will return True when passed into *is_primitive()* >>> is_primitive(3) True >>> is_primitive([4,4]) False """ if obj is None: return True elif type(obj) in PRIMITIVES: return True return False def is_dictionary(obj): """Helper method for testing if the object is a dictionary. >>> is_dictionary({'key':'value'}) True """ return type(obj) is dict def is_sequence(obj): """Helper method to see if the object is a sequence (list, set, or tuple). >>> is_sequence([4]) True """ return type(obj) in SEQUENCES_SET def is_list(obj): """Helper method to see if the object is a Python list. >>> is_list([4]) True """ return type(obj) is list def is_set(obj): """Helper method to see if the object is a Python set. >>> is_set(set()) True """ return type(obj) is set def is_bytes(obj): """Helper method to see if the object is a bytestring. >>> is_bytes(b'foo') True """ return type(obj) is bytes def is_unicode(obj): """Helper method to see if the object is a unicode string""" return type(obj) is str def is_tuple(obj): """Helper method to see if the object is a Python tuple. >>> is_tuple((1,)) True """ return type(obj) is tuple def is_dictionary_subclass(obj): """Returns True if *obj* is a subclass of the dict type. *obj* must be a subclass and not the actual builtin dict. >>> class Temp(dict): pass >>> is_dictionary_subclass(Temp()) True """ return (hasattr(obj, '__class__') and issubclass(obj.__class__, dict) and not is_dictionary(obj)) def is_sequence_subclass(obj): """Returns True if *obj* is a subclass of list, set or tuple. *obj* must be a subclass and not the actual builtin, such as list, set, tuple, etc.. >>> class Temp(list): pass >>> is_sequence_subclass(Temp()) True """ return (hasattr(obj, '__class__') and (issubclass(obj.__class__, SEQUENCES) or is_list_like(obj)) and not is_sequence(obj)) def is_list_like(obj): return hasattr(obj, '__getitem__') and hasattr(obj, 'append') def is_noncomplex(obj): """Returns True if *obj* is a special (weird) class, that is more complex than primitive data types, but is not a full object. Including: * :class:`~time.struct_time` """ if type(obj) is time.struct_time: return True return False def is_function(obj): """Returns true if passed a function >>> is_function(lambda x: 1) True >>> is_function(locals) True >>> def method(): pass >>> is_function(method) True >>> is_function(1) False """ if type(obj) in (types.FunctionType, types.MethodType, types.LambdaType, types.BuiltinFunctionType, types.BuiltinMethodType): return True if not hasattr(obj, '__class__'): return False module = translate_module_name(obj.__class__.__module__) name = obj.__class__.__name__ return (module == '__builtin__' and name in ('function', 'builtin_function_or_method', 'instancemethod', 'method-wrapper')) def is_module_function(obj): """Return True if `obj` is a module-global function >>> import os >>> is_module_function(os.path.exists) True >>> is_module_function(lambda: None) False """ return (hasattr(obj, '__class__') and isinstance(obj, types.FunctionType) and hasattr(obj, '__module__') and hasattr(obj, '__name__') and obj.__name__ != '<lambda>') def is_module(obj): """Returns True if passed a module >>> import os >>> is_module(os) True """ return isinstance(obj, types.ModuleType) def translate_module_name(module): """Rename builtin modules to a consistent (Python2) module name This is used so that references to Python's `builtins` module can be loaded in both Python 2 and 3. We remap to the "__builtin__" name and unmap it when importing. See untranslate_module_name() for the reverse operation. """ if module == 'builtins' or module == 'exceptions': # We map the Python2 `exceptions` module to `__builtin__` because # `__builtin__` is a superset and contains everything that is # available in `exceptions`, which makes the translation simpler. return '__builtin__' else: return module def untranslate_module_name(module): """Rename module names mention in JSON to names that we can import This reverses the translation applied by translate_module_name() to a module name available to the current version of Python. """ # remap `__builtin__` and `exceptions` to the `builtins` module if module == '__builtin__': module = 'builtins' elif module == 'exceptions': module = 'builtins' return module def importable_name(cls): """ >>> class Example(object): ... pass >>> ex = Example() >>> importable_name(ex.__class__) == 'jsonpickle.util.Example' True >>> importable_name(type(25)) == '__builtin__.int' True >>> importable_name(None.__class__) == '__builtin__.NoneType' True >>> importable_name(False.__class__) == '__builtin__.bool' True >>> importable_name(AttributeError) == '__builtin__.AttributeError' True """ name = cls.__name__ module = translate_module_name(cls.__module__) return '%s.%s' % (module, name) def itemgetter(obj, getter=operator.itemgetter(0)): return str(getter(obj))