update docs about contexts

This commit is contained in:
David Lord 2022-07-08 07:08:54 -07:00
parent 82c2e0366c
commit e0dad45481
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
9 changed files with 74 additions and 124 deletions

View file

@ -311,56 +311,28 @@ Useful Internals
.. autoclass:: flask.ctx.RequestContext .. autoclass:: flask.ctx.RequestContext
:members: :members:
.. data:: _request_ctx_stack .. data:: flask.globals.request_ctx
The internal :class:`~werkzeug.local.LocalStack` that holds The current :class:`~flask.ctx.RequestContext`. If a request context
:class:`~flask.ctx.RequestContext` instances. Typically, the is not active, accessing attributes on this proxy will raise a
:data:`request` and :data:`session` proxies should be accessed ``RuntimeError``.
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 This is an internal object that is essential to how Flask handles
stack: requests. Accessing this should not be needed in most cases. Most
likely you want :data:`request` and :data:`session` instead.
`app`
the active Flask application.
`url_adapter`
the URL adapter that was used to match the request.
`request`
the current request object.
`session`
the active session object.
`g`
an object with all the attributes of the :data:`flask.g` object.
`flashes`
an internal cache for the flashed messages.
Example usage::
from flask import _request_ctx_stack
def get_session():
ctx = _request_ctx_stack.top
if ctx is not None:
return ctx.session
.. autoclass:: flask.ctx.AppContext .. autoclass:: flask.ctx.AppContext
:members: :members:
.. data:: _app_ctx_stack .. data:: flask.globals.app_ctx
The internal :class:`~werkzeug.local.LocalStack` that holds The current :class:`~flask.ctx.AppContext`. If an app context is not
:class:`~flask.ctx.AppContext` instances. Typically, the active, accessing attributes on this proxy will raise a
:data:`current_app` and :data:`g` proxies should be accessed instead ``RuntimeError``.
of the stack. Extensions can access the contexts on the stack as a
namespace to store data.
.. versionadded:: 0.9 This is an internal object that is essential to how Flask handles
requests. Accessing this should not be needed in most cases. Most
likely you want :data:`current_app` and :data:`g` instead.
.. autoclass:: flask.blueprints.BlueprintSetupState .. autoclass:: flask.blueprints.BlueprintSetupState
:members: :members:

View file

@ -136,14 +136,6 @@ local from ``get_db()``::
Accessing ``db`` will call ``get_db`` internally, in the same way that Accessing ``db`` will call ``get_db`` internally, in the same way that
:data:`current_app` works. :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 Events and Signals
------------------ ------------------

View file

@ -187,12 +187,6 @@ when the application context ends. If it should only be valid during a
request, or would not be used in the CLI outside a reqeust, use request, or would not be used in the CLI outside a reqeust, use
:meth:`~flask.Flask.teardown_request`. :meth:`~flask.Flask.teardown_request`.
An older technique for storing context data was to store it on
``_app_ctx_stack.top`` or ``_request_ctx_stack.top``. However, this just
moves the same namespace collision problem elsewhere (although less
likely) and modifies objects that are very internal to Flask's
operations. Prefer storing data under a unique name in ``g``.
Views and Models Views and Models
---------------- ----------------

View file

@ -30,10 +30,6 @@ or create an application context itself. At that point the ``get_db``
function can be used to get the current database connection. Whenever the function can be used to get the current database connection. Whenever the
context is destroyed the database connection will be terminated. context is destroyed the database connection will be terminated.
Note: if you use Flask 0.9 or older you need to use
``flask._app_ctx_stack.top`` instead of ``g`` as the :data:`flask.g`
object was bound to the request and not application context.
Example:: Example::
@app.route('/') @app.route('/')

View file

@ -37,12 +37,14 @@ context, which also pushes an :doc:`app context </appcontext>`. When the
request ends it pops the request context then the application context. request ends it pops the request context then the application context.
The context is unique to each thread (or other worker type). The context is unique to each thread (or other worker type).
:data:`request` cannot be passed to another thread, the other thread :data:`request` cannot be passed to another thread, the other thread has
will have a different context stack and will not know about the request a different context space and will not know about the request the parent
the parent thread was pointing to. thread was pointing to.
Context locals are implemented in Werkzeug. See :doc:`werkzeug:local` Context locals are implemented using Python's :mod:`contextvars` and
for more information on how this works internally. Werkzeug's :class:`~werkzeug.local.LocalProxy`. Python manages the
lifetime of context vars automatically, and local proxy wraps that
low-level interface to make the data easier to work with.
Manually Push a Context Manually Push a Context
@ -87,10 +89,9 @@ How the Context Works
The :meth:`Flask.wsgi_app` method is called to handle each request. It The :meth:`Flask.wsgi_app` method is called to handle each request. It
manages the contexts during the request. Internally, the request and manages the contexts during the request. Internally, the request and
application contexts work as stacks, :data:`_request_ctx_stack` and application contexts work like stacks. When contexts are pushed, the
:data:`_app_ctx_stack`. When contexts are pushed onto the stack, the
proxies that depend on them are available and point at information from proxies that depend on them are available and point at information from
the top context on the stack. the top item.
When the request starts, a :class:`~ctx.RequestContext` is created and When the request starts, a :class:`~ctx.RequestContext` is created and
pushed, which creates and pushes an :class:`~ctx.AppContext` first if pushed, which creates and pushes an :class:`~ctx.AppContext` first if
@ -99,10 +100,10 @@ these contexts are pushed, the :data:`current_app`, :data:`g`,
:data:`request`, and :data:`session` proxies are available to the :data:`request`, and :data:`session` proxies are available to the
original thread handling the request. original thread handling the request.
Because the contexts are stacks, other contexts may be pushed to change Other contexts may be pushed to change the proxies during a request.
the proxies during a request. While this is not a common pattern, it While this is not a common pattern, it can be used in advanced
can be used in advanced applications to, for example, do internal applications to, for example, do internal redirects or chain different
redirects or chain different applications together. applications together.
After the request is dispatched and a response is generated and sent, After the request is dispatched and a response is generated and sent,
the request context is popped, which then pops the application context. the request context is popped, which then pops the application context.

View file

@ -1284,29 +1284,30 @@ class Flask(Scaffold):
@setupmethod @setupmethod
def teardown_appcontext(self, f: T_teardown) -> T_teardown: def teardown_appcontext(self, f: T_teardown) -> T_teardown:
"""Registers a function to be called when the application context """Registers a function to be called when the application
ends. These functions are typically also called when the request context is popped. The application context is typically popped
context is popped. after the request context for each request, at the end of CLI
commands, or after a manually pushed context ends.
Example:: .. code-block:: python
ctx = app.app_context() with app.app_context():
ctx.push() ...
...
ctx.pop()
When ``ctx.pop()`` is executed in the above example, the teardown When the ``with`` block exits (or ``ctx.pop()`` is called), the
functions are called just before the app context moves from the teardown functions are called just before the app context is
stack of active contexts. This becomes relevant if you are using made inactive. Since a request context typically also manages an
such constructs in tests. application context it would also be called when you pop a
request context.
Since a request context typically also manages an application When a teardown function was called because of an unhandled
context it would also be called when you pop a request context. exception it will be passed an error object. If an
:meth:`errorhandler` is registered, it will handle the exception
and the teardown will not receive it.
When a teardown function was called because of an unhandled exception Teardown functions must avoid raising exceptions. If they
it will be passed an error object. If an :meth:`errorhandler` is execute code that might fail they must surround that code with a
registered, it will handle the exception and the teardown will not ``try``/``except`` block and log any errors.
receive it.
The return values of teardown functions are ignored. The return values of teardown functions are ignored.

View file

@ -227,12 +227,10 @@ def has_app_context() -> bool:
class AppContext: class AppContext:
"""The application context binds an application object implicitly """The app context contains application-specific information. An app
to the current thread or greenlet, similar to how the context is created and pushed at the beginning of each request if
:class:`RequestContext` binds request information. The application one is not already active. An app context is also pushed when
context is also implicitly created if a request context is created running CLI commands.
but the application is not on top of the individual application
context.
""" """
def __init__(self, app: "Flask") -> None: def __init__(self, app: "Flask") -> None:
@ -278,10 +276,10 @@ class AppContext:
class RequestContext: class RequestContext:
"""The request context contains all request relevant information. It is """The request context contains per-request information. The Flask
created at the beginning of the request and pushed to the app creates and pushes it at the beginning of the request, then pops
`_request_ctx_stack` and removed at the end of it. It will create the it at the end of the request. It will create the URL adapter and
URL adapter and request object for the WSGI environment provided. request object for the WSGI environment provided.
Do not attempt to use this class directly, instead use Do not attempt to use this class directly, instead use
:meth:`~flask.Flask.test_request_context` and :meth:`~flask.Flask.test_request_context` and

View file

@ -574,30 +574,27 @@ class Scaffold:
@setupmethod @setupmethod
def teardown_request(self, f: T_teardown) -> T_teardown: def teardown_request(self, f: T_teardown) -> T_teardown:
"""Register a function to be run at the end of each request, """Register a function to be called when the request context is
regardless of whether there was an exception or not. These functions popped. Typically this happens at the end of each request, but
are executed when the request context is popped, even if not an contexts may be pushed manually as well during testing.
actual request was performed.
Example:: .. code-block:: python
ctx = app.test_request_context() with app.test_request_context():
ctx.push() ...
...
ctx.pop()
When ``ctx.pop()`` is executed in the above example, the teardown When the ``with`` block exits (or ``ctx.pop()`` is called), the
functions are called just before the request context moves from the teardown functions are called just before the request context is
stack of active contexts. This becomes relevant if you are using made inactive.
such constructs in tests.
Teardown functions must avoid raising exceptions. If When a teardown function was called because of an unhandled
they execute code that might fail they exception it will be passed an error object. If an
will have to surround the execution of that code with try/except :meth:`errorhandler` is registered, it will handle the exception
statements and log any errors. and the teardown will not receive it.
When a teardown function was called because of an exception it will Teardown functions must avoid raising exceptions. If they
be passed an error object. execute code that might fail they must surround that code with a
``try``/``except`` block and log any errors.
The return values of teardown functions are ignored. The return values of teardown functions are ignored.
""" """

View file

@ -94,11 +94,10 @@ class EnvironBuilder(werkzeug.test.EnvironBuilder):
class FlaskClient(Client): class FlaskClient(Client):
"""Works like a regular Werkzeug test client but has some knowledge about """Works like a regular Werkzeug test client but has knowledge about
how Flask works to defer the cleanup of the request context stack to the Flask's contexts to defer the cleanup of the request context until
end of a ``with`` body when used in a ``with`` statement. For general the end of a ``with`` block. For general information about how to
information about how to use this class refer to use this class refer to :class:`werkzeug.test.Client`.
:class:`werkzeug.test.Client`.
.. versionchanged:: 0.12 .. versionchanged:: 0.12
`app.test_client()` includes preset default environment, which can be `app.test_client()` includes preset default environment, which can be