Merge "Trap and expose exception any 'args'"

This commit is contained in:
Jenkins 2016-01-06 19:31:47 +00:00 committed by Gerrit Code Review
commit a0207ecd41
2 changed files with 37 additions and 3 deletions

View File

@ -181,6 +181,14 @@ class FailureObjectTestCase(test.TestCase):
d_f['exc_type_names'] = ['RuntimeError', 'Exception', 'BaseException'] d_f['exc_type_names'] = ['RuntimeError', 'Exception', 'BaseException']
failure.Failure.validate(d_f) failure.Failure.validate(d_f)
def test_cause_exception_args(self):
f = _captured_failure('Woot!')
d_f = f.to_dict()
self.assertEqual(1, len(d_f['exc_args']))
self.assertEqual(("Woot!",), d_f['exc_args'])
f2 = failure.Failure.from_dict(d_f)
self.assertEqual(f.exception_args, f2.exception_args)
def test_dont_catch_base_exception(self): def test_dont_catch_base_exception(self):
try: try:
raise SystemExit() raise SystemExit()
@ -236,7 +244,8 @@ class FailureObjectTestCase(test.TestCase):
captured = _captured_failure('Woot!') captured = _captured_failure('Woot!')
fail_obj = failure.Failure(exception_str=captured.exception_str, fail_obj = failure.Failure(exception_str=captured.exception_str,
traceback_str=captured.traceback_str, traceback_str=captured.traceback_str,
exc_type_names=list(captured)) exc_type_names=list(captured),
exc_args=list(captured.exception_args))
self.assertFalse(fail_obj == captured) self.assertFalse(fail_obj == captured)
self.assertTrue(fail_obj != captured) self.assertTrue(fail_obj != captured)
self.assertTrue(fail_obj.matches(captured)) self.assertTrue(fail_obj.matches(captured))

View File

@ -141,6 +141,10 @@ class Failure(mixins.StrMixin):
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
}, },
'exc_args': {
"type": "array",
"minItems": 0,
},
'exception_str': { 'exception_str': {
"type": "string", "type": "string",
}, },
@ -183,6 +187,7 @@ class Failure(mixins.StrMixin):
raise ValueError("Provided 'exc_info' must contain three" raise ValueError("Provided 'exc_info' must contain three"
" elements") " elements")
self._exc_info = exc_info self._exc_info = exc_info
self._exc_args = tuple(getattr(exc_info[1], 'args', []))
self._exc_type_names = tuple( self._exc_type_names = tuple(
reflection.get_all_class_names(exc_info[0], up_to=Exception)) reflection.get_all_class_names(exc_info[0], up_to=Exception))
if not self._exc_type_names: if not self._exc_type_names:
@ -195,6 +200,7 @@ class Failure(mixins.StrMixin):
else: else:
self._causes = kwargs.pop('causes', None) self._causes = kwargs.pop('causes', None)
self._exc_info = exc_info self._exc_info = exc_info
self._exc_args = tuple(kwargs.pop('exc_args', []))
self._exception_str = kwargs.pop('exception_str') self._exception_str = kwargs.pop('exception_str')
self._exc_type_names = tuple(kwargs.pop('exc_type_names', [])) self._exc_type_names = tuple(kwargs.pop('exc_type_names', []))
self._traceback_str = kwargs.pop('traceback_str', None) self._traceback_str = kwargs.pop('traceback_str', None)
@ -243,6 +249,7 @@ class Failure(mixins.StrMixin):
if self is other: if self is other:
return True return True
return (self._exc_type_names == other._exc_type_names return (self._exc_type_names == other._exc_type_names
and self.exception_args == other.exception_args
and self.exception_str == other.exception_str and self.exception_str == other.exception_str
and self.traceback_str == other.traceback_str and self.traceback_str == other.traceback_str
and self.causes == other.causes) and self.causes == other.causes)
@ -278,7 +285,7 @@ class Failure(mixins.StrMixin):
@property @property
def exception(self): def exception(self):
"""Exception value, or None if exception value is not present. """Exception value, or none if exception value is not present.
Exception value may be lost during serialization. Exception value may be lost during serialization.
""" """
@ -292,9 +299,19 @@ class Failure(mixins.StrMixin):
"""String representation of exception.""" """String representation of exception."""
return self._exception_str return self._exception_str
@property
def exception_args(self):
"""Tuple of arguments given to the exception constructor."""
return self._exc_args
@property @property
def exc_info(self): def exc_info(self):
"""Exception info tuple or None.""" """Exception info tuple or none.
See: https://docs.python.org/2/library/sys.html#sys.exc_info for what
the contents of this tuple are (if none, then no contents can
be examined).
"""
return self._exc_info return self._exc_info
@property @property
@ -444,6 +461,12 @@ class Failure(mixins.StrMixin):
def __setstate__(self, dct): def __setstate__(self, dct):
self._exception_str = dct['exception_str'] self._exception_str = dct['exception_str']
if 'exc_args' in dct:
self._exc_args = tuple(dct['exc_args'])
else:
# Guess we got an older version somehow, before this
# was added, so at that point just set to an empty tuple...
self._exc_args = ()
self._traceback_str = dct['traceback_str'] self._traceback_str = dct['traceback_str']
self._exc_type_names = dct['exc_type_names'] self._exc_type_names = dct['exc_type_names']
if 'exc_info' in dct: if 'exc_info' in dct:
@ -483,6 +506,7 @@ class Failure(mixins.StrMixin):
'traceback_str': self.traceback_str, 'traceback_str': self.traceback_str,
'exc_type_names': list(self), 'exc_type_names': list(self),
'version': self.DICT_VERSION, 'version': self.DICT_VERSION,
'exc_args': self.exception_args,
'causes': [f.to_dict() for f in self.causes], 'causes': [f.to_dict() for f in self.causes],
} }
@ -491,5 +515,6 @@ class Failure(mixins.StrMixin):
return Failure(exc_info=_copy_exc_info(self.exc_info), return Failure(exc_info=_copy_exc_info(self.exc_info),
exception_str=self.exception_str, exception_str=self.exception_str,
traceback_str=self.traceback_str, traceback_str=self.traceback_str,
exc_args=self.exception_args,
exc_type_names=self._exc_type_names[:], exc_type_names=self._exc_type_names[:],
causes=self._causes) causes=self._causes)