I love Flask for simple stuff, but I'm a little concerned that, as someone who considers himself a relatively advanced Python developer, I don't really understand quite a lot of this.
I have no doubt that if I dug into it then it would all make sense, but my first instinct is this: how much of this complexity (proxy objects to thread locals, context stacks etc) results from the fact that doing:
from flask import request
is just a bad idea?
Perhaps things would be easier if instead of:
from flask import request
...
@app.route('/'):
def index():
return "Hello from %s" % request.args.get('name')
we did:
@app.route('/'):
def index(request):
return "Hello from %s" % request.args.get('name')
I'm probably massively over-simplifying things, but the idea of magically importing state is the one aspect of Flask that always felt a bit odd to me.
I was a huge opponent of thread locals for a really long time but I finally had to acknowledge that they make things easier instead of harder. And the reason for this is that thread locals exposed are a very explicit thing compared to magic thread locals hidden somewhere in a framework.
The fact that you can do `_app_ctx_stack.top.mydatabase_connection` to get a database connection from anywhere is very helpful. Frameworks that did not expose thread locals still have them. Just special cased for certain things.
How does User.objects.all() get to the current transaction? Correct: a thread local. It's just hidden in the core of the framework. Not having a thread local there is nearly impossible, especially if you need to work with foreign libraries that do not support passing in of information. It's just going to cause a horrible API. (Not for the view case, but for things like database connections)
Flask does not hide things from you. It is very explicit, honest and upfront with everything it's doing. Is it the best solution? I am pretty sure it's not. I do however think that it's a very viable one.
The talk is very advanced and I think I did not make that clear enough from the summary on the website and I learned from that. I also plan on doing a “postmortem” that gives more context into some of the things the talk was mentioning and why it works the way it works.
TL;DR: you can't live without thread locals or you have a horrible API. Flask embraces them on every level and tells you how you can deal with the downsides of it.
I find this to be true in general: Modern software engineering practices are strongly astronauted, and so well ingrained/indoctrinated, that people think you might be crazy for suggesting globals (or thread locals, which are an evolution of globals) are a good idea.
flask seems to make good use of these. For GUI client programming, FLTK does the same thing marvelously - FLTK code is often 3-4 times shorter and simpler than any other GUI API/framework I've used, and it usually performs much better as well.
In general, the "missing piece" that makes globals/TLS at-least-as-usable-as-pass-everything-explicitly, is "push state"/"pop state", which allows you to do reentrant calls -- usually works much, much better than passing the state as an argument everywhere.
edit: I originally wrote "but flask probably doesn't need a state stack", but then I got to the slide that says it does have them :) silly me, apologies.
Yes it is usually not such a bright idea to use thread locals. They cause
troubles for servers that are not based on the concept of threads and make
large applications harder to maintain. However Flask is just not designed
for large applications or asynchronous servers. Flask wants to make it quick
and easy to write a traditional web application.
I want to thank the flask team for this. we are using flask + gevent in production and it has been highly performant (1200 requests a second for our app) and stable :-)
I do not think the usage of thread locals in Flask is a bad idea. Conceptually request-local variables are no different to stack variables in multiple threads of execution, or member variables of objects in OO languages: both change their value depending on some (often) implicit context. We tolerate both, because we've grown accustomed to them.
Server-side web application frameworks are a well-understood and rigid domain: there is only so much variation you can get in the core structure, so it's easy to keep in mind the meaning and scope of Flask's "magic" implicit state variables.
I have used (and continue using) Flask for small- and medium-size projects, and thread-locals so far haven't been a maintenance burden.
If you're interested in this talk, Armin provides the slides and links to video for many of his previous presentations at his website[1]. The talks range from horrific (but useful) Python hackery to an overview of Python web app development.
Thank you so much for these. His Flask talks are very intriguing and a good yardstick for measuring your python-fu. The overview of pastebin was enlightening.
This is basically an explanation of flask internal organization for flask hackers and extension developers. You do you not need such knowledge to create flask applications. Actually due to this features it's possible to have nice and clean end-user programming experience without too much magic. Comparable level of complexity exists in any modern web framework -- just read the source of Django or Rails.
> Anyone care to explain what these advanced patterns are useful for?
It's not intended to be used by newcomers. It's for people that write Flask extensions that should work in a wide range of environments. The word “advanced” is in there for a good reason.
Always happy to see Flask related stuff on HN front page :). Being a novice python wannabe, I am still struggling with thread locals but more than happy to keep working with Flask. Reading the source code is fun.
I have no doubt that if I dug into it then it would all make sense, but my first instinct is this: how much of this complexity (proxy objects to thread locals, context stacks etc) results from the fact that doing:
is just a bad idea?Perhaps things would be easier if instead of:
we did: I'm probably massively over-simplifying things, but the idea of magically importing state is the one aspect of Flask that always felt a bit odd to me.