summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Nemec <bnemec@us.ibm.com>2013-07-02 10:59:02 -0500
committerBen Nemec <bnemec@us.ibm.com>2013-07-02 10:59:02 -0500
commit323e465718174299f392e1fb12726593712a2d34 (patch)
tree5a42684642718bee1b78b9cdd5e3da8216f9a483
parent78649a52d90a63117f3213107b826cc561cef419 (diff)
downloadoslo-323e465718174299f392e1fb12726593712a2d34.zip
oslo-323e465718174299f392e1fb12726593712a2d34.tar.gz
oslo-323e465718174299f392e1fb12726593712a2d34.tar.xz
Add conditional exception reraise
In some cases we need to save an exception and reraise it only under certain conditions. As written, the save_and_reraise_exception context always reraises, which means it can't always be used. This change adds a flag that allows conditional reraising to address the limitation. Change-Id: Ib5c6406a1b91daff94cc4aa305dcb7d6262aecdc
-rw-r--r--openstack/common/excutils.py38
-rw-r--r--tests/unit/test_excutils.py8
2 files changed, 35 insertions, 11 deletions
diff --git a/openstack/common/excutils.py b/openstack/common/excutils.py
index d40d46c..336e147 100644
--- a/openstack/common/excutils.py
+++ b/openstack/common/excutils.py
@@ -19,7 +19,6 @@
Exception related utilities.
"""
-import contextlib
import logging
import sys
import time
@@ -28,8 +27,7 @@ import traceback
from openstack.common.gettextutils import _
-@contextlib.contextmanager
-def save_and_reraise_exception():
+class save_and_reraise_exception(object):
"""Save current exception, run some code and then re-raise.
In some cases the exception context can be cleared, resulting in None
@@ -41,15 +39,33 @@ def save_and_reraise_exception():
To work around this, we save the exception state, run handler code, and
then re-raise the original exception. If another exception occurs, the
saved exception is logged and the new exception is re-raised.
- """
- type_, value, tb = sys.exc_info()
- try:
- yield
+
+ In some cases the caller may not want to re-raise the exception, and
+ for those circumstances this context provides a reraise flag that
+ can be used to suppress the exception. For example:
+
except Exception:
- logging.error(_('Original exception being dropped: %s'),
- traceback.format_exception(type_, value, tb))
- raise
- raise type_, value, tb
+ with save_and_reraise_exception() as ctxt:
+ decide_if_need_reraise()
+ if not should_be_reraised:
+ ctxt.reraise = False
+ """
+ def __init__(self):
+ self.reraise = True
+
+ def __enter__(self):
+ self.type_, self.value, self.tb, = sys.exc_info()
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if exc_type is not None:
+ logging.error(_('Original exception being dropped: %s'),
+ traceback.format_exception(self.type_,
+ self.value,
+ self.tb))
+ return False
+ if self.reraise:
+ raise self.type_, self.value, self.tb
def forever_retry_uncaught_exceptions(infunc):
diff --git a/tests/unit/test_excutils.py b/tests/unit/test_excutils.py
index b8f9b96..1386eaa 100644
--- a/tests/unit/test_excutils.py
+++ b/tests/unit/test_excutils.py
@@ -52,6 +52,14 @@ class SaveAndReraiseTest(utils.BaseTestCase):
self.assertEqual(str(e), msg)
+ def test_save_and_reraise_exception_no_reraise(self):
+ """Test that suppressing the reraise works."""
+ try:
+ raise Exception('foo')
+ except Exception:
+ with excutils.save_and_reraise_exception() as ctxt:
+ ctxt.reraise = False
+
class ForeverRetryUncaughtExceptionsTest(utils.BaseTestCase):