Commit 1671c7cb authored by Hanno Schlichting's avatar Hanno Schlichting

Make repoze.tm2 optional when using the WSGIPublisher, refs #64.

parent 8d5c5603
......@@ -54,6 +54,8 @@ Bugs Fixed
Features Added
++++++++++++++
- Make repoze.tm2 optional when using the WSGIPublisher.
- Include waitress as a default WSGI app server.
- Add `egg:Zope2#httpexceptions` WSGI middleware.
......
......@@ -34,7 +34,6 @@ persistent==4.2.1
python-gettext==3.0
pytz==2016.6.1
repoze.retry==1.4
repoze.tm2==1.0
six==1.10.0
tempstorage==3.0
transaction==1.6.1
......
......@@ -71,7 +71,6 @@ setup(
'docutils',
'five.globalrequest',
'pytz',
'repoze.tm2',
'repoze.retry',
'setuptools',
'tempstorage',
......
......@@ -126,9 +126,7 @@ class WSGIResponse(HTTPResponse):
raise NotImplementedError
def publish(request, module_name,
_get_module_info=get_module_info, # only for testing
):
def publish(request, module_info, repoze_tm_active=False):
(bobo_before,
bobo_after,
object,
......@@ -136,8 +134,7 @@ def publish(request, module_name,
debug_mode,
err_hook,
validated_hook,
transactions_manager,
) = _get_module_info(module_name)
transactions_manager) = module_info
notify(pubevents.PubStart(request))
newInteraction()
......@@ -162,6 +159,10 @@ def publish(request, module_name,
path = request.get('PATH_INFO')
request['PARENTS'] = [object]
if not repoze_tm_active and transactions_manager:
transactions_manager.begin()
object = request.traverse(path, validated_hook=validated_hook)
notify(pubevents.PubAfterTraversal(request))
......@@ -183,6 +184,11 @@ def publish(request, module_name,
response.setBody(result)
notify(pubevents.PubBeforeCommit(request))
if not repoze_tm_active and transactions_manager:
transactions_manager.commit()
notify(pubevents.PubSuccess(request))
finally:
endInteraction()
......@@ -222,7 +228,10 @@ def publish_module(environ, start_response,
_publish=publish, # only for testing
_response_factory=WSGIResponse, # only for testing
_request_factory=HTTPRequest, # only for testing
):
):
module_info = get_module_info('Zope2')
transactions_manager = module_info[7]
status = 200
stdout = StringIO()
stderr = StringIO()
......@@ -232,7 +241,9 @@ def publish_module(environ, start_response,
request = _request_factory(environ['wsgi.input'], environ, response)
if 'repoze.tm.active' in environ:
repoze_tm_active = 'repoze.tm.active' in environ
if repoze_tm_active:
# NOTE: registerSynch is a no-op after the first request
transaction.manager.registerSynch(_request_closer_for_repoze_tm)
txn = transaction.get()
......@@ -242,14 +253,16 @@ def publish_module(environ, start_response,
try:
try:
response = _publish(request, 'Zope2')
response = _publish(request, module_info, repoze_tm_active)
except Exception:
try:
exc_info = sys.exc_info()
notify(pubevents.PubBeforeAbort(
request, exc_info, request.supports_retry()))
# This should really be after transaction abort
if not repoze_tm_active and transactions_manager:
transactions_manager.abort()
notify(pubevents.PubFailure(
request, exc_info, request.supports_retry()))
finally:
......@@ -274,7 +287,7 @@ def publish_module(environ, start_response,
# XXX This still needs verification that it really works.
result = (stdout.getvalue(), response.body)
if 'repoze.tm.active' not in environ:
if not repoze_tm_active:
request.close() # this aborts the transaction!
stdout.close()
......
......@@ -12,6 +12,9 @@
##############################################################################
import unittest
from ZPublisher.Publish import get_module_info
class WSGIResponseTests(unittest.TestCase):
_old_NOW = None
......@@ -140,18 +143,12 @@ class WSGIResponseTests(unittest.TestCase):
class TestPublish(unittest.TestCase):
def _callFUT(self, request, module_name, _get_module_info=None):
def _callFUT(self, request, module_info=None):
from ZPublisher.WSGIPublisher import publish
if _get_module_info is None:
return publish(request, module_name)
if module_info is None:
module_info = get_module_info('Zope2')
return publish(request, module_name, _get_module_info)
def test_invalid_module_doesnt_catch_error(self):
_gmi = DummyCallable()
_gmi._raise = ImportError('testing')
self.assertRaises(ImportError, self._callFUT, None, 'nonesuch', _gmi)
self.assertEqual(_gmi._called_with, (('nonesuch',), {}))
return publish(request, module_info)
def test_wo_REMOTE_USER(self):
request = DummyRequest(PATH_INFO='/')
......@@ -166,12 +163,10 @@ class TestPublish(unittest.TestCase):
_err_hook = DummyCallable()
_validated_hook = object()
_tm = DummyTM()
_gmi = DummyCallable()
_gmi._result = (_before, _after, _object, _realm, _debug_mode,
_err_hook, _validated_hook, _tm)
returned = self._callFUT(request, 'okmodule', _gmi)
module_info = (_before, _after, _object, _realm, _debug_mode,
_err_hook, _validated_hook, _tm)
returned = self._callFUT(request, module_info)
self.assertTrue(returned is response)
self.assertEqual(_gmi._called_with, (('okmodule',), {}))
self.assertTrue(request._processedInputs)
self.assertEqual(response.after_list, (_after,))
self.assertTrue(response.debug_mode)
......@@ -180,6 +175,8 @@ class TestPublish(unittest.TestCase):
self.assertEqual(request['PARENTS'], [_object])
self.assertEqual(request._traversed, ('/', None, _validated_hook))
self.assertEqual(_tm._recorded, (_object, request))
self.assertTrue(_tm._begin)
self.assertTrue(_tm._commit)
self.assertEqual(_object._called_with, ((), {}))
self.assertEqual(response._body, 'RESULT')
self.assertEqual(_err_hook._called_with, None)
......@@ -197,10 +194,9 @@ class TestPublish(unittest.TestCase):
_err_hook = DummyCallable()
_validated_hook = object()
_tm = DummyTM()
_gmi = DummyCallable()
_gmi._result = (_before, _after, _object, _realm, _debug_mode,
_err_hook, _validated_hook, _tm)
self._callFUT(request, 'okmodule', _gmi)
module_info = (_before, _after, _object, _realm, _debug_mode,
_err_hook, _validated_hook, _tm)
self._callFUT(request, module_info)
self.assertEqual(response.realm, None)
......@@ -208,7 +204,6 @@ class TestPublishModule(unittest.TestCase):
def setUp(self):
from zope.testing.cleanup import cleanUp
cleanUp()
def tearDown(self):
......@@ -302,9 +297,9 @@ class TestPublishModule(unittest.TestCase):
self.assertEqual(status, '204 No Content')
self.assertEqual(headers, [('Content-Length', '0')])
self.assertEqual(kw, {})
(request, module), kw = _publish._called_with
(request, module_info, repoze_tm_active), kw = _publish._called_with
self.assertTrue(isinstance(request, HTTPRequest))
self.assertEqual(module, 'Zope2')
self.assertEqual(repoze_tm_active, False)
self.assertEqual(kw, {})
self.assertTrue(_response._finalized)
self.assertEqual(_after1._called_with, ((), {}))
......@@ -514,6 +509,16 @@ class DummyCallable(object):
class DummyTM(object):
_recorded = _raise = _result = None
_abort = _begin = _commit = False
def abort(self):
self._abort = True
def begin(self):
self._begin = True
def commit(self):
self._commit = True
def recordMetaData(self, *args):
self._recorded = args
......
......@@ -6,7 +6,6 @@ zope_conf = %(here)s/wsgi.conf
pipeline =
egg:Zope2#httpexceptions
egg:repoze.retry#retry
egg:repoze.tm2#tm
zope
[server:main]
......
......@@ -30,7 +30,6 @@ python-gettext = 3.0
pytz = 2016.6.1
Record = 3.1
repoze.retry = 1.4
repoze.tm2 = 1.0
RestrictedPython = 3.6.0
six = 1.10.0
tempstorage = 3.0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment