summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBert JW Regeer <bertjw@regeer.org>2017-05-23 13:53:10 -0700
committerBert JW Regeer <bertjw@regeer.org>2017-05-23 13:53:10 -0700
commitdda9fa85a8132ae3a18ff0b09e902ee6057430d1 (patch)
tree605621470da8e304d5249f7fc2f83fe06e84c98d
parent50d216a549bc848f411769690d722d367c91fdb4 (diff)
downloadpyramid-dda9fa85a8132ae3a18ff0b09e902ee6057430d1.tar.gz
pyramid-dda9fa85a8132ae3a18ff0b09e902ee6057430d1.tar.bz2
pyramid-dda9fa85a8132ae3a18ff0b09e902ee6057430d1.zip
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.
-rw-r--r--pyramid/tests/test_view.py22
-rw-r--r--pyramid/threadlocal.py2
-rw-r--r--pyramid/view.py40
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