mirror of
https://github.com/python/cpython
synced 2024-09-16 00:07:33 +00:00
gh-87822: Make traceback module robust to exceptions from repr() of local values (GH-94691)
This commit is contained in:
parent
da717519ec
commit
46fc584b00
|
@ -341,6 +341,10 @@ capture data for later printing in a lightweight fashion.
|
||||||
local variables in each :class:`FrameSummary` are captured as object
|
local variables in each :class:`FrameSummary` are captured as object
|
||||||
representations.
|
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)
|
.. classmethod:: from_list(a_list)
|
||||||
|
|
||||||
Construct a :class:`StackSummary` object from a supplied list of
|
Construct a :class:`StackSummary` object from a supplied list of
|
||||||
|
|
|
@ -2279,6 +2279,9 @@ def format_frame_summary(self, frame_summary):
|
||||||
f' File "{__file__}", line {lno}, in f\n 1/0\n'
|
f' File "{__file__}", line {lno}, in f\n 1/0\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class Unrepresentable:
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
raise Exception("Unrepresentable")
|
||||||
|
|
||||||
class TestTracebackException(unittest.TestCase):
|
class TestTracebackException(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -2546,12 +2549,13 @@ def test_locals(self):
|
||||||
linecache.updatecache('/foo.py', globals())
|
linecache.updatecache('/foo.py', globals())
|
||||||
e = Exception("uh oh")
|
e = Exception("uh oh")
|
||||||
c = test_code('/foo.py', 'method')
|
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)
|
tb = test_tb(f, 6, None, 0)
|
||||||
exc = traceback.TracebackException(
|
exc = traceback.TracebackException(
|
||||||
Exception, e, tb, capture_locals=True)
|
Exception, e, tb, capture_locals=True)
|
||||||
self.assertEqual(
|
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):
|
def test_no_locals(self):
|
||||||
linecache.updatecache('/foo.py', globals())
|
linecache.updatecache('/foo.py', globals())
|
||||||
|
|
|
@ -279,7 +279,8 @@ def __init__(self, filename, lineno, name, *, lookup_line=True,
|
||||||
self._line = line
|
self._line = line
|
||||||
if lookup_line:
|
if lookup_line:
|
||||||
self.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.end_lineno = end_lineno
|
||||||
self.colno = colno
|
self.colno = colno
|
||||||
self.end_colno = end_colno
|
self.end_colno = end_colno
|
||||||
|
|
|
@ -1590,6 +1590,7 @@ Ed Schouten
|
||||||
Scott Schram
|
Scott Schram
|
||||||
Robin Schreiber
|
Robin Schreiber
|
||||||
Chad J. Schroeder
|
Chad J. Schroeder
|
||||||
|
Simon-Martin Schroeder
|
||||||
Christian Schubert
|
Christian Schubert
|
||||||
Sam Schulenburg
|
Sam Schulenburg
|
||||||
Andreas Schwab
|
Andreas Schwab
|
||||||
|
|
|
@ -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).
|
Loading…
Reference in a new issue