diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 730596efd8bcec..45632910812a90 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -19,6 +19,10 @@ test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals']) test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next']) +class Unrepresentable: + def __repr__(self) -> str: + raise Exception("Unrepresentable") + class TracebackCases(unittest.TestCase): # For now, a very minimal set of tests. I want to be sure that @@ -995,9 +999,9 @@ def test_format_smoke(self): def test_locals(self): linecache.updatecache('/foo.py', globals()) c = test_code('/foo.py', 'method') - f = test_frame(c, globals(), {'something': 1}) + f = test_frame(c, globals(), {'something': 1, "unrepresentable": Unrepresentable()}) s = traceback.StackSummary.extract(iter([(f, 6)]), capture_locals=True) - self.assertEqual(s[0].locals, {'something': '1'}) + self.assertEqual(s[0].locals, {'something': '1', "unrepresentable": "[Unrepresentable: Unrepresentable]"}) def test_no_locals(self): linecache.updatecache('/foo.py', globals()) diff --git a/Lib/traceback.py b/Lib/traceback.py index a19e38718b1205..973e03fd114fb9 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -223,6 +223,11 @@ def clear_frames(tb): pass tb = tb.tb_next +def _try_repr(x): + try: + return repr(x) + except Exception as exc: + return "[Unrepresentable: {}]".format(exc) class FrameSummary: """A single frame from a traceback. @@ -257,7 +262,7 @@ 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: _try_repr(v) for k, v in locals.items()} if locals else None def __eq__(self, other): if isinstance(other, FrameSummary):