Search code examples
pythonflaskpython-decorators

Python/Flask nested decorator with parameter


I am trying to wrap an authentication decorator made for flask (Flask-Kerberos). I need to pass a parameter to the wrapper and I can't seem figure out how to do it.

original working code:

#main.py:
@app.route("/")
@requires_authentication
def index(user):
    return render_template('index.html', user=user)

not working code, but illustrates what I'm trying to do:

#main.py
from auth import customauth
@app.route("/")
@customauth(config)
def index(user):
    return render_template('index.html', user=user)
#auth.py
def customauth(*args, **kwargs): 
    @requires_authentication
    def inner(func):
        print(config)
        return func
    return inner

Solution

  • def customauth(config):
        def decorator(func):
            @requires_authentication
            def wrapper(*args, **kwargs):
                print(config)
                return func(*args, **kwargs)
    
            return wrapper
    
        return decorator
    

    This is basically what you'll see if you look up tutorials about decorators with parameters. The outermost function accepts the arguments. The inner one is the actual decorator which receives the function being decorated. And the innermost one is the final result which replaces index. To understand it, imagine unwrapping the function calls. This code:

    @customauth(config)
    def index(user):
    

    is equivalent to:

    @decorator  # for some specific config
    def index(user):
    

    which is equivalent to:

    @requires_authentication
    def wrapper(*args, **kwargs):
        print(config)
        return index(*args, **kwargs)  # func = index