Skip to content

Instantly share code, notes, and snippets.

@sprin
Last active August 29, 2015 13:56
Show Gist options
  • Save sprin/8889173 to your computer and use it in GitHub Desktop.
Save sprin/8889173 to your computer and use it in GitHub Desktop.
from flask import Flask
app = Flask(__name__)
import datetime
from threading import local
threadlocal = local()
@app.route('/')
def abuse_threadlocals():
# Get the threadlocal and return it if it is defined,
# otherwise set it to current time and return that value.
x = getattr(threadlocal, 'x', None)
if not x:
threadlocal.x = datetime.datetime.now()
x = threadlocal.x
return 'You made this request on {}'.format(x)
# So what's wrong here? If the application is not using threads, but is
# instead running in a persistent single-threaded process, x will have the value
# that was set from the first request for the life of the process. If the web
# server is using a thread pool, each thread will retain the value from the
# first request it handled for the life of the thread.
# The solution? If you read my other gist on threadlocal abuse and the
# problems associated with readability and testing, and still
# think you have very compelling reasons to use threadlocals....
# https://gist.github.com/sprin/8887860
# Use a proven solution for context locals that handles access safety and
# cleanup, such as werkzeug.local:
# http://werkzeug.pocoo.org/docs/local/
# https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/local.py
# This works not only in threads, but in the general case. A quote:
#
# The same context means the same greenlet (if you're using greenlets)
# in the same thread and same process.
#
# The Flask microframework provides an easy-to-use context-local object
# called request which uses werkzueg.local.
# http://flask.pocoo.org/docs/reqcontext/
#
# However, to store your own context-local information, flask provides flask.g.
import flask
from flask import request, render_template_string
@app.route('/safer')
def safer_threadlocals():
x = getattr(flask.g, 'x', None)
if not x:
flask.g.x = datetime.datetime.now()
x = flask.g.x
ctx = {
'x': x,
'request': request.__dict__,
}
return render_template_string(SAFER_TMPL, **ctx)
SAFER_TMPL = (
"""
You made this request on {{x}}.<br><br>
Here is your request object:
<dl>
{% for key, value in request.items() %}
<dt>{{ key|e }}</dt>
{% if value.items %}
<dd>
<dl>
{% for k, v in value.items() %}
<dt>{{ k|e }}</dt>
<dd>{{ v|e }}</dd>
{% endfor %}
</dl>
</dd>
{% else %}
<dd>{{ value|e }}</dd>
{% endif %}
{% endfor %}
</dl>
"""
)
if __name__ == '__main__':
app.run(debug=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment