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