From 9f3fbea48aa604df503b4920fdb81262be548521 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Fri, 22 Jan 2016 10:21:27 -0800 Subject: [PATCH] Add excutils.save_and_reraise_exception force_reraise + capture Change-Id: Ie0972ca5634547ce3a71f7755905d3081008a2f8 --- oslo_utils/excutils.py | 22 ++++++++++++++++++--- oslo_utils/tests/test_excutils.py | 33 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/oslo_utils/excutils.py b/oslo_utils/excutils.py index dbaf0f6..0d1517b 100644 --- a/oslo_utils/excutils.py +++ b/oslo_utils/excutils.py @@ -178,10 +178,26 @@ class save_and_reraise_exception(object): if logger is None: logger = logging.getLogger() self.logger = logger + self.type_, self.value, self.tb = (None, None, None) + + def force_reraise(self): + if self.type_ is None and self.value is None: + raise RuntimeError("There is no (currently) captured exception" + " to force the reraising of") + six.reraise(self.type_, self.value, self.tb) + + def capture(self, check=True): + (type_, value, tb) = sys.exc_info() + if check and type_ is None and value is None: + raise RuntimeError("There is no active exception to capture") + self.type_, self.value, self.tb = (type_, value, tb) + return self def __enter__(self): - self.type_, self.value, self.tb, = sys.exc_info() - return self + # TODO(harlowja): perhaps someday in the future turn check here + # to true, because that is likely the desired intention, and doing + # so ensures that people are actually using this correctly. + return self.capture(check=False) def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is not None: @@ -192,7 +208,7 @@ class save_and_reraise_exception(object): self.tb)) return False if self.reraise: - six.reraise(self.type_, self.value, self.tb) + self.force_reraise() def forever_retry_uncaught_exceptions(infunc): diff --git a/oslo_utils/tests/test_excutils.py b/oslo_utils/tests/test_excutils.py index 60f752d..197bdb6 100644 --- a/oslo_utils/tests/test_excutils.py +++ b/oslo_utils/tests/test_excutils.py @@ -62,6 +62,39 @@ class CausedByTest(test_base.BaseTestCase): class SaveAndReraiseTest(test_base.BaseTestCase): + def test_save_and_reraise_exception_forced(self): + + def _force_reraise(): + try: + raise IOError("I broke") + except Exception: + with excutils.save_and_reraise_exception() as e: + e.reraise = False + e.force_reraise() + + self.assertRaises(IOError, _force_reraise) + + def test_save_and_reraise_exception_capture_reraise(self): + + def _force_reraise(): + try: + raise IOError("I broke") + except Exception: + excutils.save_and_reraise_exception().capture().force_reraise() + + self.assertRaises(IOError, _force_reraise) + + def test_save_and_reraise_exception_capture_not_active(self): + e = excutils.save_and_reraise_exception() + self.assertRaises(RuntimeError, e.capture, check=True) + + def test_save_and_reraise_exception_forced_not_active(self): + e = excutils.save_and_reraise_exception() + self.assertRaises(RuntimeError, e.force_reraise) + e = excutils.save_and_reraise_exception() + e.capture(check=False) + self.assertRaises(RuntimeError, e.force_reraise) + def test_save_and_reraise_exception(self): e = None msg = 'foo'