def _flatten_obj_instance(self, obj):
    'Recursively flatten an instance and return a json-friendly dict'
    data = {}
    has_class = hasattr(obj, '__class__')
    has_dict = hasattr(obj, '__dict__')
    has_slots = ((not has_dict) and hasattr(obj, '__slots__'))
    has_getnewargs = util.has_method(obj, '__getnewargs__')
    has_getnewargs_ex = util.has_method(obj, '__getnewargs_ex__')
    has_getinitargs = util.has_method(obj, '__getinitargs__')
    (has_reduce, has_reduce_ex) = util.has_reduce(obj)
    has_getstate = hasattr(obj, '__getstate__')
    if has_class:
        cls = obj.__class__
    else:
        cls = type(obj)
    class_name = util.importable_name(cls)
    handler = handlers.get(cls, handlers.get(class_name))
    if (handler is not None):
        if self.unpicklable:
            data[tags.OBJECT] = class_name
        return handler(self).flatten(obj, data)
    reduce_val = None
    if self.unpicklable:
        if (has_reduce and (not has_reduce_ex)):
            try:
                reduce_val = obj.__reduce__()
            except TypeError:
                pass
        elif has_reduce_ex:
            try:
                reduce_val = obj.__reduce_ex__(2)
            except TypeError:
                pass
        if (reduce_val and isinstance(reduce_val, string_types)):
            try:
                varpath = iter(reduce_val.split('.'))
                curmod = sys.modules[next(varpath)]
                for modname in varpath:
                    curmod = getattr(curmod, modname)
                    return self._flatten(curmod)
            except KeyError:
                pass
        elif reduce_val:
            rv_as_list = list(reduce_val)
            insufficiency = (5 - len(rv_as_list))
            if insufficiency:
                rv_as_list += ([None] * insufficiency)
            if (getattr(rv_as_list[0], '__name__', '') == '__newobj__'):
                rv_as_list[0] = tags.NEWOBJ
            (f, args, state, listitems, dictitems) = rv_as_list
            if (not (state and hasattr(obj, '__getstate__') and (not hasattr(obj, '__setstate__')) and (not isinstance(obj, dict)))):
                if rv_as_list[3]:
                    rv_as_list[3] = tuple(rv_as_list[3])
                if rv_as_list[4]:
                    rv_as_list[4] = tuple(rv_as_list[4])
                reduce_args = list(map(self._flatten, rv_as_list))
                last_index = (len(reduce_args) - 1)
                while ((last_index >= 2) and (reduce_args[last_index] is None)):
                    last_index -= 1
                data[tags.REDUCE] = reduce_args[:(last_index + 1)]
                return data
    if (has_class and (not util.is_module(obj))):
        if self.unpicklable:
            data[tags.OBJECT] = class_name
        if has_getnewargs_ex:
            data[tags.NEWARGSEX] = list(map(self._flatten, obj.__getnewargs_ex__()))
        if (has_getnewargs and (not has_getnewargs_ex)):
            data[tags.NEWARGS] = self._flatten(obj.__getnewargs__())
        if has_getinitargs:
            data[tags.INITARGS] = self._flatten(obj.__getinitargs__())
    if has_getstate:
        try:
            state = obj.__getstate__()
        except TypeError:
            self._pickle_warning(obj)
            return None
        else:
            return self._getstate(state, data)
    if util.is_module(obj):
        if self.unpicklable:
            data[tags.REPR] = '{name}/{name}'.format(name=obj.__name__)
        else:
            data = compat.ustr(obj)
        return data
    if util.is_dictionary_subclass(obj):
        self._flatten_dict_obj(obj, data)
        return data
    if util.is_sequence_subclass(obj):
        return self._flatten_sequence_obj(obj, data)
    if util.is_iterator(obj):
        data[tags.ITERATOR] = list(map(self._flatten, islice(obj, self._max_iter)))
        return data
    if has_dict:
        if util.is_sequence_subclass(obj):
            return self._flatten_sequence_obj(obj, data)
        getattr(obj, '_', None)
        return self._flatten_dict_obj(obj.__dict__, data)
    if has_slots:
        return self._flatten_newstyle_with_slots(obj, data)
    if data:
        return data
    self._pickle_warning(obj)
    return None
Recursively flatten an instance and return a json-friendly dict
def _flatten_obj_instance(self, obj):
    
    data = {}
    has_class = hasattr(obj, '__class__')
    has_dict = hasattr(obj, '__dict__')
    has_slots = ((not has_dict) and hasattr(obj, '__slots__'))
    has_getnewargs = util.has_method(obj, '__getnewargs__')
    has_getnewargs_ex = util.has_method(obj, '__getnewargs_ex__')
    has_getinitargs = util.has_method(obj, '__getinitargs__')
    (has_reduce, has_reduce_ex) = util.has_reduce(obj)
    has_getstate = hasattr(obj, '__getstate__')
    if has_class:
        cls = obj.__class__
    else:
        cls = type(obj)
    class_name = util.importable_name(cls)
    handler = handlers.get(cls, handlers.get(class_name))
    if (handler is not None):
        if self.unpicklable:
            data[tags.OBJECT] = class_name
        return handler(self).flatten(obj, data)
    reduce_val = None
    if self.unpicklable:
        if (has_reduce and (not has_reduce_ex)):
            try:
                reduce_val = obj.__reduce__()
            except TypeError:
                pass
        elif has_reduce_ex:
            try:
                reduce_val = obj.__reduce_ex__(2)
            except TypeError:
                pass
        if (reduce_val and isinstance(reduce_val, string_types)):
            try:
                varpath = iter(reduce_val.split('.'))
                curmod = sys.modules[next(varpath)]
                for modname in varpath:
                    curmod = getattr(curmod, modname)
                    return self._flatten(curmod)
            except KeyError:
                pass
        elif reduce_val:
            rv_as_list = list(reduce_val)
            insufficiency = (5 - len(rv_as_list))
            if insufficiency:
                rv_as_list += ([None] * insufficiency)
            if (getattr(rv_as_list[0], '__name__', ) == '__newobj__'):
                rv_as_list[0] = tags.NEWOBJ
            (f, args, state, listitems, dictitems) = rv_as_list
            if (not (state and hasattr(obj, '__getstate__') and (not hasattr(obj, '__setstate__')) and (not isinstance(obj, dict)))):
                if rv_as_list[3]:
                    rv_as_list[3] = tuple(rv_as_list[3])
                if rv_as_list[4]:
                    rv_as_list[4] = tuple(rv_as_list[4])
                reduce_args = list(map(self._flatten, rv_as_list))
                last_index = (len(reduce_args) - 1)
                while ((last_index >= 2) and (reduce_args[last_index] is None)):
                    last_index -= 1
                data[tags.REDUCE] = reduce_args[:(last_index + 1)]
                return data
    if (has_class and (not util.is_module(obj))):
        if self.unpicklable:
            data[tags.OBJECT] = class_name
        if has_getnewargs_ex:
            data[tags.NEWARGSEX] = list(map(self._flatten, obj.__getnewargs_ex__()))
        if (has_getnewargs and (not has_getnewargs_ex)):
            data[tags.NEWARGS] = self._flatten(obj.__getnewargs__())
        if has_getinitargs:
            data[tags.INITARGS] = self._flatten(obj.__getinitargs__())
    if has_getstate:
        try:
            state = obj.__getstate__()
        except TypeError:
            self._pickle_warning(obj)
            return None
        else:
            return self._getstate(state, data)
    if util.is_module(obj):
        if self.unpicklable:
            data[tags.REPR] = '{name}/{name}'.format(name=obj.__name__)
        else:
            data = compat.ustr(obj)
        return data
    if util.is_dictionary_subclass(obj):
        self._flatten_dict_obj(obj, data)
        return data
    if util.is_sequence_subclass(obj):
        return self._flatten_sequence_obj(obj, data)
    if util.is_iterator(obj):
        data[tags.ITERATOR] = list(map(self._flatten, islice(obj, self._max_iter)))
        return data
    if has_dict:
        if util.is_sequence_subclass(obj):
            return self._flatten_sequence_obj(obj, data)
        getattr(obj, '_', None)
        return self._flatten_dict_obj(obj.__dict__, data)
    if has_slots:
        return self._flatten_newstyle_with_slots(obj, data)
    if data:
        return data
    self._pickle_warning(obj)
    return None