Permalink
Browse files

- When a non-retryable exception was raised as the result of a call to

  ``transaction.manager.commit``, the exception was not reraised properly.
  Symptom: an unrecoverable exception such as ``Unsupported: Storing blobs in
  <somestorage> is not supported.`` would be swallowed inappropriately.

- ignore all env* dirs.
  • Loading branch information...
1 parent 454ca26 commit defb13d2953dea35b0065d785245e0304960f617 @mcdonc mcdonc committed Jun 26, 2012
Showing with 58 additions and 10 deletions.
  1. +1 −2 .gitignore
  2. +8 −0 CHANGES.txt
  3. +12 −7 pyramid_tm/__init__.py
  4. +30 −0 pyramid_tm/compat.py
  5. +7 −1 pyramid_tm/tests.py
View
@@ -11,5 +11,4 @@ dist/
.tox/
nosetests.xml
pyramid_tm/coverage.xml
-env26/
-env32/
+env*/
View
@@ -1,3 +1,11 @@
+Next release
+------------
+
+- When a non-retryable exception was raised as the result of a call to
+ ``transaction.manager.commit``, the exception was not reraised properly.
+ Symptom: an unrecoverable exception such as ``Unsupported: Storing blobs in
+ <somestorage> is not supported.`` would be swallowed inappropriately.
+
0.4 (2012-03-28)
----------------
View
@@ -5,6 +5,7 @@
from pyramid.util import DottedNameResolver
from pyramid.tweens import EXCVIEW
+from pyramid_tm.compat import reraise
resolver = DottedNameResolver(None)
@@ -51,23 +52,27 @@ class Attempt(object):
def __init__(self, manager):
self.manager = manager
+ def _retry_or_raise(self, t, v, tb):
+ retry = self.manager._retryable(t, v)
+ self.manager.abort()
+ if retry:
+ return retry # suppress the exception if necessary
+ reraise(t, v, tb) # otherwise reraise the exception
+
def __enter__(self):
return self.manager.__enter__()
def __exit__(self, t, v, tb):
+
if v is None:
try:
self.manager.commit()
except:
# this is what transaction 1.2.0 doesn't do (it doesn't
- # catch exceptions raised by a commit)
- retry = self.manager._retryable(*sys.exc_info()[:2])
- self.manager.abort()
- return retry
+ # suppress retryable exceptions raised by a commit)
+ return self._retry_or_raise(*sys.exc_info())
else:
- retry = self.manager._retryable(t, v)
- self.manager.abort()
- return retry
+ return self._retry_or_raise(t, v, tb)
def tm_tween_factory(handler, registry, transaction=transaction):
# transaction parameterized for testing purposes
View
@@ -0,0 +1,30 @@
+import sys
+
+PY3 = sys.version_info[0] == 3
+
+if PY3: # pragma: no cover
+ import builtins
+ exec_ = getattr(builtins, "exec")
+
+
+ def reraise(tp, value, tb=None):
+ if value.__traceback__ is not tb:
+ raise value.with_traceback(tb)
+ raise value
+
+else: # pragma: no cover
+ def exec_(code, globs=None, locs=None):
+ """Execute code in a namespace."""
+ if globs is None:
+ frame = sys._getframe(1)
+ globs = frame.f_globals
+ if locs is None:
+ locs = frame.f_locals
+ del frame
+ elif locs is None:
+ locs = globs
+ exec("""exec code in globs, locs""")
+
+ exec_("""def reraise(tp, value, tb=None):
+ raise tp, value, tb
+""")
View
@@ -231,12 +231,18 @@ def test_exit_v_is_None_commit_does_not_raise(self):
self.assertTrue(manager.committed)
self.assertEqual(result, None)
- def test_exit_v_is_None_commit_raises(self):
+ def test_exit_v_is_None_commit_raises_retryable(self):
manager = DummyManager(toraise=ValueError, retryable='abc')
inst = self._makeOne(manager)
result = inst.__exit__(None, None, None)
self.assertTrue(manager.aborted)
self.assertEqual(result, 'abc')
+
+ def test_exit_v_is_None_commit_raises_nonretryable(self):
+ manager = DummyManager(toraise=ValueError, retryable=False)
+ inst = self._makeOne(manager)
+ self.assertRaises(ValueError, inst.__exit__, None, None, None)
+ self.assertTrue(manager.aborted)
class DummyManager(object):
def __init__(self, toraise=None, retryable=False):

0 comments on commit defb13d

Please sign in to comment.