aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2009-11-28 16:12:28 +0000
committerAntoine Pitrou <solipsis@pitrou.net>2009-11-28 16:12:28 +0000
commit7b0d4a238f2a69747ed570f8bfb51fb31315eba9 (patch)
tree0e1ea6c39a6ce48f33b1358992f26d3e5ce1081a
parent1fc0d2b364b144e501615cf82e998beb87733607 (diff)
downloadcpython-7b0d4a238f2a69747ed570f8bfb51fb31315eba9.tar.gz
cpython-7b0d4a238f2a69747ed570f8bfb51fb31315eba9.zip
Issue #4486: When an exception has an explicit cause, do not print its implicit context too.
-rw-r--r--Lib/test/test_traceback.py20
-rw-r--r--Lib/traceback.py9
-rw-r--r--Misc/NEWS4
-rw-r--r--Python/pythonrun.c2
4 files changed, 30 insertions, 5 deletions
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 @@ class BaseExceptionReportingTests:
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 3abf192ef9d..4efc4790745 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -140,6 +140,10 @@ C-API
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 #1515: Enable use of deepcopy() with instance methods. Patch by
Robert Collins.
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();