Skip to content

Commit

Permalink
Backport Pylons#3649 to 1.10 branch.
Browse files Browse the repository at this point in the history
  • Loading branch information
luhn committed Jan 15, 2021
1 parent aa6f92b commit f7af5f1
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 4 deletions.
8 changes: 6 additions & 2 deletions src/pyramid/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,12 @@ def invoke_request(self, request, _use_tweens=True):
return response

finally:
if request.finished_callbacks:
request._process_finished_callbacks()
self.finish_request(request)

def finish_request(self, request):
if request.finished_callbacks:
request._process_finished_callbacks()
request.__dict__.pop('context', None) # Break potential ref cycle

def __call__(self, environ, start_response):
"""
Expand Down
27 changes: 25 additions & 2 deletions tests/test_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ def _makeOne(self):
klass = self._getTargetClass()
return klass(self.registry)

def _mockFinishRequest(self, router):
"""
Mock :meth:`pyramid.router.Router.finish_request` to be a no-op. This
prevents :prop:`pyramid.request.Request.context` from being removed, so
we can write assertions against it.
"""

def mock_finish_request(request):
pass

router.finish_request = mock_finish_request

def _makeEnviron(self, **extras):
environ = {
'wsgi.url_scheme': 'http',
Expand Down Expand Up @@ -422,6 +435,7 @@ def test_call_view_registered_nonspecific_default_path(self):
)
self._registerRootFactory(context)
router = self._makeOne()
self._mockFinishRequest(router)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
Expand Down Expand Up @@ -449,6 +463,7 @@ def test_call_view_registered_nonspecific_nondefault_path_and_subpath(
environ = self._makeEnviron()
self._registerView(view, 'foo', IViewClassifier, None, None)
router = self._makeOne()
self._mockFinishRequest(router)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
Expand Down Expand Up @@ -480,6 +495,7 @@ class IContext(Interface):
environ = self._makeEnviron()
self._registerView(view, '', IViewClassifier, IRequest, IContext)
router = self._makeOne()
self._mockFinishRequest(router)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
Expand Down Expand Up @@ -627,7 +643,7 @@ def callback(request, response):
router(environ, start_response)
self.assertEqual(response.called_back, True)

def test_call_request_has_finished_callbacks_when_view_succeeds(self):
def test_finish_request_when_view_succeeds(self):
from zope.interface import Interface
from zope.interface import directlyProvides

Expand All @@ -647,6 +663,7 @@ def callback(request):
request.environ['called_back'] = True

request.add_finished_callback(callback)
request.environ['request'] = request
return response

environ = self._makeEnviron()
Expand All @@ -655,8 +672,9 @@ def callback(request):
start_response = DummyStartResponse()
router(environ, start_response)
self.assertEqual(environ['called_back'], True)
self.assertFalse(hasattr(environ['request'], 'context'))

def test_call_request_has_finished_callbacks_when_view_raises(self):
def test_finish_request_when_view_raises(self):
from zope.interface import Interface
from zope.interface import directlyProvides

Expand All @@ -675,6 +693,7 @@ def callback(request):
request.environ['called_back'] = True

request.add_finished_callback(callback)
request.environ['request'] = request
raise NotImplementedError

environ = self._makeEnviron()
Expand All @@ -683,6 +702,7 @@ def callback(request):
start_response = DummyStartResponse()
exc_raised(NotImplementedError, router, environ, start_response)
self.assertEqual(environ['called_back'], True)
self.assertFalse(hasattr(environ['request'], 'context'))

def test_call_request_factory_raises(self):
# making sure finally doesnt barf when a request cannot be created
Expand Down Expand Up @@ -715,6 +735,7 @@ def test_call_eventsends(self):
context_found_events = self._registerEventListener(IContextFound)
response_events = self._registerEventListener(INewResponse)
router = self._makeOne()
self._mockFinishRequest(router)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(len(request_events), 1)
Expand Down Expand Up @@ -776,6 +797,7 @@ def factory(request):
self._registerView(view, '', IViewClassifier, None, None)
self._registerRootFactory(context)
router = self._makeOne()
self._mockFinishRequest(router)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
Expand Down Expand Up @@ -851,6 +873,7 @@ def factory(request):
self._registerView(view, '', IViewClassifier, None, None)
self._registerRootFactory(context)
router = self._makeOne()
self._mockFinishRequest(router)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
Expand Down

0 comments on commit f7af5f1

Please sign in to comment.