What Is the Purpose of Flask's Context Stacks

What is the purpose of Flask's context stacks?

Multiple Apps

The application context (and its purpose) is indeed confusing until you realize that Flask can have multiple apps. Imagine the situation where you want to have a single WSGI Python interpreter run multiple Flask application. We're not talking Blueprints here, we're talking entirely different Flask applications.

You might set this up similar to the Flask documentation section on "Application Dispatching" example:

from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend

application = DispatcherMiddleware(frontend, {
'/backend': backend
})

Notice that there are two completely different Flask applications being created "frontend" and "backend". In other words, the Flask(...) application constructor has been called twice, creating two instances of a Flask application.

Contexts

When you are working with Flask, you often end up using global variables to access various functionality. For example, you probably have code that reads...

from flask import request

Then, during a view, you might use request to access the information of the current request. Obviously, request is not a normal global variable; in actuality, it is a context local value. In other words, there is some magic behind the scenes that says "when I call request.path, get the path attribute from the request object of the CURRENT request." Two different requests will have a different results for request.path.

In fact, even if you run Flask with multiple threads, Flask is smart enough to keep the request objects isolated. In doing so, it becomes possible for two threads, each handling a different request, to simultaneously call request.path and get the correct information for their respective requests.

Putting it Together

So we've already seen that Flask can handle multiple applications in the same interpreter, and also that because of the way that Flask allows you to use "context local" globals there must be some mechanism to determine what the "current" request is (in order to do things such as request.path).

Putting these ideas together, it should also make sense that Flask must have some way to determine what the "current" application is!

You probably also have code similar to the following:

from flask import url_for

Like our request example, the url_for function has logic that is dependent on the current environment. In this case, however, it is clear to see that the logic is heavily dependent on which app is considered the "current" app. In the frontend/backend example shown above, both the "frontend" and "backend" apps could have a "/login" route, and so url_for('/login') should return something different depending on if the view is handling the request for the frontend or backend app.

To answer your questions...

What is the purpose of the "stack" when it comes to the request or
application context?

From the Request Context docs:

Because the request context is internally maintained as a stack you
can push and pop multiple times. This is very handy to implement
things like internal redirects.

In other words, even though you typically will have 0 or 1 items on these stack of "current" requests or "current" applications, it is possible that you could have more.

The example given is where you would have your request return the results of an "internal redirect". Let's say a user requests A, but you want to return to the user B. In most cases, you issue a redirect to the user, and point the user to resource B, meaning the user will run a second request to fetch B. A slightly different way of handling this would be to do an internal redirect, which means that while processing A, Flask will make a new request to itself for resource B, and use the results of this second request as the results of the user's original request.

Are these two separate stacks, or are they both part of one stack?

They are two separate stacks. However, this is an implementation detail. What's more important is not so much that there is a stack, but the fact that at any time you can get the "current" app or request (top of the stack).

Is the request context pushed onto a stack, or is it a stack itself?

A "request context" is one item of the "request context stack". Similarly with the "app context" and "app context stack".

Am I able to push/pop multiple contexts on top of eachother? If so,
why would I want to do that?

In a Flask application, you typically would not do this. One example of where you might want to is for an internal redirect (described above). Even in that case, however, you would probably end up having Flask handle a new request, and so Flask would do all of the pushing/popping for you.

However, there are some cases where you'd want to manipulate the stack yourself.

Running code outside of a request

One typical problem people have is that they use the Flask-SQLAlchemy extension to set up a SQL database and model definition using code something like what is shown below...

app = Flask(__name__)
db = SQLAlchemy() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)

Then they use the app and db values in a script that should be run from the shell. For example, a "setup_tables.py" script...

from myapp import app, db

# Set up models
db.create_all()

In this case, the Flask-SQLAlchemy extension knows about the app application, but during create_all() it will throw an error complaining about there not being an application context. This error is justified; you never told Flask what application it should be dealing with when running the create_all method.

You might be wondering why you don't end up needing this with app.app_context() call when you run similar functions in your views. The reason is that Flask already handles the management of the application context for you when it is handling actual web requests. The problem really only comes up outside of these view functions (or other such callbacks), such as when using your models in a one-off script.

The resolution is to push the application context yourself, which can be done by doing...

from myapp import app, db

# Set up models
with app.app_context():
db.create_all()

This will push a new application context (using the application of app, remember there could be more than one application).

Testing

Another case where you would want to manipulate the stack is for testing. You could create a unit test that handles a request and you check the results:

import unittest
from flask import request

class MyTest(unittest.TestCase):
def test_thing(self):
with app.test_request_context('/?next=http://example.com/') as ctx:
# You can now view attributes on request context stack by using `request`.

# Now the request context stack is empty

What's the difference between application and request contexts?

Both are created on request and torn down when it finishes.

It is true in the request lifecycle. Flask create the app context, the request context, do some magic, destroy request context, destroy app context.

The application context can exist without a request and that is the reason you have both. For example, if I'm running from a shell, I can create the app_context, without the request and has access to the ´current_app` proxy.

It is a design decision to separate concerns and give you the option to not create the request context. The request context is expensive.

In old Flask's (0.7?), you had only the request context and created the current_app with a Werkzeug proxy. So the application context just create a pattern.

Some docs about appcontext, but you probably already read it: http://flask.pocoo.org/docs/appcontext/

Why app context in flask not a singleton for an app?

The app context is not meant for sharing between requests. It is there to share context before the request context is set up, as well as after the request has been torn down already. Yes, this means that there can be multiple g contexts active for different requests.

You can't share 'global' state because a WSGI app is not limited to a single process. Many WSGI servers use multiprocessing to scale request handling, not just threading. If you need to share 'global' state across requests, use something like a database or memcached.

Flask, push application context for Flask-sqlalchemy to huey worker

It is better if you let Huey create a Flask app for its use. Organize your code as follows:

Add a second method that creates a Flask app for the specific use by Huey, similar to create_app

#__init__.py
from flask import Flask
from app.config import db, Config, huey
from app.tasks import my_task

def create_app():
# ...
return app

def create_huey_app():
app = Flask('HUEY APP')
app.config.from_object(Config)

# only initialize stuff here that is needed by Huey, eg DB connection

db.init_app(app)

# register any blueprints needed
# e.g. maybe it needs a blueprint to work with urls in email generation

return app

Make all your tasks have a first parameter that is a callable:

#tasks.py
from app.config import huey
from app.models import User

# every task takes an app_factory parameter
@huey.task()
def background_task(app_factory):
app = app_factory()
with app.app_context():
User.query.get(1)
return 1

Then pass create_huey_app as the callable to each task instantiation:

#view.py
from flask import Blueprint
from app.tasks import my_task

main = Blueprint("main", __name__)

@main.route("/")
def index():
# pass the Huey app factory to the task
background_task(create_huey_app) # running the registered background task
return "hello view"

If you want to run the task locally when debugging:

@main.route("/")
def index():
# pass the Huey app factory to the task
if current_app.debug:
background_task.call_local(create_huey_app) # running the task directly
else:
background_task(create_huey_app) # running the task in Huey
return "hello view"

Why flask app context is lost in child thread when application factory pattern is used?

From https://flask.palletsprojects.com/en/2.1.x/reqcontext/#lifetime-of-the-context:

When a Flask application begins handling a request, it pushes a request context, which also pushes an app context. When the request ends it pops the request context then the application context.

The context is unique to each thread (or other worker type). ...

In the case of a global app and db = SQLAlchemy(app), db always has self.app.

In the case of application factory pattern, db gets the app context from the thread.

Pass an AppContext to be pushed onto the thread:

# def printer():           # Change this
def printer(app_context): # to this
app_context.push() #
print(User.query.all())

@blueprint.route('/')
def index():

# athread = Thread(target=printer, args=(), daemon=True) # Change this
athread = Thread(target=printer, args=(current_app.app_context(),), daemon=True) # to this
athread.start()

return 'ok'

How to use flask app context when using decorators

The problem is in the way of using auth_token_required decorator. auth_token_required decorator unlike auth_required doesn't accept any additional arguments for configuration and expects the only decorated function to be transmitted.

Your code can be fixed by applying of one of the following variants:


@article_manager.route('/<string:title>', '/<int:id>')
class GetArticle(Resource):

@auth_token_required
def get(self, title=None, id=None):
pass

or


@article_manager.route('/<string:title>', '/<int:id>')
class GetArticle(Resource):

@auth_required("token")
def get(self, title=None, id=None):
pass

Implementing threading with flask with application context

I found a solution to this issue. I added this code to my backend.py:

from flask import Blueprint
from threading import Thread

bp = Blueprint('backend', __name__)

def backend(app):
thread = Thread(target=start, args=(app,))
thread.daemon = True
thread.start()

I then added backend.backend(app) to my create_app() function in __init__.py, right before the end of my function. This will call my backend() function from backend.py and pass the application context, and this function starts my sub-process.



Related Topics



Leave a reply



Submit