From d5225795b3b98b8ef746ba5f9a807eb701d099bb Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 2 Mar 2016 23:46:37 -0600 Subject: fix and add tests for invoke_exception_view --- pyramid/tests/test_view.py | 132 +++++++++++++++++++++++++++++++++++++++++++++ pyramid/view.py | 7 +-- 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index e6b9f9e7e..2be47e318 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -673,6 +673,138 @@ class Test_view_defaults(unittest.TestCase): class Bar(Foo): pass self.assertEqual(Bar.__view_defaults__, {}) +class TestViewMethodsMixin(unittest.TestCase): + def setUp(self): + self.config = testing.setUp() + + def tearDown(self): + testing.tearDown() + + def _makeOne(self, environ=None): + from pyramid.decorator import reify + from pyramid.view import ViewMethodsMixin + if environ is None: + environ = {} + class Request(ViewMethodsMixin): + def __init__(self, environ): + self.environ = environ + + @reify + def response(self): + return DummyResponse() + request = Request(environ) + request.registry = self.config.registry + return request + + def test_it(self): + def exc_view(exc, request): + self.assertTrue(exc is dummy_exc) + self.assertTrue(request.exception is dummy_exc) + return DummyResponse(b'foo') + self.config.add_view(exc_view, context=RuntimeError) + request = self._makeOne() + dummy_exc = RuntimeError() + try: + raise dummy_exc + except RuntimeError: + response = request.invoke_exception_view() + self.assertEqual(response.app_iter, [b'foo']) + else: # pragma: no cover + self.fail() + + def test_it_hides_attrs(self): + def exc_view(exc, request): + self.assertTrue(exc is not orig_exc) + self.assertTrue(request.exception is not orig_exc) + self.assertTrue(request.exc_info is not orig_exc_info) + self.assertTrue(request.response is not orig_response) + request.response.app_iter = [b'bar'] + return request.response + self.config.add_view(exc_view, context=RuntimeError) + request = self._makeOne() + orig_exc = request.exception = DummyContext() + orig_exc_info = request.exc_info = DummyContext() + orig_response = request.response = DummyResponse(b'foo') + try: + raise RuntimeError + except RuntimeError: + response = request.invoke_exception_view() + self.assertEqual(response.app_iter, [b'bar']) + self.assertTrue(request.exception is orig_exc) + self.assertTrue(request.exc_info is orig_exc_info) + self.assertTrue(request.response is orig_response) + else: # pragma: no cover + self.fail() + + def test_it_supports_alternate_requests(self): + def exc_view(exc, request): + self.assertTrue(request is other_req) + return DummyResponse(b'foo') + self.config.add_view(exc_view, context=RuntimeError) + request = self._makeOne() + other_req = self._makeOne() + try: + raise RuntimeError + except RuntimeError: + response = request.invoke_exception_view(request=other_req) + self.assertEqual(response.app_iter, [b'foo']) + else: # pragma: no cover + self.fail() + + def test_it_supports_threadlocal_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 + try: + raise RuntimeError + except RuntimeError: + response = request.invoke_exception_view() + self.assertEqual(response.app_iter, [b'foo']) + else: # pragma: no cover + self.fail() + + def test_it_supports_alternate_exc_info(self): + def exc_view(exc, request): + self.assertTrue(request.exc_info is exc_info) + return DummyResponse(b'foo') + self.config.add_view(exc_view, context=RuntimeError) + request = self._makeOne() + try: + raise RuntimeError + except RuntimeError: + exc_info = sys.exc_info() + response = request.invoke_exception_view(exc_info=exc_info) + self.assertEqual(response.app_iter, [b'foo']) + + def test_it_rejects_secured_view(self): + from pyramid.exceptions import Forbidden + def exc_view(exc, request): pass + self.config.testing_securitypolicy(permissive=False) + self.config.add_view(exc_view, context=RuntimeError, permission='view') + request = self._makeOne() + try: + raise RuntimeError + except RuntimeError: + self.assertRaises(Forbidden, request.invoke_exception_view) + else: # pragma: no cover + self.fail() + + def test_it_allows_secured_view(self): + def exc_view(exc, request): + return DummyResponse(b'foo') + self.config.testing_securitypolicy(permissive=False) + self.config.add_view(exc_view, context=RuntimeError, permission='view') + request = self._makeOne() + try: + raise RuntimeError + except RuntimeError: + response = request.invoke_exception_view(secure=False) + self.assertEqual(response.app_iter, [b'foo']) + else: # pragma: no cover + self.fail() + class ExceptionResponse(Exception): status = '404 Not Found' app_iter = ['Not Found'] diff --git a/pyramid/view.py b/pyramid/view.py index 16b60b77a..9108f120e 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -598,14 +598,15 @@ class ViewMethodsMixin(object): registry = get_current_registry() if exc_info is None: exc_info = sys.exc_info() + exc = exc_info[1] attrs = request.__dict__ - context_iface = providedBy(exc_info[0]) + context_iface = providedBy(exc) # clear old generated request.response, if any; it may # have been mutated by the view, and its state is not # sane (e.g. caching headers) with hide_attrs(request, 'exception', 'exc_info', 'response'): - attrs['exception'] = exc_info[0] + attrs['exception'] = exc attrs['exc_info'] = exc_info # we use .get instead of .__getitem__ below due to # https://github.com/Pylons/pyramid/issues/700 @@ -613,7 +614,7 @@ class ViewMethodsMixin(object): response = _call_view( registry, request, - exc_info[0], + exc, context_iface, '', view_types=None, -- cgit v1.2.3