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:
'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):
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
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__),
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__),
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(