From dda9fa85a8132ae3a18ff0b09e902ee6057430d1 Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 23 May 2017 13:53:10 -0700 Subject: When invoking an exception view, push the new threadlocals This way when calling the threadlocal get_current_request() you get the same request object as the one that was passed to the view. --- pyramid/tests/test_view.py | 22 ++++++++++++++++++++++ pyramid/threadlocal.py | 2 +- pyramid/view.py | 40 ++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index 2061515b3..9f02b1352 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -790,6 +790,8 @@ class TestViewMethodsMixin(unittest.TestCase): def test_it_supports_alternate_requests(self): def exc_view(exc, request): self.assertTrue(request is other_req) + from pyramid.threadlocal import get_current_request + self.assertTrue(get_current_request() is other_req) return DummyResponse(b'foo') self.config.add_view(exc_view, context=RuntimeError) request = self._makeOne() @@ -816,6 +818,26 @@ class TestViewMethodsMixin(unittest.TestCase): else: # pragma: no cover self.fail() + def test_it_raises_if_no_registry(self): + def exc_view(exc, request): + return DummyResponse(b'foo') + self.config.add_view(exc_view, context=RuntimeError) + request = self._makeOne() + del request.registry + from pyramid.threadlocal import manager + manager.push({'registry': None, 'request': request}) + try: + raise RuntimeError + except RuntimeError: + try: + request.invoke_exception_view() + except RuntimeError as e: + self.assertEqual(e.args[0], "Unable to retrieve registry") + else: # pragma: no cover + self.fail() + finally: + manager.pop() + def test_it_supports_alternate_exc_info(self): def exc_view(exc, request): self.assertTrue(request.exc_info is exc_info) diff --git a/pyramid/threadlocal.py b/pyramid/threadlocal.py index 638f7b7b0..9429fe953 100644 --- a/pyramid/threadlocal.py +++ b/pyramid/threadlocal.py @@ -31,7 +31,7 @@ class ThreadLocalManager(threading.local): self.stack[:] = [] def defaults(): - return {'request':None, 'registry':global_registry} + return {'request': None, 'registry': global_registry} manager = ThreadLocalManager(default=defaults) diff --git a/pyramid/view.py b/pyramid/view.py index 0c1b8cd97..14c8c029e 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -28,7 +28,11 @@ from pyramid.httpexceptions import ( default_exceptionresponse_view, ) -from pyramid.threadlocal import get_current_registry +from pyramid.threadlocal import ( + get_current_registry, + manager, + ) + from pyramid.util import hide_attrs _marker = object() @@ -675,8 +679,13 @@ class ViewMethodsMixin(object): registry = getattr(request, 'registry', None) if registry is None: registry = get_current_registry() + + if registry is None: + raise RuntimeError("Unable to retrieve registry") + if exc_info is None: exc_info = sys.exc_info() + exc = exc_info[1] attrs = request.__dict__ context_iface = providedBy(exc) @@ -690,17 +699,24 @@ class ViewMethodsMixin(object): # we use .get instead of .__getitem__ below due to # https://github.com/Pylons/pyramid/issues/700 request_iface = attrs.get('request_iface', IRequest) - response = _call_view( - registry, - request, - exc, - context_iface, - '', - view_types=None, - view_classifier=IExceptionViewClassifier, - secure=secure, - request_iface=request_iface.combined, - ) + + try: + if request is not self: + manager.push({'request': request, 'registry': registry}) + + response = _call_view( + registry, + request, + exc, + context_iface, + '', + view_types=None, + view_classifier=IExceptionViewClassifier, + secure=secure, + request_iface=request_iface.combined, + ) + finally: + manager.pop() if response is None: raise HTTPNotFound -- cgit v1.2.3 From 3bb3c6e18bc94856b8c08907dfea5d1ce8217754 Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 23 May 2017 13:59:55 -0700 Subject: Make coverage happy again --- pyramid/tests/test_view.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index 9f02b1352..a9ce2234d 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -819,9 +819,6 @@ class TestViewMethodsMixin(unittest.TestCase): self.fail() def test_it_raises_if_no_registry(self): - def exc_view(exc, request): - return DummyResponse(b'foo') - self.config.add_view(exc_view, context=RuntimeError) request = self._makeOne() del request.registry from pyramid.threadlocal import manager -- cgit v1.2.3 From 4f66355fb5d7e6fe319742cb50f263425a88c57f Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Tue, 23 May 2017 14:35:48 -0700 Subject: Always push the threadlocals --- pyramid/view.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyramid/view.py b/pyramid/view.py index 14c8c029e..47b756ad8 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -700,10 +700,9 @@ class ViewMethodsMixin(object): # https://github.com/Pylons/pyramid/issues/700 request_iface = attrs.get('request_iface', IRequest) - try: - if request is not self: - manager.push({'request': request, 'registry': registry}) + manager.push({'request': request, 'registry': registry}) + try: response = _call_view( registry, request, -- cgit v1.2.3