Understanding the Application and Request Contexts in Flask

Last updated December 31st, 2021

The goal of this post is to provide clarity on how the Application and Request contexts work in Flask.


This is part one of a two-part series on Flask Contexts:

  1. Basics: Understanding the Application and Request Contexts in Flask (this article!)
  2. Advanced: Deep Dive into Flask's Application and Request Contexts

Contents

Objectives

By the end of this post, you should be able to explain:

  1. How Flask handles the request object and how this differs from other web frameworks
  2. What the application and request context are
  3. Which data is stored in both the Application and Request contexts
  4. How to utilize current_app, test_request_context, and test_client with the correct contexts

You should also be able to fix the following error:

RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context().

Contexts in Flask

Unlike Django and other web frameworks, Flask view functions do not accept a request object that contains metadata about the HTTP request.

Django Example:

def users(request):
    if request.method == 'POST':
         # Save the form data to the database
         # Send response
   else:
         # Get all users from the database
         # Send response

With Flask, you import in the request object like so:

from flask import request

@app.route('/users', methods=['GET', 'POST'])
def users():
    if request.method == 'POST':
         # Save the form data to the database
         # Send response
    else:
         # Get all users from the database
         # Send response

In the Flask example, the request object looks, feels, and acts like a global variable, but it's not.

If the request object were a global variable, you wouldn't be able to run a multi-threaded Flask app since global variables are not thread-safe.

Instead, Flask uses contexts to make a number of objects "act" like globals only for the particular context (a thread, process, or coroutine) being used. In Flask, this is called a context-local.

Context locals are similar to but ultimately different than Python's thread-local implementation for storing data that is specific to a thread. Flask's implementation is more generic in order to allow for workers to be threads, processes, or coroutines.

Data Stored in Flask Contexts

When a request is received, Flask provides two contexts:

Context Description Available Objects
Application Keeps track of the application-level data (configuration variables, logger, database connection) current_app, g
Request Keeps track of the request-level data (URL, HTTP method, headers, request data, session info) request, session

It's worth noting that each of the above objects are often referred to as "proxies". This just means that they are proxies to global flavors of the objects. For more on this, check out the second post in this series.

Flask handles the creation of these contexts when a request is received. They can cause confusion as you don't always have access to a particular object depending on which state your application is in.

Let's look at a few examples.

Application Context Example

Assume you have the following Flask app:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Welcome!'

if __name__ == '__main__':
    app.run()

First, let's look at how to work with the current_app object to access the Application context.

Within the Python shell, if you try to access the current_app.config object outside of a view function, you should see the following error:

$ python
>>> from flask import current_app
>>> current_app.config

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "werkzeug/local.py", line 306, in _get_current_object
    return self.__local()
  File "flask/globals.py", line 52, in _find_app
    raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context().  See the
documentation for more information.

To access objects exposed by the Application and Request contexts outside of a view function, you need to create the appropriate context first:

# without a context manager
$ python

>>> from app import app
>>> from flask import current_app
>>>
>>> app_ctx = app.app_context()
>>> app_ctx.push()
>>>
>>> current_app.config["ENV"]
'production'
>>> app_ctx.pop()
>>>
# with a context manager
$ python

>>> from app import app
>>> from flask import current_app
>>>
>>> with app.app_context():
...     current_app.config["ENV"]
...
'production'
>>>

Request Context Example

You can use the test_request_context method to create a request context:

# without a context manager
$ python

>>> from app import app
>>> from flask import request
>>>
>>> request_ctx = app.test_request_context()
>>> request_ctx.push()
>>>
>>> request.method
'GET'
>>>
>>> request.path
'/'
>>>
>>> request_ctx.pop()
>>>
# with a context manager
$ python

>>> from app import app
>>> from flask import request
>>>
>>> with app.test_request_context('/'):
...     request.method
...     request.path
...
'GET'
'/'
>>>

test_request_context is typically used during testing when you want to use request data without the overhead of a full request.

Testing Example

The most common time to run into issues with the Application and Request context is when your app is under test:

import pytest
from flask import current_app

from app import app


@pytest.fixture
def client():
    with app.test_client() as client:
        assert current_app.config["ENV"] == "production"  # Error!
        yield client


def test_index_page(client):
   response = client.get('/')

   assert response.status_code == 200
   assert b'Welcome!' in response.data

When run, the tests will fail in the fixture:

$ pytest
________________________ ERROR at setup of test_index_page _____________________

@pytest.fixture
def client():
    with app.test_client() as client:
>       assert current_app.config["ENV"] == "production"
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def _find_app():
        top = _app_ctx_stack.top
        if top is None:
>           raise RuntimeError(_app_ctx_err_msg)
E           RuntimeError: Working outside of application context.
E
E           This typically means that you attempted to use functionality that needed
E           to interface with the current application object in some way. To solve
E           this, set up an application context with app.app_context().  See the
E           documentation for more information.
================================= 1 error in 0.13s =================================

To fix, create an application context before accessing current_app:

import pytest
from flask import current_app

from app import app


@pytest.fixture
def client():
    with app.test_client() as client:
        with app.app_context():  # New!!
            assert current_app.config["ENV"] == "production"
        yield client


def test_index_page(client):
   response = client.get('/')

   assert response.status_code == 200
   assert b'Welcome!' in response.data

Summary

To summarize, use the following objects in view functions, CLI commands, and test functions:

Object Context Common Error Solution
current_app Application Context Working outside of application context with app.app_context():
g Application Context Working outside of application context with app.test_request_context('/'):
request Request Context Working outside of request context with app.test_request_context('/'):
session Request Context Working outside of request context with app.test_request_context('/'):

The following methods should be utilized during testing:

Flask Method Description
test_client Test client for the Flask app
test_request_context Push Request Context for Testing

Conclusion

This blog post just scratches the surface on the application and request contexts. Be sure to check out the second part in this series to learn more: Deep Dive into Flask's Application and Request Contexts

Check out the following course on how to build, test, and deploy a Flask application as well:

Patrick Kennedy

Patrick Kennedy

Patrick is a software engineer from the San Francisco Bay Area with experience in C++, Python, and JavaScript. His favorite areas of teaching are Vue and Flask. In his free time, he enjoys spending time with his family and cooking.

Share this tutorial

Featured Course

Developing Web Applications with Python and Flask

This course focuses on teaching the fundamentals of Flask by building and testing a web application using Test-Driven Development (TDD).

Featured Course

Developing Web Applications with Python and Flask

This course focuses on teaching the fundamentals of Flask by building and testing a web application using Test-Driven Development (TDD).