diff --git a/taskflow/exceptions.py b/taskflow/exceptions.py index 5d15355a..15a73b3b 100644 --- a/taskflow/exceptions.py +++ b/taskflow/exceptions.py @@ -98,7 +98,9 @@ class TaskFlowException(Exception): buf.write(self._get_message()) active_indent = indent next_up = self.cause - while next_up is not None: + seen = [] + while next_up is not None and next_up not in seen: + seen.append(next_up) buf.write(os.linesep) if isinstance(next_up, TaskFlowException): buf.write(indent_text * active_indent) diff --git a/taskflow/tests/unit/test_exceptions.py b/taskflow/tests/unit/test_exceptions.py index b3590653..c542ae83 100644 --- a/taskflow/tests/unit/test_exceptions.py +++ b/taskflow/tests/unit/test_exceptions.py @@ -14,6 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. +import string + import six import testtools @@ -56,6 +58,19 @@ class TestExceptions(test.TestCase): self.assertIsNotNone(capture.cause) self.assertIsInstance(capture.cause, IOError) + def test_no_looping(self): + causes = [] + for a in string.ascii_lowercase: + try: + cause = causes[-1] + except IndexError: + cause = None + causes.append(exc.TaskFlowException('%s broken' % a, cause=cause)) + e = causes[0] + last_e = causes[-1] + e._cause = last_e + self.assertIsNotNone(e.pformat()) + def test_pformat_str(self): ex = None try: