import functools


def optional_parameter_decorator(f):
    """
    A decorator for a decorator, allowing the decorator to be used both with
    and without arguments applied.

    Example:
    ------
    @optional_parameter_decorator
    def decorator(func, foo='bar'):
        pass

    which can now be used as

    @decorator
    def my_method():
        pass

    or

    @decorator(foo='bar')
    def my_method():
        pass
    """
    @functools.wraps(f)
    def wrapped_decorator(*args, **kwargs):
        if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
            # Return the actual decorated function.
            return f(args[0])
        else:
            # Wrap the function in a decorator in the case that arguments are
            # applied.
            return lambda realf: f(realf, *args, **kwargs)
    return wrapped_decorator