From e93095c8da44f50e63ca0eba0c3f46979580f602 Mon Sep 17 00:00:00 2001 From: "Adam D. Thomas" Date: Tue, 4 Feb 2025 19:03:05 +1100 Subject: [PATCH 1/2] Add fix and tests --- Lib/test/test_traceback.py | 26 +++++++++++++++++++ Lib/traceback.py | 51 ++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index d5b00a3bb628cb1..678538eb2539c7b 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -5109,6 +5109,32 @@ def func(): actual = self.get_suggestion(func) self.assertIn("forget to import '_io'", actual) + def test_name_error_with_bad_getattr(self): + class A: + def __getattr__(self, x): + spam + + actual = self.get_suggestion(A(), "eggs") + self.assertIn("name 'spam' is not defined", actual) + + def test_name_error_with_bad_getattribute(self): + + class A: + def __getattribute__(self, x): + spam + + actual = self.get_suggestion(A(), "eggs") + self.assertIn("name 'spam' is not defined", actual) + + def test_name_error_with_bad_property(self): + class A: + @property + def eggs(self): + eggs + + actual = self.get_suggestion(A(), "eggs") + self.assertIn("name 'eggs' is not defined", actual) + class PurePythonSuggestionFormattingTests( diff --git a/Lib/traceback.py b/Lib/traceback.py index dcdab1f12e9a168..9c34624b90460af 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1954,31 +1954,34 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): return None else: assert isinstance(exc_value, NameError) - # find most recent frame - if tb is None: + try: + # find most recent frame + if tb is None: + return None + while tb.tb_next is not None: + tb = tb.tb_next + frame = tb.tb_frame + d = ( + list(frame.f_locals) + + list(frame.f_globals) + + list(frame.f_builtins) + ) + d = [x for x in d if isinstance(x, str)] + if not_normalized and wrong_name in d: + return wrong_name + + # Check first if we are in a method and the instance + # has the wrong name as attribute + if 'self' in frame.f_locals: + self = frame.f_locals['self'] + try: + has_wrong_name = hasattr(self, wrong_name) + except Exception: + has_wrong_name = False + if has_wrong_name: + return f"self.{wrong_name}" + except Exception: return None - while tb.tb_next is not None: - tb = tb.tb_next - frame = tb.tb_frame - d = ( - list(frame.f_locals) - + list(frame.f_globals) - + list(frame.f_builtins) - ) - d = [x for x in d if isinstance(x, str)] - if not_normalized and wrong_name in d: - return wrong_name - - # Check first if we are in a method and the instance - # has the wrong name as attribute - if 'self' in frame.f_locals: - self = frame.f_locals['self'] - try: - has_wrong_name = hasattr(self, wrong_name) - except Exception: - has_wrong_name = False - if has_wrong_name: - return f"self.{wrong_name}" if not_normalized and wrong_name in d: return wrong_name From 97771ba584af2e72d8a3f2b58b8e083087345c35 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 09:01:07 +0000 Subject: [PATCH 2/2] =?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/2025-02-04-09-01-06.gh-issue-129605.wKGNXQ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-02-04-09-01-06.gh-issue-129605.wKGNXQ.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-04-09-01-06.gh-issue-129605.wKGNXQ.rst b/Misc/NEWS.d/next/Library/2025-02-04-09-01-06.gh-issue-129605.wKGNXQ.rst new file mode 100644 index 000000000000000..9dcf05913870b92 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-04-09-01-06.gh-issue-129605.wKGNXQ.rst @@ -0,0 +1 @@ +Improve exception handling when computing suggestions in traceback.py. This fixes a bug that could cause PyREPL to exit unexpectedly.