Decorator used to create consistent decorators.
    Consistent in the meaning that the wrapper do not have to
    care if the wrapped callable is a function or a method,
    it will always receive a valid callable.
    If the decorator is used with a function, the wrapper will
    receive the function itself, but if the decorator is used
    with a method, the wrapper will receive a bound method
    callable directly and the first argument (self) will be removed.
    This allows writing decorators behaving consistently
    with function and method.

    Note that when using reflect or annotate module functions,
    depth should be incremented by one.

    Example::

        @decorator.simple_callable
        def mydecorator(original_function):

            def wrapper(callable, call, arguments):
                # processing
                return callable(call, arguments)

            return wrapper

        @mydecorator
        def myfunction():
            pass

def simple_callable(decorator):
    '''Decorator used to create consistent decorators.
    Consistent in the meaning that the wrapper do not have to
    care if the wrapped callable is a function or a method,
    it will always receive a valid callable.
    If the decorator is used with a function, the wrapper will
    receive the function itself, but if the decorator is used
    with a method, the wrapper will receive a bound method
    callable directly and the first argument (self) will be removed.
    This allows writing decorators behaving consistently
    with function and method.

    Note that when using reflect or annotate module functions,
    depth should be incremented by one.

    Example::

        @decorator.simple_callable
        def mydecorator(original_function):

            def wrapper(callable, call, arguments):
                # processing
                return callable(call, arguments)

            return wrapper

        @mydecorator
        def myfunction():
            pass

    '''

    def meta_decorator(function):

        wrapper = decorator(function)

        if reflect.inside_class_definition(depth=2):

            def method_wrapper(*args, **kwargs):
                obj, args = args[0], args[1:]
                method = types.MethodType(function, obj, obj.__class__)
                return wrapper(method, *args, **kwargs)

            meta_wrapper = _function_mimicry(function, method_wrapper)

        else:

            def function_wrapper(*args, **kwargs):
                return wrapper(function, *args, **kwargs)

            meta_wrapper = _function_mimicry(function, function_wrapper)

        return meta_wrapper

    return meta_decorator