gh-87822: Make traceback module robust to exceptions from repr() of local values (GH-94691)

This commit is contained in:
Simon-Martin Schröder 2022-07-11 11:14:15 +02:00 committed by GitHub
parent da717519ec
commit 46fc584b00
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 14 additions and 3 deletions

View file

@ -341,6 +341,10 @@ capture data for later printing in a lightweight fashion.
local variables in each :class:`FrameSummary` are captured as object
representations.
.. versionchanged:: 3.12
Exceptions raised from :func:`repr` on a local variable (when
*capture_locals* is ``True``) are no longer propagated to the caller.
.. classmethod:: from_list(a_list)
Construct a :class:`StackSummary` object from a supplied list of

View file

@ -2279,6 +2279,9 @@ def format_frame_summary(self, frame_summary):
f' File "{__file__}", line {lno}, in f\n 1/0\n'
)
class Unrepresentable:
def __repr__(self) -> str:
raise Exception("Unrepresentable")
class TestTracebackException(unittest.TestCase):
@ -2546,12 +2549,13 @@ def test_locals(self):
linecache.updatecache('/foo.py', globals())
e = Exception("uh oh")
c = test_code('/foo.py', 'method')
f = test_frame(c, globals(), {'something': 1, 'other': 'string'})
f = test_frame(c, globals(), {'something': 1, 'other': 'string', 'unrepresentable': Unrepresentable()})
tb = test_tb(f, 6, None, 0)
exc = traceback.TracebackException(
Exception, e, tb, capture_locals=True)
self.assertEqual(
exc.stack[0].locals, {'something': '1', 'other': "'string'"})
exc.stack[0].locals,
{'something': '1', 'other': "'string'", 'unrepresentable': '<local repr() failed>'})
def test_no_locals(self):
linecache.updatecache('/foo.py', globals())

View file

@ -279,7 +279,8 @@ def __init__(self, filename, lineno, name, *, lookup_line=True,
self._line = line
if lookup_line:
self.line
self.locals = {k: repr(v) for k, v in locals.items()} if locals else None
self.locals = {k: _safe_string(v, 'local', func=repr)
for k, v in locals.items()} if locals else None
self.end_lineno = end_lineno
self.colno = colno
self.end_colno = end_colno

View file

@ -1590,6 +1590,7 @@ Ed Schouten
Scott Schram
Robin Schreiber
Chad J. Schroeder
Simon-Martin Schroeder
Christian Schubert
Sam Schulenburg
Andreas Schwab

View file

@ -0,0 +1 @@
When called with ``capture_locals=True``, the :mod:`traceback` module functions swallow exceptions raised from calls to ``repr()`` on local variables of frames. This is in order to prioritize the original exception over rendering errors. An indication of the failure is printed in place of the missing value. (Patch by Simon-Martin Schroeder).