From 8e22de73285420ddf1ad38a11fc7529ed57adc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon-Martin=20Schr=C3=B6der?= Date: Fri, 8 Jul 2022 17:43:26 +0200 Subject: [PATCH 1/8] Make FrameSummary robust to unrepresentable values Fixes #87822. --- Doc/library/traceback.rst | 4 +++- Lib/test/test_traceback.py | 7 +++++-- Lib/traceback.py | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 796309c6cf0bb9..a34d56f93afde3 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -339,7 +339,9 @@ capture data for later printing in a lightweight fashion. creating the :class:`StackSummary` cheaper (which may be valuable if it may not actually get formatted). If *capture_locals* is ``True`` the local variables in each :class:`FrameSummary` are captured as object - representations. + representations. If, for some reason, a representation can not be + created (i.e. :func:`repr` fails), it is replaced with a placeholder + (``''``). .. classmethod:: from_list(a_list) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 722c265a6a8a51..68c01c2579326b 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2247,6 +2247,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): @@ -2514,12 +2517,12 @@ 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': ''}) def test_no_locals(self): linecache.updatecache('/foo.py', globals()) diff --git a/Lib/traceback.py b/Lib/traceback.py index 3afe49d1d8a0e6..1086686b2f06c9 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -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 From ab73490b288d28e280099f15b73c6c9c698829bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon-Martin=20Schr=C3=B6der?= Date: Fri, 8 Jul 2022 17:49:47 +0200 Subject: [PATCH 2/8] ACKS and NEWS --- Misc/ACKS | 1 + .../next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst diff --git a/Misc/ACKS b/Misc/ACKS index b6340414cf7012..32475f874c36db 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1590,6 +1590,7 @@ Ed Schouten Scott Schram Robin Schreiber Chad J. Schroeder +Simon-Martin Schroeder Christian Schubert Sam Schulenburg Andreas Schwab diff --git a/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst b/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst new file mode 100644 index 00000000000000..5327760e7d3ddc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst @@ -0,0 +1 @@ +Make FrameSummary robust to unrepresentable values. From 0e22c03beedabbc6e0ad554bf9f2af96e0c1fe83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon-Martin=20Schr=C3=B6der?= Date: Fri, 8 Jul 2022 21:40:29 +0200 Subject: [PATCH 3/8] Update Lib/test/test_traceback.py Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/test/test_traceback.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 68c01c2579326b..097e319d784cfc 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2522,7 +2522,8 @@ def test_locals(self): exc = traceback.TracebackException( Exception, e, tb, capture_locals=True) self.assertEqual( - exc.stack[0].locals, {'something': '1', 'other': "'string'", 'unrepresentable': ''}) + exc.stack[0].locals, + {'something': '1', 'other': "'string'", 'unrepresentable': ''}) def test_no_locals(self): linecache.updatecache('/foo.py', globals()) From 7c29129b6b623c8f3262cac0f8fcddbdb513fdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon-Martin=20Schr=C3=B6der?= Date: Sun, 10 Jul 2022 09:55:53 +0200 Subject: [PATCH 4/8] Update Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- .../next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst b/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst index 5327760e7d3ddc..7b27f5df45ba20 100644 --- a/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst +++ b/Misc/NEWS.d/next/Library/2022-07-08-17-49-12.gh-issue-87822.F9dzkf.rst @@ -1 +1 @@ -Make FrameSummary robust to unrepresentable values. +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). From 2a96b89f9379f3493990a3fd0d7b65fabf8ba2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon-Martin=20Schr=C3=B6der?= Date: Sun, 10 Jul 2022 09:59:56 +0200 Subject: [PATCH 5/8] Update traceback.rst: Convert to versionchanged --- Doc/library/traceback.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index a34d56f93afde3..7abb37eb968c47 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -339,9 +339,11 @@ capture data for later printing in a lightweight fashion. creating the :class:`StackSummary` cheaper (which may be valuable if it may not actually get formatted). If *capture_locals* is ``True`` the local variables in each :class:`FrameSummary` are captured as object - representations. If, for some reason, a representation can not be - created (i.e. :func:`repr` fails), it is replaced with a placeholder - (``''``). + representations. + + .. versionchanged:: 3.12 + Exceptions raised from :func:`repr` on a local variable are no longer + propagated to the caller and a placeholder is stored instead. .. classmethod:: from_list(a_list) From d758b6a53dccb8116409995e2289ab7a60a5eb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon-Martin=20Schr=C3=B6der?= Date: Sun, 10 Jul 2022 10:13:37 +0200 Subject: [PATCH 6/8] Whitespace --- Doc/library/traceback.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 7abb37eb968c47..9d266abb4530f6 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -340,7 +340,7 @@ capture data for later printing in a lightweight fashion. may not actually get formatted). If *capture_locals* is ``True`` the local variables in each :class:`FrameSummary` are captured as object representations. - + .. versionchanged:: 3.12 Exceptions raised from :func:`repr` on a local variable are no longer propagated to the caller and a placeholder is stored instead. From 636700a4ba55220c1cb44f23d4fc75da1bd2ccb7 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:18:45 +0100 Subject: [PATCH 7/8] tweak doc wording --- Doc/library/traceback.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 9d266abb4530f6..844e965e067442 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -343,7 +343,7 @@ capture data for later printing in a lightweight fashion. .. versionchanged:: 3.12 Exceptions raised from :func:`repr` on a local variable are no longer - propagated to the caller and a placeholder is stored instead. + propagated to the caller. .. classmethod:: from_list(a_list) From 3a4f5c3e3fd42ca3d110bbdd493d04f818fafd0b Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:20:51 +0100 Subject: [PATCH 8/8] Another tweak --- Doc/library/traceback.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 844e965e067442..4506631effae45 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -342,8 +342,8 @@ capture data for later printing in a lightweight fashion. representations. .. versionchanged:: 3.12 - Exceptions raised from :func:`repr` on a local variable are no longer - propagated to the caller. + 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)