python decorator
Decorador de Python con Frasco (2)
Necesito agregar un decorador de Python a las funciones de ruta de Flask (básicamente edité el código desde aquí )
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
y usarlo así estará bien:
@app.route(''/admin/action'')
@requires_admin
def AdminAction():
#NO error if NO parameter
Pero úsalo así tendréis un error:
@app.route(''/admin/action/<int:id>'')
@requires_admin
def AdminAction(id):
En Flask 0.10, recibo errores como este (acabo de actualizar de Flask 0.9 a 0.10, y en Flask 0.9 no hay errores de gramática como este):
@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
Soy bastante nuevo en materia de decoración, ¿cómo puedo corregir este error?
Tienes dos funciones de contenedor donde solo necesitas una. Tenga en cuenta que cada función de contenedor toma un argumento. Esto debería ser una pista de lo que está sucediendo.
Tienes:
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
Cuando decora una función con ella:
@decorator
def my_function(*takes_multiple_arguments):
pass
Esto es equivalente a:
def my_function(*takes_multiple_arguments):
pass
my_function = decorator(my_function)
pero haciendo decorator(my_function)
devuelve wrapper1
, que si lo recuerdas toma un argumento, take_a_function
. Esto claramente no es lo que quieres. Quieres que wrapper2
devuelto. Como en su respuesta, la solución es eliminar la envoltura externa ( wrapper1
):
def decorator(takes_a_function):
@wraps(takes_a_function)
def wrapper(*args, **kwargs):
# logic here
return takes_a_function(*args, **kwargs)
return wrapper
Ok, resolví este problema leyendo esta respuesta Route to view_func con el mismo "matraz" de decoradores dado por @ will-hart
Simplemente elimino la def wrapper(f)
y todo parece estar bien ahora. al menos no hay error gramatical.
def requires_admin(f):
@wraps(f)
def wrapped(*args, **kwargs):
#if blah blah:
#return blah blah
return f(*args, **kwargs)
return wrapped
Ya que soy bastante nuevo como decorador y no sé por qué. Pero espero que esto pueda ayudar a otras personas.