Gets the name of the object containing @obj and returns as a string

        @obj: any python object

        -> #str parent object name or None
        ..
            from redis_structures.debug import get_parent_obj

            get_parent_obj(get_parent_obj)
            # -> <module 'redis_structures.debug' from>
        ..

def get_parent_obj(obj):
    """ Gets the name of the object containing @obj and returns as a string

        @obj: any python object

        -> #str parent object name or None
        ..
            from redis_structures.debug import get_parent_obj

            get_parent_obj(get_parent_obj)
            # -> <module 'redis_structures.debug' from>
        ..
    """
    try:
        cls = get_class_that_defined_method(obj)
        if cls and cls != obj:
            return cls
    except AttributeError:
        pass
    if hasattr(obj, '__module__') and obj.__module__:
        try:
            module = importlib.import_module(obj.__module__)
            objname = get_obj_name(obj).split(".")
            owner = getattr(module, objname[-2])
            return getattr(owner, objname[-1])
        except Exception:
            try:
                return module
            except Exception:
                pass
    try:
        assert hasattr(obj, '__qualname__') or hasattr(obj, '__name__')
        objname = obj.__qualname__ if hasattr(obj, '__qualname__') \
            else obj.__name__
        objname = objname.split(".")
        assert len(objname) > 1
        return locate(".".join(objname[:-1]))
    except Exception:
        try:
            module = importlib.import_module(".".join(objname[:-1]))
            return module
        except Exception:
            pass
    return None