I have the following code:
import datetime
from flask.app import Flask
app = Flask(__name__)
app.config.from_object(__name__)
app.debug = True
def track_time_spent(name):
def decorator(f):
def wrapped(*args, **kwargs):
start = datetime.datetime.now()
ret = f(*args, **kwargs)
delta = datetime.datetime.now() - start
print name, "took", delta.total_seconds(), "seconds"
return ret
return wrapped
return decorator
@app.route('/foo')
@track_time_spent('foo')
def foo():
print "foo"
return "foo"
@app.route('/bar')
@track_time_spent('bar')
def bar():
print "bar"
return "bar"
I am unable to get foo to return 'foo':
$ curl localhost:8888/foo
bar
(flask window)
bar
bar took 8.2e-05 seconds
127.0.0.1 - - [18/Apr/2013 19:21:31] "GET /foo HTTP/1.1" 200 -
$ curl localhost:8888/bar
bar
(flask window)
bar
bar took 3.5e-05 seconds
127.0.0.1 - - [18/Apr/2013 19:21:35] "GET /bar HTTP/1.1" 200 -
What's going on? Why isn't my decorator working?
EDIT
I don't think you guys seem to be able to see the problem.
When I have @app.route
before @track_time_spent
, both methods return bar. The error here is that calling localhost:8888/foo results in bar
in both the http response as well as the print function.
The other answers seem to be missing that you're getting "bar" as a response from "/foo" when you switch the order of the decorators. You must use @wraps
here unless you update the __name__
, __module__
, and such manually. Flask uses your methods kinda like singletons, and sees your decorator just as the wrapped()
method, instead of the methods you actually wrapped. Hence, your routes will keep getting overwritten by the last method to use your decorator.
import datetime
from functools import wraps
from flask.app import Flask
app = Flask(__name__)
app.config.from_object(__name__)
app.debug = True
def track_time_spent(name):
def decorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
start = datetime.datetime.now()
ret = f(*args, **kwargs)
delta = datetime.datetime.now() - start
print name, "took", delta.total_seconds(), "seconds"
return ret
return wrapped
return decorator
@app.route('/foo')
@track_time_spent('foo')
def foo():
print "foo"
return "foo"
@app.route('/bar')
@track_time_spent('bar')
def bar():
print "bar"
return "bar"
app.run(host='0.0.0.0', port=8888)
Flask's route
function is a registering function in the sense you call it for its side effect - it'll register your view function for an endpoint. However, you're registering just the view function, not the decorated view function. Simply switch the order of decorators to register the "time-tracked" function.
Also, you can use @app.before_request and @app.teardown_request-registered functions to track time more reliably (taking into account the time it took to render the template and such).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With