Skip to content

Commit

Permalink
Merge branch 'master' into py38
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Howitz committed Feb 9, 2019
2 parents e626cf8 + e664a8c commit 2b5d615
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGES.rst
Expand Up @@ -19,6 +19,9 @@ Features
Fixes
+++++

- Make sure conflicts are always retried and not masked by exception views
(`#413 <https://github.com/zopefoundation/Zope/issues/413>`_)

- Fix faulty ZMI links due to missing URL-quoting
(`#391 <https://github.com/zopefoundation/Zope/issues/391>`_)

Expand All @@ -44,6 +47,7 @@ Other changes
+++++++++++++

- Document filesystem caching for Chameleon page templates
and activate it by default for new WSGI instances
(`#291 <https://github.com/zopefoundation/Zope/issues/291>`_)

- Remove obsolete environment variable "Z_DEBUG_MODE"
Expand Down
3 changes: 3 additions & 0 deletions src/ZPublisher/WSGIPublisher.py
Expand Up @@ -166,6 +166,9 @@ def transaction_pubevents(request, response, tm=transaction.manager):
notify(pubevents.PubFailure(
request, exc_info, request.supports_retry()))

if isinstance(exc, TransientError) and request.supports_retry():
reraise(*exc_info)

if not (exc_view_created or isinstance(exc, Unauthorized)):
reraise(*exc_info)
finally:
Expand Down
49 changes: 49 additions & 0 deletions src/ZPublisher/tests/test_WSGIPublisher.py
Expand Up @@ -469,6 +469,50 @@ def _publish(request, module_info):
finally:
HTTPRequest.retry_max_count = original_retry_max_count

def testCustomExceptionViewConflictErrorHandling(self):
# Make sure requests are retried as often as configured
# even if an exception view has been registered that
# matches ConflictError
from zope.interface import directlyProvides
from zope.publisher.browser import IDefaultBrowserLayer
registerExceptionView(Exception)
environ = self._makeEnviron()
start_response = DummyCallable()
_publish = DummyCallable()
_publish._raise = ConflictError('oops')
_request = DummyRequest()
directlyProvides(_request, IDefaultBrowserLayer)
_request.response = DummyResponse()
_request.retry_count = 0
_request.retry_max_count = 3
_request.environ = {}

def _close():
pass
_request.close = _close

def _retry():
_request.retry_count += 1
return _request
_request.retry = _retry

def _supports_retry():
return _request.retry_count < _request.retry_max_count
_request.supports_retry = _supports_retry

def _request_factory(stdin, environ, response):
return _request

# At first, retry_count is zero. Request has never been retried.
self.assertEqual(_request.retry_count, 0)
app_iter = self._callFUT(environ, start_response, _publish,
_request_factory=_request_factory)

# In the end the error view is rendered, but the request should
# have been retried up to retry_max_count times
self.assertTrue(app_iter[1].startswith('Exception View: ConflictError'))
self.assertEqual(_request.retry_count, _request.retry_max_count)

def testCustomExceptionViewUnauthorized(self):
from AccessControl import Unauthorized
registerExceptionView(IUnauthorized)
Expand Down Expand Up @@ -717,6 +761,11 @@ def setBody(self, body):

body = property(lambda self: self._body, setBody)

def setStatus(self, status, reason=None, lock=None):
self._status = status

status = property(lambda self: self._status, setStatus)


class DummyCallable(object):
_called_with = _raise = _result = None
Expand Down
5 changes: 4 additions & 1 deletion src/Zope2/utilities/skel/etc/wsgi.conf.in
Expand Up @@ -48,8 +48,11 @@ instancehome $INSTANCE
# Example:
#
# <environment>
# CHAMELEON_CACHE $INSTANCE/var/cache
# MY_PRODUCT_ENVVAR foobar
# </environment>
<environment>
CHAMELEON_CACHE $INSTANCE/var/cache
</environment>


# Directive: debug-mode
Expand Down
2 changes: 2 additions & 0 deletions src/Zope2/utilities/skel/var/cache/README.txt
@@ -0,0 +1,2 @@
This directory typically contains cache files, such as Page Template
cache files generated by Chameleon.

0 comments on commit 2b5d615

Please sign in to comment.