diff options
| author | Chris McDonough <chrism@agendaless.com> | 2010-09-13 02:39:26 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2010-09-13 02:39:26 +0000 |
| commit | 81d3b5412b43e4a104d0118ad4147402d787220e (patch) | |
| tree | bcf8b75f49b9015286a6439e67d71ad45f114292 /docs/narr/hooks.rst | |
| parent | ad6a6706391c60dbdb66073caff1306b771da0bd (diff) | |
| download | pyramid-81d3b5412b43e4a104d0118ad4147402d787220e.tar.gz pyramid-81d3b5412b43e4a104d0118ad4147402d787220e.tar.bz2 pyramid-81d3b5412b43e4a104d0118ad4147402d787220e.zip | |
Features
--------
- A ``request.matched_route`` attribute is now added to the request
when a route has matched. Its value is the "route" object that
matched (see the ``IRoute`` interface within
``repoze.bfg.interfaces`` API documentation for the API of a route
object).
- The ``exception`` attribute of the request is now set slightly
earlier and in a slightly different set of scenarios, for benefit of
"finished callbacks" and "response callbacks". In previous
versions, the ``exception`` attribute of the request was not set at
all if an exception view was not found. In this version, the
``request.exception`` attribute is set immediately when an exception
is caught by the router, even if an exception view could not be
found.
Backwards Incompatibilities
---------------------------
- The router no longer sets the value ``wsgiorg.routing_args`` into
the environ when a route matches. The value used to be something
like ``((), matchdict)``. This functionality was only ever
obliquely referred to in change logs; it was never documented as an
API.
- The ``exception`` attribute of the request now defaults to ``None``.
In prior versions, the ``request.exception`` attribute did not exist
if an exception was not raised by user code during request
processing; it only began existence once an exception view was
found.
Deprecations
------------
- References to the WSGI environment values ``bfg.routes.matchdict``
and ``bfg.routes.route`` were removed from documentation. These
will stick around internally for several more releases, but it is
``request.matchdict`` and ``request.matched_route`` are now the
"official" way to obtain the matchdict and the route object which
resulted in the match.
Documentation
-------------
- Added two sections to the "Hooks" chapter of the documentation:
"Using Response Callbacks" and "Using Finished Callbacks".
- Added documentation of the ``request.exception`` attribute to the
``repoze.bfg.request.Request`` API documentation.
- Added glossary entries for "response callback" and "finished
callback".
- The "Request Processing" narrative chapter has been updated to note
finished and response callback steps.
Diffstat (limited to 'docs/narr/hooks.rst')
| -rw-r--r-- | docs/narr/hooks.rst | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b00fc6727..965a4c77f 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -461,6 +461,111 @@ method: config = Configurator() config.set_renderer_globals_factory(renderer_globals_factory) +.. _using_response_callbacks: + +Using Response Callbacks +------------------------ + +Unlike many other web frameworks, :mod:`repoze.bfg` does not eagerly +create a global response object. Adding a :term:`response callback` +allows an application to register an action to be performed against a +response object once it is created, usually in order to mutate it. + +The :meth:`repoze.bfg.request.Request.add_response_callback` method is +used to register a response callback. + +A response callback is a callable which accepts two positional +parameters: ``request`` and ``response``. For example: + +.. code-block:: python + :linenos: + + def cache_callback(request, response): + """Set the cache_control max_age for the response""" + if request.exception is not None: + response.cache_control.max_age = 360 + request.add_response_callback(cache_callback) + +No response callback is called if an unhandled exception happens in +application code, or if the response object returned by a :term:`view +callable` is invalid. Response callbacks *are*, however, invoked when +a :term:`exception view` is rendered successfully: in such a case, the +:attr:`request.exception` attribute of the request when it enters a +response callback will be an exception object instead of its default +value of ``None``. + +Response callbacks are called in the order they're added +(first-to-most-recently-added). All response callbacks are called +*before* the :class:`repoze.bfg.interfaces.INewResponse` event is +sent. Errors raised by response callbacks are not handled specially. +They will be propagated to the caller of the :mod:`repoze.bfg` router +application. + +A response callback has a lifetime of a *single* request. If you want +a response callback to happen as the result of *every* request, you +must re-register the callback into every new request (perhaps within a +subscriber of a :class:`repoze.bfg.interfaces.INewRequest` event). + +.. _using_finished_callbacks: + +Using Finished Callbacks +------------------------ + +A :term:`finished callback` is a function that will be called +unconditionally by the :mod:`repoze.bfg` :term:`router` at the very +end of request processing. A finished callback can be used to perform +an action at the end of a request unconditionally. + +The :meth:`repoze.bfg.request.Request.add_finished_callback` method is +used to register a finished callback. + +A finished callback is a callable which accepts a single positional +parameter: ``request``. For example: + +.. code-block:: python + :linenos: + + import transaction + + def commit_callback(request): + '''commit or abort the transaction associated with request''' + if request.exception is not None: + transaction.abort() + else: + transaction.commit() + request.add_finished_callback(commit_callback) + +Finished callbacks are called in the order they're added ( first- to +most-recently- added). Finished callbacks (unlike a :term:`response +callback`) are *always* called, even if an exception happens in +application code that prevents a response from being generated. + +The set of finished callbacks associated with a request are called +*very late* in the processing of that request; they are essentially +the very last thing called by the :term:`router` before a request +"ends". They are called after response processing has already occurred +in a top-level ``finally:`` block within the router request processing +code. As a result, mutations performed to the ``request`` provided to +a finished callback will have no meaningful effect, because response +processing will have already occurred, and the request's scope will +expire almost immediately after all finished callbacks have been +processed. + +It is often necessary to tell whether an exception occurred within +:term:`view callable` code from within a finished callback: in such a +case, the :attr:`request.exception` attribute of the request when it +enters a response callback will be an exception object instead of its +default value of ``None``. + +Errors raised by finished callbacks are not handled specially. They +will be propagated to the caller of the :mod:`repoze.bfg` router +application. + +A finished callback has a lifetime of a *single* request. If you want +a finished callback to happen as the result of *every* request, you +must re-register the callback into every new request (perhaps within a +subscriber of a :class:`repoze.bfg.interfaces.INewRequest` event). + .. _registering_configuration_decorators: Registering Configuration Decorators |
