Python decorator with Flask
Solution 1
You have two wrapper functions where you only need one. Notice that each wrapper function takes one argument. This should be a clue as to what is happening.
You have:
def decorator(take_a_function):
def wrapper1(take_a_function):
def wrapper2(*takes_multiple_arguments):
# do stuff
return take_a_function(*takes_multiple_arguments)
return wrapper2
return wrapper1
When you decorate a function with it:
@decorator
def my_function(*takes_multiple_arguments):
pass
This is equivalent to:
def my_function(*takes_multiple_arguments):
pass
my_function = decorator(my_function)
but doing decorator(my_function)
returns wrapper1
, which if you recall takes one
argument, take_a_function
. This is clearly not what you want. You want wrapper2
returned. As in your answer, the solution is to remove the outer wrapper(wrapper1
):
from functools import wraps
def decorator(takes_a_function):
@wraps(takes_a_function)
def wrapper(*args, **kwargs):
# logic here
return takes_a_function(*args, **kwargs)
return wrapper
Solution 2
Ok I solved this problem by reading this answer Route to view_func with same decorators "flask" given by @will-hart
I simply remove the def wrapper(f)
and everything seems fine now. at leaset no grammar error.
from functools import wraps
def requires_admin(f):
@wraps(f)
def wrapped(*args, **kwargs):
#if blah blah:
#return blah blah
return f(*args, **kwargs)
return wrapped
Since I am pretty new to decorator and I dont know why. But hope this can help other ppl.
Related videos on Youtube
James King
Updated on September 14, 2022Comments
-
James King over 1 year
I need to add a python decorator to Flask route functions, (basically I edited the code from here)
def requires_admin(f): def wrapper(f): @wraps(f) def wrapped(*args, **kwargs): #if not admin: #return render_template('error.html') return f(*args, **kwargs) return wrapped return wrapper
and use it like this will be OK:
@app.route('/admin/action') @requires_admin def AdminAction(): #NO error if NO parameter
But use it like this will have error:
@app.route('/admin/action/<int:id>') @requires_admin def AdminAction(id):
In Flask 0.10, I get errors like this (I just updated from Flask 0.9 to 0.10, and in Flask 0.9 there is no grammar error like this):
@requires_admin File "/usr/local/lib/python2.6/dist-packages/Flask-0.10.1-py2.6.egg/flask/app. py", line 1013, in decorator self.add_url_rule(rule, endpoint, f, **options) File "/usr/local/lib/python2.6/dist-packages/Flask-0.10.1-py2.6.egg/flask/app. py", line 62, in wrapper_func return f(self, *args, **kwargs) File "/usr/local/lib/python2.6/dist-packages/Flask-0.10.1-py2.6.egg/flask/app. py", line 984, in add_url_rule 'existing endpoint function: %s' % endpoint) AssertionError: View function mapping is overwriting an existing endpoint functi on: wrapper
I am pretty new to the decorator stuff, how do I correct this error?
-
loki about 10 yearsIn general a decorator with no arguments besides the wrapped function requires just one inner function. In your first example
requires_admin
returns a function which in turn takes a second function. Two level decorators are for things like@app.route(extra_args)
or@wraps(f)
.