Skip to content

Commit

Permalink
Merge pull request #2685 from davidism/app-context-docs
Browse files Browse the repository at this point in the history
rework context docs
  • Loading branch information
davidism committed Apr 9, 2018
2 parents 47a0086 + 2411707 commit 16d83d6
Show file tree
Hide file tree
Showing 7 changed files with 542 additions and 375 deletions.
93 changes: 47 additions & 46 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -211,43 +211,40 @@ thing, like it does for :class:`request` and :class:`session`.

.. data:: g

Just store on this whatever you want. For example a database
connection or the user that is currently logged in.
A namespace object that can store data during an
:doc:`application context </appcontext>`. This is an instance of
:attr:`Flask.app_ctx_globals_class`, which defaults to
:class:`ctx._AppCtxGlobals`.

Starting with Flask 0.10 this is stored on the application context and
no longer on the request context which means it becomes available if
only the application context is bound and not yet a request. This
is especially useful when combined with the :ref:`faking-resources`
pattern for testing.
This is a good place to store resources during a request. During
testing, you can use the :ref:`faking-resources` pattern to
pre-configure such resources.

Additionally as of 0.10 you can use the :meth:`get` method to
get an attribute or ``None`` (or the second argument) if it's not set.
These two usages are now equivalent::
This is a proxy. See :ref:`notes-on-proxies` for more information.

user = getattr(flask.g, 'user', None)
user = flask.g.get('user', None)
.. versionchanged:: 0.10
Bound to the application context instead of the request context.

It's now also possible to use the ``in`` operator on it to see if an
attribute is defined and it yields all keys on iteration.

As of 0.11 you can use :meth:`pop` and :meth:`setdefault` in the same
way you would use them on a dictionary.

This is a proxy. See :ref:`notes-on-proxies` for more information.
.. autoclass:: flask.ctx._AppCtxGlobals
:members:


Useful Functions and Classes
----------------------------

.. data:: current_app

Points to the application handling the request. This is useful for
extensions that want to support multiple applications running side
by side. This is powered by the application context and not by the
request context, so you can change the value of this proxy by
using the :meth:`~flask.Flask.app_context` method.
A proxy to the application handling the current request. This is
useful to access the application without needing to import it, or if
it can't be imported, such as when using the application factory
pattern or in blueprints and extensions.

This is a proxy. See :ref:`notes-on-proxies` for more information.
This is only available when an
:doc:`application context </appcontext>` is pushed. This happens
automatically during requests and CLI commands. It can be controlled
manually with :meth:`~flask.Flask.app_context`.

This is a proxy. See :ref:`notes-on-proxies` for more information.

.. autofunction:: has_request_context

Expand Down Expand Up @@ -384,50 +381,54 @@ Useful Internals

.. data:: _request_ctx_stack

The internal :class:`~werkzeug.local.LocalStack` that is used to implement
all the context local objects used in Flask. This is a documented
instance and can be used by extensions and application code but the
use is discouraged in general.
The internal :class:`~werkzeug.local.LocalStack` that holds
:class:`~flask.ctx.RequestContext` instances. Typically, the
:data:`request` and :data:`session` proxies should be accessed
instead of the stack. It may be useful to access the stack in
extension code.

The following attributes are always present on each layer of the
stack:
The following attributes are always present on each layer of the
stack:

`app`
`app`
the active Flask application.

`url_adapter`
`url_adapter`
the URL adapter that was used to match the request.

`request`
`request`
the current request object.

`session`
`session`
the active session object.

`g`
`g`
an object with all the attributes of the :data:`flask.g` object.

`flashes`
`flashes`
an internal cache for the flashed messages.

Example usage::
Example usage::

from flask import _request_ctx_stack
from flask import _request_ctx_stack

def get_session():
ctx = _request_ctx_stack.top
if ctx is not None:
return ctx.session
def get_session():
ctx = _request_ctx_stack.top
if ctx is not None:
return ctx.session

.. autoclass:: flask.ctx.AppContext
:members:

.. data:: _app_ctx_stack

Works similar to the request context but only binds the application.
This is mainly there for extensions to store data.
The internal :class:`~werkzeug.local.LocalStack` that holds
:class:`~flask.ctx.AppContext` instances. Typically, the
:data:`current_app` and :data:`g` proxies should be accessed instead
of the stack. Extensions can access the contexts on the stack as a
namespace to store data.

.. versionadded:: 0.9
.. versionadded:: 0.9

.. autoclass:: flask.blueprints.BlueprintSetupState
:members:
Expand Down
211 changes: 113 additions & 98 deletions docs/appcontext.rst
Original file line number Diff line number Diff line change
@@ -1,144 +1,159 @@
.. currentmodule:: flask

.. _app-context:

The Application Context
=======================

.. versionadded:: 0.9

One of the design ideas behind Flask is that there are at least two
different “states” in which code is executed:

1. The application setup state, in which the application implicitly is
on the module level.
The application context keeps track of the application-level data during
a request, CLI command, or other activity. Rather than passing the
application around to each function, the :data:`current_app` and
:data:`g` proxies are accessed instead.

This state starts when the :class:`Flask` object is instantiated, and
it implicitly ends when the first request comes in. While the
application is in this state, a few assumptions are true:
This is similar to the :doc:`/reqcontext`, which keeps track of
request-level data during a request. A corresponding application context
is pushed when a request context is pushed.

- the programmer can modify the application object safely.
- no request handling happened so far
- you have to have a reference to the application object in order to
modify it, there is no magic proxy that can give you a reference to
the application object you're currently creating or modifying.
Purpose of the Context
----------------------

2. In contrast, in the request handling state, a couple of other rules
exist:
The :class:`Flask` application object has attributes, such as
:attr:`~Flask.config`, that are useful to access within views and
:doc:`CLI commands </cli>`. However, importing the ``app`` instance
within the modules in your project is prone to circular import issues.
When using the :doc:`app factory pattern </patterns/appfactories>` or
writing reusable :doc:`blueprints </blueprints>` or
:doc:`extensions </extensions>` there won't be an ``app`` instance to
import at all.

- while a request is active, the context local objects
(:data:`flask.request` and others) point to the current request.
- any code can get hold of these objects at any time.
Flask solves this issue with the *application context*. Rather than
referring to an ``app`` directly, you use the the :data:`current_app`
proxy, which points to the application handling the current activity.

3. There is also a third state somewhere in between 'module-level' and
'request-handling':
Flask automatically *pushes* an application context when handling a
request. View functions, error handlers, and other functions that run
during a request will have access to :data:`current_app`.

Sometimes you are dealing with an application in a way that is similar to
how you interact with applications during request handling, but without
there being an active request. Consider, for instance, that you're
sitting in an interactive Python shell and interacting with the
application, or a command line application.
Flask will also automatically push an app context when running CLI
commands registered with :attr:`Flask.cli` using ``@app.cli.command()``.

The application context is what powers the :data:`~flask.current_app`
context local.

Purpose of the Application Context
----------------------------------
Lifetime of the Context
-----------------------

The main reason for the application's context existence is that in the
past a bunch of functionality was attached to the request context for lack
of a better solution. Since one of the pillars of Flask's design is that
you can have more than one application in the same Python process.
The application context is created and destroyed as necessary. When a
Flask application begins handling a request, it pushes an application
context and a :doc:`request context </reqcontext>`. When the request
ends it pops the request context then the application context.
Typically, an application context will have the same lifetime as a
request.

So how does the code find the “right” application? In the past we
recommended passing applications around explicitly, but that caused issues
with libraries that were not designed with that in mind.
See :doc:`/reqcontext` for more information about how the contexts work
and the full lifecycle of a request.

A common workaround for that problem was to use the
:data:`~flask.current_app` proxy later on, which was bound to the current
request's application reference. Since creating such a request context is
an unnecessarily expensive operation in case there is no request around,
the application context was introduced.

Creating an Application Context
-------------------------------
Manually Push a Context
-----------------------

There are two ways to make an application context. The first one is
implicit: whenever a request context is pushed, an application context
will be created alongside if this is necessary. As a result, you can
ignore the existence of the application context unless you need it.
If you try to access :data:`current_app`, or anything that uses it,
outside an application context, you'll get this error message:

The second way is the explicit way using the
:meth:`~flask.Flask.app_context` method::
.. code-block:: pytb
from flask import Flask, current_app
RuntimeError: Working outside of application context.
app = Flask(__name__)
with app.app_context():
# within this block, current_app points to app.
print current_app.name
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().
The application context is also used by the :func:`~flask.url_for`
function in case a ``SERVER_NAME`` was configured. This allows you to
generate URLs even in the absence of a request.
If you see that error while configuring your application, such as when
initializing an extension, you can push a context manually since you
have direct access to the ``app``. Use :meth:`~Flask.app_context` in a
``with`` block, and everything that runs in the block will have access
to :data:`current_app`. ::

If no request context has been pushed and an application context has
not been explicitly set, a ``RuntimeError`` will be raised. ::
def create_app():
app = Flask(__name__)

RuntimeError: Working outside of application context.
with app.app_context():
init_db()

Locality of the Context
-----------------------
return app

The application context is created and destroyed as necessary. It never
moves between threads and it will not be shared between requests. As such
it is the perfect place to store database connection information and other
things. The internal stack object is called :data:`flask._app_ctx_stack`.
Extensions are free to store additional information on the topmost level,
assuming they pick a sufficiently unique name and should put their
information there, instead of on the :data:`flask.g` object which is reserved
for user code.
If you see that error somewhere else in your code not related to
configuring the application, it most likely indicates that you should
move that code into a view function or CLI command.

For more information about that, see :ref:`extension-dev`.

Context Usage
-------------
Storing Data
------------

The context is typically used to cache resources that need to be created
on a per-request or usage case. For instance, database connections are
destined to go there. When storing things on the application context
unique names should be chosen as this is a place that is shared between
Flask applications and extensions.
The application context is a good place to store common data during a
request or CLI command. Flask provides the :data:`g object <g>` for this
purpose. It is a simple namespace object that has the same lifetime as
an application context.

The most common usage is to split resource management into two parts:
.. note::
The ``g`` name stands for "global", but that is referring to the
data being global *within a context*. The data on ``g`` is lost
after the context ends, and it is not an appropriate place to store
data between requests. Use the :data:`session` or a database to
store data across requests.

1. an implicit resource caching on the context.
2. a context teardown based resource deallocation.
A common use for :data:`g` is to manage resources during a request.

Generally there would be a ``get_X()`` function that creates resource
``X`` if it does not exist yet and otherwise returns the same resource,
and a ``teardown_X()`` function that is registered as teardown handler.
1. ``get_X()`` creates resource ``X`` if it does not exist, caching it
as ``g.X``.
2. ``teardown_X()`` closes or otherwise deallocates the resource if it
exists. It is registered as a :meth:`~Flask.teardown_appcontext`
handler.

This is an example that connects to a database::
For example, you can manage a database connection using this pattern::

import sqlite3
from flask import g

def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = connect_to_database()
return db
if 'db' not in g:
g.db = connect_to_database()

return g.db

@app.teardown_appcontext
def teardown_db(exception):
db = getattr(g, '_database', None)
def teardown_db():
db = g.pop('db', None)

if db is not None:
db.close()

The first time ``get_db()`` is called the connection will be established.
To make this implicit a :class:`~werkzeug.local.LocalProxy` can be used::
During a request, every call to ``get_db()`` will return the same
connection, and it will be closed automatically at the end of the
request.

You can use :class:`~werkzeug.local.LocalProxy` to make a new context
local from ``get_db()``::

from werkzeug.local import LocalProxy
db = LocalProxy(get_db)

That way a user can directly access ``db`` which internally calls
``get_db()``.
Accessing ``db`` will call ``get_db`` internally, in the same way that
:data:`current_app` works.

----

If you're writing an extension, :data:`g` should be reserved for user
code. You may store internal data on the context itself, but be sure to
use a sufficiently unique name. The current context is accessed with
:data:`_app_ctx_stack.top <_app_ctx_stack>`. For more information see
:doc:`extensiondev`.


Events and Signals
------------------

The application will call functions registered with
:meth:`~Flask.teardown_appcontext` when the application context is
popped.

If :data:`~signals.signals_available` is true, the following signals are
sent: :data:`appcontext_pushed`, :data:`appcontext_tearing_down`, and
:data:`appcontext_popped`.

0 comments on commit 16d83d6

Please sign in to comment.