https://github.com/python/cpython/commit/69cda31261dd98b0462dc5ca63bdbcd0954dfa77
commit: 69cda31261dd98b0462dc5ca63bdbcd0954dfa77
branch: main
author: Duprat <[email protected]>
committer: picnixz <[email protected]>
date: 2025-04-19T09:49:18Z
summary:
gh-132308: prevent `TracebackException` swallowing attributes of a falsey
`Exception` or `ExceptionGroup` (#132363)
files:
A Misc/NEWS.d/next/Library/2025-04-10-13-06-42.gh-issue-132308.1js5SI.rst
M Lib/test/test_traceback.py
M Lib/traceback.py
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index 5c390fd056b3e3..a806dbf1582268 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -3413,6 +3413,19 @@ class Unrepresentable:
def __repr__(self) -> str:
raise Exception("Unrepresentable")
+
+# Used in test_dont_swallow_cause_or_context_of_falsey_exception and
+# test_dont_swallow_subexceptions_of_falsey_exceptiongroup.
+class FalseyException(Exception):
+ def __bool__(self):
+ return False
+
+
+class FalseyExceptionGroup(ExceptionGroup):
+ def __bool__(self):
+ return False
+
+
class TestTracebackException(unittest.TestCase):
def do_test_smoke(self, exc, expected_type_str):
try:
@@ -3759,6 +3772,24 @@ def f():
'ZeroDivisionError: division by zero',
''])
+ def test_dont_swallow_cause_or_context_of_falsey_exception(self):
+ # see gh-132308: Ensure that __cause__ or __context__ attributes of
exceptions
+ # that evaluate as falsey are included in the output. For falsey term,
+ # see
https://docs.python.org/3/library/stdtypes.html#truth-value-testing.
+
+ try:
+ raise FalseyException from KeyError
+ except FalseyException as e:
+ self.assertIn(cause_message, traceback.format_exception(e))
+
+ try:
+ try:
+ 1/0
+ except ZeroDivisionError:
+ raise FalseyException
+ except FalseyException as e:
+ self.assertIn(context_message, traceback.format_exception(e))
+
class TestTracebackException_ExceptionGroups(unittest.TestCase):
def setUp(self):
@@ -3960,6 +3991,26 @@ def test_comparison(self):
self.assertNotEqual(exc, object())
self.assertEqual(exc, ALWAYS_EQ)
+ def test_dont_swallow_subexceptions_of_falsey_exceptiongroup(self):
+ # see gh-132308: Ensure that subexceptions of exception groups
+ # that evaluate as falsey are displayed in the output. For falsey term,
+ # see
https://docs.python.org/3/library/stdtypes.html#truth-value-testing.
+
+ try:
+ raise FalseyExceptionGroup("Gih", (KeyError(), NameError()))
+ except Exception as ee:
+ str_exc = ''.join(traceback.format_exception(ee))
+ self.assertIn('+---------------- 1 ----------------', str_exc)
+ self.assertIn('+---------------- 2 ----------------', str_exc)
+
+ # Test with a falsey exception, in last position, as sub-exceptions.
+ msg = 'bool'
+ try:
+ raise FalseyExceptionGroup("Gah", (KeyError(),
FalseyException(msg)))
+ except Exception as ee:
+ str_exc = traceback.format_exception(ee)
+ self.assertIn(f'{FalseyException.__name__}: {msg}', str_exc[-2])
+
global_for_suggestions = None
diff --git a/Lib/traceback.py b/Lib/traceback.py
index 647c23ed782c41..78c35136ea9e8c 100644
--- a/Lib/traceback.py
+++ b/Lib/traceback.py
@@ -1120,7 +1120,7 @@ def __init__(self, exc_type, exc_value, exc_traceback, *,
limit=None,
queue = [(self, exc_value)]
while queue:
te, e = queue.pop()
- if (e and e.__cause__ is not None
+ if (e is not None and e.__cause__ is not None
and id(e.__cause__) not in _seen):
cause = TracebackException(
type(e.__cause__),
@@ -1141,7 +1141,7 @@ def __init__(self, exc_type, exc_value, exc_traceback, *,
limit=None,
not e.__suppress_context__)
else:
need_context = True
- if (e and e.__context__ is not None
+ if (e is not None and e.__context__ is not None
and need_context and id(e.__context__) not in _seen):
context = TracebackException(
type(e.__context__),
@@ -1156,7 +1156,7 @@ def __init__(self, exc_type, exc_value, exc_traceback, *,
limit=None,
else:
context = None
- if e and isinstance(e, BaseExceptionGroup):
+ if e is not None and isinstance(e, BaseExceptionGroup):
exceptions = []
for exc in e.exceptions:
texc = TracebackException(
diff --git
a/Misc/NEWS.d/next/Library/2025-04-10-13-06-42.gh-issue-132308.1js5SI.rst
b/Misc/NEWS.d/next/Library/2025-04-10-13-06-42.gh-issue-132308.1js5SI.rst
new file mode 100644
index 00000000000000..8e8b99c2be31ec
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-10-13-06-42.gh-issue-132308.1js5SI.rst
@@ -0,0 +1,3 @@
+A :class:`traceback.TracebackException` now correctly renders the
``__context__``
+and ``__cause__`` attributes from :ref:`falsey <truth>` :class:`Exception`,
+and the ``exceptions`` attribute from falsey :class:`ExceptionGroup`.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]