mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
[3.13] gh-132308: prevent TracebackException
swallowing attributes of a falsey Exception
or ExceptionGroup
(GH-132363) (#132725)
gh-132308: prevent `TracebackException` swallowing attributes of a falsey `Exception` or `ExceptionGroup` (GH-132363)
(cherry picked from commit 69cda31261
)
Co-authored-by: Duprat <yduprat@gmail.com>
This commit is contained in:
parent
7998f998b2
commit
dfaa384991
3 changed files with 57 additions and 3 deletions
|
@ -3408,6 +3408,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:
|
||||
|
@ -3753,6 +3766,24 @@ class TestTracebackException(unittest.TestCase):
|
|||
'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):
|
||||
|
@ -3954,6 +3985,26 @@ class TestTracebackException_ExceptionGroups(unittest.TestCase):
|
|||
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
|
||||
|
||||
|
|
|
@ -1116,7 +1116,7 @@ class TracebackException:
|
|||
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__),
|
||||
|
@ -1137,7 +1137,7 @@ class TracebackException:
|
|||
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__),
|
||||
|
@ -1152,7 +1152,7 @@ class TracebackException:
|
|||
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(
|
||||
|
|
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue