summaryrefslogtreecommitdiff
path: root/repoze/bfg/request.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-09-12 22:33:16 +0000
committerChris McDonough <chrism@agendaless.com>2010-09-12 22:33:16 +0000
commitad6a6706391c60dbdb66073caff1306b771da0bd (patch)
tree058fa1f42f71069112b0258bb249730231941811 /repoze/bfg/request.py
parent79c11cc905bcc5eae4f1b6e63aa187551966be34 (diff)
downloadpyramid-ad6a6706391c60dbdb66073caff1306b771da0bd.tar.gz
pyramid-ad6a6706391c60dbdb66073caff1306b771da0bd.tar.bz2
pyramid-ad6a6706391c60dbdb66073caff1306b771da0bd.zip
- Add a new request API: ``request.add_finished_callback``. Finished
callbacks are called by the router unconditionally near the very end of request processing.
Diffstat (limited to 'repoze/bfg/request.py')
-rw-r--r--repoze/bfg/request.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/repoze/bfg/request.py b/repoze/bfg/request.py
index 6318faf5a..6e5417d9a 100644
--- a/repoze/bfg/request.py
+++ b/repoze/bfg/request.py
@@ -39,6 +39,7 @@ class Request(WebobRequest):
"""
implements(IRequest)
response_callbacks = ()
+ finished_callbacks = ()
default_charset = 'utf-8'
def add_response_callback(self, callback):
@@ -84,6 +85,60 @@ class Request(WebobRequest):
callback(self, response)
self.response_callbacks = ()
+ def add_finished_callback(self, callback):
+ """
+ Add a callback to the set of callbacks to be called
+ unconditionally by the :term:`router` at the very end of
+ request processing.
+
+ ``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 hasattr(request, 'exception'):
+ 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
+ response callbacks) 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 last thing called by the :term:`router`. 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.
+
+ Errors raised by finished callbacks are not handled specially.
+ They will be propagated to the caller of the :mod:`repoze.bfg`
+ router application. """
+
+ callbacks = self.finished_callbacks
+ if not callbacks:
+ callbacks = []
+ callbacks.append(callback)
+ self.finished_callbacks = callbacks
+
+ def _process_finished_callbacks(self):
+ for callback in self.finished_callbacks:
+ callback(self)
+ self.finished_callbacks = ()
+
# override default WebOb "environ['adhoc_attr']" mutation behavior
__getattr__ = object.__getattribute__
__setattr__ = object.__setattr__