]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-116871: Improve name suggestions in tracebacks (GH-116930)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 6 May 2024 12:53:15 +0000 (15:53 +0300)
committerGitHub <noreply@github.com>
Mon, 6 May 2024 12:53:15 +0000 (15:53 +0300)
Only include underscored names in name suggestions for AttributeError and
ImportError if the original name was underscored.

Lib/test/test_traceback.py
Lib/traceback.py
Misc/NEWS.d/next/Library/2024-03-17-18-24-23.gh-issue-116871.9uSl8M.rst [new file with mode: 0644]

index 7e4851058e0109d914d94a9954639693c7ec70d8..5987ec382e6c8535dffbdd2315359538a9e23c58 100644 (file)
@@ -3882,6 +3882,27 @@ class SuggestionFormattingTestBase:
             actual = self.get_suggestion(cls(), 'bluch')
             self.assertIn(suggestion, actual)
 
+    def test_getattr_suggestions_underscored(self):
+        class A:
+            bluch = None
+
+        self.assertIn("'bluch'", self.get_suggestion(A(), 'blach'))
+        self.assertIn("'bluch'", self.get_suggestion(A(), '_luch'))
+        self.assertIn("'bluch'", self.get_suggestion(A(), '_bluch'))
+
+        class B:
+            _bluch = None
+            def method(self, name):
+                getattr(self, name)
+
+        self.assertIn("'_bluch'", self.get_suggestion(B(), '_blach'))
+        self.assertIn("'_bluch'", self.get_suggestion(B(), '_luch'))
+        self.assertNotIn("'_bluch'", self.get_suggestion(B(), 'bluch'))
+
+        self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, '_blach')))
+        self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, '_luch')))
+        self.assertIn("'_bluch'", self.get_suggestion(partial(B().method, 'bluch')))
+
     def test_getattr_suggestions_do_not_trigger_for_long_attributes(self):
         class A:
             blech = None
@@ -4074,6 +4095,17 @@ class SuggestionFormattingTestBase:
             actual = self.get_import_from_suggestion(code, 'bluch')
             self.assertIn(suggestion, actual)
 
+    def test_import_from_suggestions_underscored(self):
+        code = "bluch = None"
+        self.assertIn("'bluch'", self.get_import_from_suggestion(code, 'blach'))
+        self.assertIn("'bluch'", self.get_import_from_suggestion(code, '_luch'))
+        self.assertIn("'bluch'", self.get_import_from_suggestion(code, '_bluch'))
+
+        code = "_bluch = None"
+        self.assertIn("'_bluch'", self.get_import_from_suggestion(code, '_blach'))
+        self.assertIn("'_bluch'", self.get_import_from_suggestion(code, '_luch'))
+        self.assertNotIn("'_bluch'", self.get_import_from_suggestion(code, 'bluch'))
+
     def test_import_from_suggestions_do_not_trigger_for_long_attributes(self):
         code = "blech = None"
 
index 1878779e154d04859a1d0fb7dcefef99d0b4bfdd..9401b461497cc1e54da49fae8b9c95f9acafb5e9 100644 (file)
@@ -1469,12 +1469,23 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
         obj = exc_value.obj
         try:
             d = dir(obj)
+            hide_underscored = (wrong_name[:1] != '_')
+            if hide_underscored and tb is not None:
+                while tb.tb_next is not None:
+                    tb = tb.tb_next
+                frame = tb.tb_frame
+                if 'self' in frame.f_locals and frame.f_locals['self'] is obj:
+                    hide_underscored = False
+            if hide_underscored:
+                d = [x for x in d if x[:1] != '_']
         except Exception:
             return None
     elif isinstance(exc_value, ImportError):
         try:
             mod = __import__(exc_value.name)
             d = dir(mod)
+            if wrong_name[:1] != '_':
+                d = [x for x in d if x[:1] != '_']
         except Exception:
             return None
     else:
diff --git a/Misc/NEWS.d/next/Library/2024-03-17-18-24-23.gh-issue-116871.9uSl8M.rst b/Misc/NEWS.d/next/Library/2024-03-17-18-24-23.gh-issue-116871.9uSl8M.rst
new file mode 100644 (file)
index 0000000..f3caa63
--- /dev/null
@@ -0,0 +1,2 @@
+Name suggestions for :exc:`AttributeError` and :exc:`ImportError` now only
+include underscored names if the original name was underscored.