From 2028bd8a5cd3b6c58c274f256463a3fb417ae781 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 3 Feb 2025 19:16:20 +0530 Subject: [PATCH 01/15] Fix crashing pyrepl when NameError occurres in __getattr__ method --- Lib/test/test_traceback.py | 10 ++++++++++ Lib/traceback.py | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 89980ae6f8573a..08b299139ffaef 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4491,6 +4491,16 @@ def foo(self): actual = self.get_suggestion(instance.foo) self.assertNotIn("self.blech", actual) + def test_unbound_local_error_with_getattr(self): + class A: + def __getattr__(self, x): + print(x) + print(qq) + instance = A() + actual = self.get_suggestion(instance, "pop") + self.assertIn("NameError: name 'qq' is not defined", actual) + self.assertEqual(actual.count("NameError: name 'qq' is not defined"), 1) + def test_unbound_local_error_does_not_match(self): def func(): something = 3 diff --git a/Lib/traceback.py b/Lib/traceback.py index 31c73efcef5a52..182a931f1b5ece 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1520,8 +1520,9 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): # has the wrong name as attribute if 'self' in frame.f_locals: self = frame.f_locals['self'] - if hasattr(self, wrong_name): - return f"self.{wrong_name}" + if frame.f_code.co_name != '__getattr__': + if hasattr(self, wrong_name): + return f"self.{wrong_name}" try: import _suggestions From ed4fb8030a8ad67aeaa5f85576a7bc3c19ea4286 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 3 Feb 2025 19:56:20 +0530 Subject: [PATCH 02/15] Fix test failures --- Lib/test/test_traceback.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 08b299139ffaef..60440e99369777 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4498,8 +4498,8 @@ def __getattr__(self, x): print(qq) instance = A() actual = self.get_suggestion(instance, "pop") - self.assertIn("NameError: name 'qq' is not defined", actual) - self.assertEqual(actual.count("NameError: name 'qq' is not defined"), 1) + self.assertRegex(actual, r"NameError:.* name 'qq' is not defined") + self.assertEqual(actual.count("NameError"), 1) def test_unbound_local_error_does_not_match(self): def func(): From c416766b0858735f61a869c5e7598187e9ac4e4f Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 3 Feb 2025 20:00:19 +0530 Subject: [PATCH 03/15] Update the test name --- Lib/test/test_traceback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 60440e99369777..34062353216537 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4491,7 +4491,7 @@ def foo(self): actual = self.get_suggestion(instance.foo) self.assertNotIn("self.blech", actual) - def test_unbound_local_error_with_getattr(self): + def test_name_error_with_getattr(self): class A: def __getattr__(self, x): print(x) From d5b2a2f7653cc4f79e6236f5bd15f30fd45248d8 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 3 Feb 2025 20:09:29 +0530 Subject: [PATCH 04/15] Fix test failure --- Lib/test/test_traceback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 34062353216537..e8731b9bfb1e46 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4498,7 +4498,7 @@ def __getattr__(self, x): print(qq) instance = A() actual = self.get_suggestion(instance, "pop") - self.assertRegex(actual, r"NameError:.* name 'qq' is not defined") + self.assertRegex(actual, r"NameError.*:.* name 'qq' is not defined") self.assertEqual(actual.count("NameError"), 1) def test_unbound_local_error_does_not_match(self): From 63da1db8bc8c71b5d7f3a7ce27e200339e15e5c5 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 3 Feb 2025 20:20:35 +0530 Subject: [PATCH 05/15] Make the check simple --- Lib/test/test_traceback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index e8731b9bfb1e46..7974dcef491f8b 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4498,7 +4498,7 @@ def __getattr__(self, x): print(qq) instance = A() actual = self.get_suggestion(instance, "pop") - self.assertRegex(actual, r"NameError.*:.* name 'qq' is not defined") + self.assertIn("name 'qq' is not defined", actual) self.assertEqual(actual.count("NameError"), 1) def test_unbound_local_error_does_not_match(self): From e07c7455de539b33bad09f04be6ed0f044f26a32 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 16:39:36 +0000 Subject: [PATCH 06/15] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst new file mode 100644 index 00000000000000..a1d91a59058481 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -0,0 +1 @@ +Fix crashing pyrepl when `NameError` occurres in `__getattr__` method From 29090d264244ebdc2c07f00be72c3307122ee0a3 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 3 Feb 2025 22:14:18 +0530 Subject: [PATCH 07/15] Update NEWS.d description --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst index a1d91a59058481..a0bd9f9cbf2d10 100644 --- a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -1 +1 @@ -Fix crashing pyrepl when `NameError` occurres in `__getattr__` method +Fix pyrepl crash when a :func:`NameError` occurs in the :meth:`__getattr__` method From 418b1b99a8e5ea72132879e031a02a13876daef1 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 4 Feb 2025 11:49:03 +0530 Subject: [PATCH 08/15] Update patch --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst index a0bd9f9cbf2d10..4c3cd299ef0a7a 100644 --- a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -1 +1 @@ -Fix pyrepl crash when a :func:`NameError` occurs in the :meth:`__getattr__` method +Fix pyrepl crash when a :exc:`NameError` occurs in the `__getattr__` method. From dfa7a097b34cf537650188ee02f4ba0404c07ffd Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 4 Feb 2025 11:51:57 +0530 Subject: [PATCH 09/15] Fix Lint failure: --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst index 4c3cd299ef0a7a..652d01d8681379 100644 --- a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -1 +1 @@ -Fix pyrepl crash when a :exc:`NameError` occurs in the `__getattr__` method. +Fix pyrepl crash when a :exc:`NameError` occurs in the ``__getattr__`` method. From c969cca34910c44be5024a0e6bd70dfff483be43 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 4 Feb 2025 15:27:32 +0530 Subject: [PATCH 10/15] Address review comments --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst index 652d01d8681379..8b1f77141fd3b6 100644 --- a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -1 +1 @@ -Fix pyrepl crash when a :exc:`NameError` occurs in the ``__getattr__`` method. +Fix pyrepl crash when a :exc:`NameError` occurs in the :meth:`~object.__getattr__` method. From 05a985851955ea8c3508818d1e9f700d3248a7bf Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 5 Feb 2025 15:06:29 +0530 Subject: [PATCH 11/15] Handle __getattribute__ case as well --- Lib/test/test_traceback.py | 14 ++++++++++---- Lib/traceback.py | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7974dcef491f8b..42ecc413052cf3 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4496,10 +4496,16 @@ class A: def __getattr__(self, x): print(x) print(qq) - instance = A() - actual = self.get_suggestion(instance, "pop") - self.assertIn("name 'qq' is not defined", actual) - self.assertEqual(actual.count("NameError"), 1) + class B: + def __getattribute__(self, x): + print(x) + print(qq) + + for name, instance in (("a", A()), ("b", B())): + with self.subTest(name=name): + actual = self.get_suggestion(instance, "pop") + self.assertIn("name 'qq' is not defined", actual) + self.assertEqual(actual.count("NameError"), 1) def test_unbound_local_error_does_not_match(self): def func(): diff --git a/Lib/traceback.py b/Lib/traceback.py index 182a931f1b5ece..a45b4d8a4f5a42 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1520,7 +1520,7 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): # has the wrong name as attribute if 'self' in frame.f_locals: self = frame.f_locals['self'] - if frame.f_code.co_name != '__getattr__': + if frame.f_code.co_name not in ('__getattr__', '__getattribute__'): if hasattr(self, wrong_name): return f"self.{wrong_name}" From af9d076e8731514beda03ddb45e86b45a5cf6628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Srinivas=20Reddy=20Thatiparthy=20=28=E0=B0=A4=E0=B0=BE?= =?UTF-8?q?=E0=B0=9F=E0=B0=BF=E0=B0=AA=E0=B0=B0=E0=B1=8D=E0=B0=A4=E0=B0=BF?= =?UTF-8?q?=20=E0=B0=B6=E0=B1=8D=E0=B0=B0=E0=B1=80=E0=B0=A8=E0=B0=BF?= =?UTF-8?q?=E0=B0=B5=E0=B0=BE=E0=B0=B8=E0=B1=8D=20=20=E0=B0=B0=E0=B1=86?= =?UTF-8?q?=E0=B0=A1=E0=B1=8D=E0=B0=A1=E0=B0=BF=29?= Date: Wed, 5 Feb 2025 15:20:20 +0530 Subject: [PATCH 12/15] Update 2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst index 8b1f77141fd3b6..a3f41a8a629916 100644 --- a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -1 +1 @@ -Fix pyrepl crash when a :exc:`NameError` occurs in the :meth:`~object.__getattr__` method. +Fix pyrepl crash when a :exc:`NameError` occurs in the :meth:`~object.__getattr__`, and :meth:`~object.__getattribute__` method. From 842dc9353a2cd5220d9ba250141d556912cc07de Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 5 Feb 2025 16:11:03 +0530 Subject: [PATCH 13/15] Add another test for NameError for property function, and also wrap exception around hasattr block --- Lib/test/test_traceback.py | 10 ++++++++++ Lib/traceback.py | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 42ecc413052cf3..48650a1b4cad10 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4507,6 +4507,16 @@ def __getattribute__(self, x): self.assertIn("name 'qq' is not defined", actual) self.assertEqual(actual.count("NameError"), 1) + def test_name_error_with_property_name(self): + class A: + @property + def past(self): + past + instance = A() + actual = self.get_suggestion(instance, "past") + self.assertIn("name 'past' is not defined", actual) + self.assertEqual(actual.count("NameError"), 1) + def test_unbound_local_error_does_not_match(self): def func(): something = 3 diff --git a/Lib/traceback.py b/Lib/traceback.py index a45b4d8a4f5a42..3692f329921bc9 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1520,9 +1520,11 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): # has the wrong name as attribute if 'self' in frame.f_locals: self = frame.f_locals['self'] - if frame.f_code.co_name not in ('__getattr__', '__getattribute__'): + try: if hasattr(self, wrong_name): return f"self.{wrong_name}" + except Exception: + return None try: import _suggestions From f1cb1e3011fd48f8286011fceca84aad1e3fc2e9 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 5 Feb 2025 16:14:16 +0530 Subject: [PATCH 14/15] Update the description --- .../next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst index a3f41a8a629916..f049abb89a1374 100644 --- a/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst +++ b/Misc/NEWS.d/next/Library/2025-02-03-16-39-35.gh-issue-129605.sN_0uq.rst @@ -1 +1 @@ -Fix pyrepl crash when a :exc:`NameError` occurs in the :meth:`~object.__getattr__`, and :meth:`~object.__getattribute__` method. +Fix pyrepl crash when a :exc:`NameError` occurs in the :meth:`~object.__getattr__`, :meth:`~object.__getattribute__` and any method of a class. From 2f46caf03bab8ba08e20f445000922aa0f22a095 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Wed, 5 Feb 2025 16:40:00 +0530 Subject: [PATCH 15/15] Address review comments --- Lib/test/test_traceback.py | 4 ++-- Lib/traceback.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 48650a1b4cad10..cb91a4cdcbae7a 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4501,8 +4501,8 @@ def __getattribute__(self, x): print(x) print(qq) - for name, instance in (("a", A()), ("b", B())): - with self.subTest(name=name): + for instance in (A(), B()): + with self.subTest(instance=instance): actual = self.get_suggestion(instance, "pop") self.assertIn("name 'qq' is not defined", actual) self.assertEqual(actual.count("NameError"), 1) diff --git a/Lib/traceback.py b/Lib/traceback.py index 3692f329921bc9..283488f9bcecd9 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1523,7 +1523,7 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): try: if hasattr(self, wrong_name): return f"self.{wrong_name}" - except Exception: + except NameError: return None try: