Merge "Make an attempt at having taskflow exceptions print causes better"

This commit is contained in:
Jenkins
2015-03-31 21:56:03 +00:00
committed by Gerrit Code Review
2 changed files with 82 additions and 27 deletions

View File

@@ -18,6 +18,7 @@ import os
import sys
import traceback
from oslo_utils import reflection
import six
@@ -76,35 +77,51 @@ class TaskFlowException(Exception):
def cause(self):
return self._cause
def pformat(self, indent=2, indent_text=" "):
def __str__(self):
return self.pformat()
def _get_message(self):
# We must *not* call into the __str__ method as that will reactivate
# the pformat method, which will end up badly (and doesn't look
# pretty at all); so be careful...
return self.args[0]
def pformat(self, indent=2, indent_text=" ", show_root_class=False):
"""Pretty formats a taskflow exception + any connected causes."""
if indent < 0:
raise ValueError("indent must be greater than or equal to zero")
return os.linesep.join(self._pformat(self, [], 0,
indent=indent,
indent_text=indent_text))
@classmethod
def _pformat(cls, excp, lines, current_indent, indent=2, indent_text=" "):
line_prefix = indent_text * current_indent
for line in traceback.format_exception_only(type(excp), excp):
# We'll add our own newlines on at the end of formatting.
#
# NOTE(harlowja): the reason we don't search for os.linesep is
# that the traceback module seems to only use '\n' (for some
# reason).
if line.endswith("\n"):
line = line[0:-1]
lines.append(line_prefix + line)
try:
cause = excp.cause
except AttributeError:
pass
else:
if cause is not None:
cls._pformat(cause, lines, current_indent + indent,
indent=indent, indent_text=indent_text)
return lines
raise ValueError("Provided 'indent' must be greater than"
" or equal to zero instead of %s" % indent)
buf = six.StringIO()
if show_root_class:
buf.write(reflection.get_class_name(self, fully_qualified=False))
buf.write(": ")
buf.write(self._get_message())
active_indent = indent
next_up = self.cause
while next_up is not None:
buf.write(os.linesep)
if isinstance(next_up, TaskFlowException):
buf.write(indent_text * active_indent)
buf.write(reflection.get_class_name(next_up,
fully_qualified=False))
buf.write(": ")
buf.write(next_up._get_message())
else:
lines = traceback.format_exception_only(type(next_up), next_up)
for i, line in enumerate(lines):
buf.write(indent_text * active_indent)
if line.endswith("\n"):
# We'll add our own newlines on...
line = line[0:-1]
buf.write(line)
if i + 1 != len(lines):
buf.write(os.linesep)
active_indent += indent
try:
next_up = next_up.cause
except AttributeError:
next_up = None
return buf.getvalue()
# Errors related to storage or operations on storage units.

View File

@@ -56,6 +56,44 @@ class TestExceptions(test.TestCase):
self.assertIsNotNone(capture.cause)
self.assertIsInstance(capture.cause, IOError)
def test_pformat_str(self):
ex = None
try:
try:
try:
raise IOError("Didn't work")
except IOError:
exc.raise_with_cause(exc.TaskFlowException,
"It didn't go so well")
except exc.TaskFlowException:
exc.raise_with_cause(exc.TaskFlowException, "I Failed")
except exc.TaskFlowException as e:
ex = e
self.assertIsNotNone(ex)
self.assertIsInstance(ex, exc.TaskFlowException)
self.assertIsInstance(ex.cause, exc.TaskFlowException)
self.assertIsInstance(ex.cause.cause, IOError)
p_msg = ex.pformat()
p_str_msg = str(ex)
for msg in ["I Failed", "It didn't go so well", "Didn't work"]:
self.assertIn(msg, p_msg)
self.assertIn(msg, p_str_msg)
def test_pformat_root_class(self):
ex = exc.TaskFlowException("Broken")
self.assertIn("TaskFlowException",
ex.pformat(show_root_class=True))
self.assertNotIn("TaskFlowException",
ex.pformat(show_root_class=False))
self.assertIn("Broken",
ex.pformat(show_root_class=True))
def test_invalid_pformat_indent(self):
ex = exc.TaskFlowException("Broken")
self.assertRaises(ValueError, ex.pformat, indent=-100)
@testtools.skipIf(not six.PY3, 'py3.x is not available')
def test_raise_with_cause(self):
capture = None