tags:

views:

57

answers:

1

I wrote a decorator that looks like this

def login_required_message(*args, **kwargs):
    kwargs.setdefault('message', "You must be logged in to do that.")
    return _user_passes_test_message(lambda u: u.is_authenticated(), *args, **kwargs)

But when I try to use it without the () at the end, it fails, unless I rewrite it like this:

def login_required_message(function=None, *args, **kwargs):
    kwargs.setdefault('message', "You must be logged in to do that.")
    decorator = _user_passes_test_message(lambda u: u.is_authenticated(), *args, **kwargs)
    if function: return decorator(function)
    else: return decorator

Then the () is optional. So, how do I encapsulate this "optional" functionality into a decorator so that I can decorate my decorators to allow no arguments?

+3  A: 

I actually recently wrote a blog post about this - at least, I think it addresses what you're trying to do. For posterity, here's what I came up with:

def opt_arguments(func):
    def meta_wrapper(*args, **kwargs):
        if len(args) == 1 and callable(args[0]):
            return func(args[0])
        else:
            def meta_func(inner_func):
                return func(inner_func, *args, **kwargs)
            return meta_func
    return meta_wrapper

By the way, in the process of trying to figure out how to do it, I came to the conclusion that this is one of those things that is almost always more complication than necessary ;-)

David Zaslavsky