diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 2145710ffc7..17413db7f9e 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -253,6 +253,26 @@ def outer_raise(): self.check_zero_div(blocks[0]) self.assertTrue('inner_raise() # Marker' in blocks[2]) + def test_cause_and_context(self): + # When both a cause and a context are set, only the cause should be + # displayed and the context should be muted. + def inner_raise(): + try: + self.zero_div() + except ZeroDivisionError as _e: + e = _e + try: + xyzzy + except NameError: + raise KeyError from e + def outer_raise(): + inner_raise() # Marker + blocks = boundaries.split(self.get_report(outer_raise)) + self.assertEquals(len(blocks), 3) + self.assertEquals(blocks[1], cause_message) + self.check_zero_div(blocks[0]) + self.assert_('inner_raise() # Marker' in blocks[2]) + def test_cause_recursive(self): def inner_raise(): try: diff --git a/Lib/traceback.py b/Lib/traceback.py index c0d8061ecd3..8d4e96edcb6 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -120,13 +120,14 @@ def _iter_chain(exc, custom_tb=None, seen=None): seen.add(exc) its = [] cause = exc.__cause__ - context = exc.__context__ if cause is not None and cause not in seen: its.append(_iter_chain(cause, None, seen)) its.append([(_cause_message, None)]) - if context is not None and context is not cause and context not in seen: - its.append(_iter_chain(context, None, seen)) - its.append([(_context_message, None)]) + else: + context = exc.__context__ + if context is not None and context not in seen: + its.append(_iter_chain(context, None, seen)) + its.append([(_context_message, None)]) its.append([(exc, custom_tb or exc.__traceback__)]) # itertools.chain is in an extension module and may be unavailable for it in its: diff --git a/Misc/NEWS b/Misc/NEWS index 0fd7655dc1a..375004fc7d7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,10 @@ Core and Builtins Library ------- +- Issue #4486: When an exception has an explicit cause, do not print its + implicit context too. This affects the `traceback` module as well as + built-in exception printing. + - Issue #1488943: difflib.Differ() doesn't always add hints for tab characters - Issue #7354: distutils.tests.test_msvc9compiler - dragfullwindows can diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 875e44e99b1..3764740e81c 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1576,7 +1576,7 @@ print_exception_recursive(PyObject *f, PyObject *value, PyObject *seen) cause_message, f); } } - if (context) { + else if (context) { res = PySet_Contains(seen, context); if (res == -1) PyErr_Clear();