From 1f40d5f8eabba7c23cf0fe1c958ddc0e6467edbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Thu, 21 Dec 2023 13:54:44 +0000 Subject: [PATCH 1/5] Fix rendering tracebacks with exceptions with a broken __getattr__ --- Lib/test/test_traceback.py | 12 ++++++++++++ Lib/traceback.py | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index a6708119b81191..f6480bb8d67338 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2209,6 +2209,18 @@ def __repr__(self): err_msg = "b'please do not show me as numbers'" self.assertEqual(self.get_report(e), vanilla + err_msg + '\n') + # an exception with a broken __getattr__ raising a non expected error + class BrokenException(Exception): + broken = False + def __getattr__(self, name): + if self.broken: + raise ValueError(f'no {name}') + + e = BrokenException(123) + vanilla = self.get_report(e) + e.broken = True + self.assertEqual(self.get_report(e), vanilla) + def test_exception_with_multiple_notes(self): for e in [ValueError(42), SyntaxError('bad syntax')]: with self.subTest(e=e): diff --git a/Lib/traceback.py b/Lib/traceback.py index 1cf008c7e9da97..7ef363c31d08a1 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1051,7 +1051,12 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, # Capture now to permit freeing resources: only complication is in the # unofficial API _format_final_exc_line self._str = _safe_string(exc_value, 'exception') - self.__notes__ = getattr(exc_value, '__notes__', None) + notes = None + try: + notes = getattr(exc_value, '__notes__', None) + except Exception: + pass + self.__notes__ = notes self._is_syntax_error = False self._have_exc_type = exc_type is not None From 9eed42e86b498a58cc2dd73c9a1ada3df1968a83 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:55:07 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2023-12-21-14-55-06.gh-issue-113358.nRkiSL.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-12-21-14-55-06.gh-issue-113358.nRkiSL.rst diff --git a/Misc/NEWS.d/next/Library/2023-12-21-14-55-06.gh-issue-113358.nRkiSL.rst b/Misc/NEWS.d/next/Library/2023-12-21-14-55-06.gh-issue-113358.nRkiSL.rst new file mode 100644 index 00000000000000..76416553a231a0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-21-14-55-06.gh-issue-113358.nRkiSL.rst @@ -0,0 +1 @@ +Fix rendering tracebacks with exceptions with a broken __getattr__ From 8651d3eb58b2f47d8688854cb3c2020cf46fd1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Mon, 15 Jan 2024 14:33:31 +0000 Subject: [PATCH 3/5] Display error accessing __notes__ along with the traceback --- Lib/test/test_traceback.py | 4 +++- Lib/traceback.py | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index f6480bb8d67338..9362965cd5149b 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2219,7 +2219,9 @@ def __getattr__(self, name): e = BrokenException(123) vanilla = self.get_report(e) e.broken = True - self.assertEqual(self.get_report(e), vanilla) + self.assertEqual( + self.get_report(e), + vanilla + "Ignored exception getting __notes__: ValueError('no __notes__')\n") def test_exception_with_multiple_notes(self): for e in [ValueError(42), SyntaxError('bad syntax')]: diff --git a/Lib/traceback.py b/Lib/traceback.py index 7ef363c31d08a1..f2b1563706d87e 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1053,10 +1053,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, self._str = _safe_string(exc_value, 'exception') notes = None try: - notes = getattr(exc_value, '__notes__', None) - except Exception: - pass - self.__notes__ = notes + self.__notes__ = getattr(exc_value, '__notes__', None) + except Exception as e: + self.__notes__ = [ + f'Ignored exception getting __notes__: {_safe_string(e, '__notes__', repr)}'] self._is_syntax_error = False self._have_exc_type = exc_type is not None From 6ecf82d84385e4b8289a3fde706aac724f49cb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Mon, 15 Jan 2024 15:15:51 +0000 Subject: [PATCH 4/5] fixup! Display error accessing __notes__ along with the traceback --- Lib/traceback.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/traceback.py b/Lib/traceback.py index f2b1563706d87e..0670b667e1d27e 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1051,7 +1051,6 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, # Capture now to permit freeing resources: only complication is in the # unofficial API _format_final_exc_line self._str = _safe_string(exc_value, 'exception') - notes = None try: self.__notes__ = getattr(exc_value, '__notes__', None) except Exception as e: From 6c6867a4cff331524a6b32218ca51ca7ed7240f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= Date: Tue, 16 Jan 2024 00:32:03 +0900 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> --- Lib/test/test_traceback.py | 2 +- Lib/traceback.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 9362965cd5149b..372fc48bf81a6a 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2221,7 +2221,7 @@ def __getattr__(self, name): e.broken = True self.assertEqual( self.get_report(e), - vanilla + "Ignored exception getting __notes__: ValueError('no __notes__')\n") + vanilla + "Ignored error getting __notes__: ValueError('no __notes__')\n") def test_exception_with_multiple_notes(self): for e in [ValueError(42), SyntaxError('bad syntax')]: diff --git a/Lib/traceback.py b/Lib/traceback.py index 0670b667e1d27e..ec686490277a01 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1055,7 +1055,7 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, self.__notes__ = getattr(exc_value, '__notes__', None) except Exception as e: self.__notes__ = [ - f'Ignored exception getting __notes__: {_safe_string(e, '__notes__', repr)}'] + f'Ignored error getting __notes__: {_safe_string(e, '__notes__', repr)}'] self._is_syntax_error = False self._have_exc_type = exc_type is not None