diff options
| -rw-r--r-- | CHANGES.txt | 11 | ||||
| -rw-r--r-- | pyramid/tests/test_router.py | 11 | ||||
| -rw-r--r-- | pyramid/tweens.py | 16 |
3 files changed, 26 insertions, 12 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index d82b3b641..ed70d7036 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,14 @@ +Next release +============ + +Features +-------- + +- We no longer eagerly clear ``request.exception`` and ``request.exc_info`` in + the exception view tween. This makes it possible to inspect exception + information within a finished callback. See + https://github.com/Pylons/pyramid/issues/1223. + 1.5a4 (2014-01-28) ================== diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py index b836d7d72..838e52db0 100644 --- a/pyramid/tests/test_router.py +++ b/pyramid/tests/test_router.py @@ -830,7 +830,8 @@ class TestRouter(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() response.app_iter = ['OK'] - view = DummyView(response, raise_exception=RuntimeError) + error = RuntimeError() + view = DummyView(response, raise_exception=error) environ = self._makeEnviron() def exception_view(context, request): self.assertEqual(request.exc_info[0], RuntimeError) @@ -842,9 +843,11 @@ class TestRouter(unittest.TestCase): start_response = DummyStartResponse() result = router(environ, start_response) self.assertEqual(result, ['OK']) - # we clean up the exc_info and exception after the request - self.assertEqual(request.exception, None) - self.assertEqual(request.exc_info, None) + # exc_info and exception should still be around on the request after + # the excview tween has run (see + # https://github.com/Pylons/pyramid/issues/1223) + self.assertEqual(request.exception, error) + self.assertEqual(request.exc_info[:2], (RuntimeError, error,)) def test_call_view_raises_exception_view(self): from pyramid.interfaces import IViewClassifier diff --git a/pyramid/tweens.py b/pyramid/tweens.py index cf2238deb..831de8481 100644 --- a/pyramid/tweens.py +++ b/pyramid/tweens.py @@ -20,8 +20,14 @@ def excview_tween_factory(handler, registry): try: response = handler(request) except Exception as exc: - # WARNING: do not assign the result of sys.exc_info() to a - # local var here, doing so will cause a leak + # WARNING: do not assign the result of sys.exc_info() to a local + # var here, doing so will cause a leak. We used to actually + # explicitly delete both "exception" and "exc_info" from ``attrs`` + # in a ``finally:`` clause below, but now we do not because these + # attributes are useful to upstream tweens. This actually still + # apparently causes a reference cycle, but it is broken + # successfully by the garbage collector (see + # https://github.com/Pylons/pyramid/issues/1223). attrs['exc_info'] = sys.exc_info() attrs['exception'] = exc # clear old generated request.response, if any; it may @@ -38,12 +44,6 @@ def excview_tween_factory(handler, registry): if view_callable is None: raise response = view_callable(exc, request) - finally: - # prevent leakage (wrt exc_info) - if 'exc_info' in attrs: - del attrs['exc_info'] - if 'exception' in attrs: - del attrs['exception'] return response |
