diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2024-05-06 12:53:15 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-06 12:53:15 (GMT) |
commit | 0085c3ae8f067abd4f6540d0f6dd2fb13107618e (patch) | |
tree | 02a0986dbc669ca6e6c53bf9fb567cfb25e95130 | |
parent | d6fa1d4beef2bf9d83048469667e0ba5f2b41068 (diff) | |
download | cpython-0085c3ae8f067abd4f6540d0f6dd2fb13107618e.zip cpython-0085c3ae8f067abd4f6540d0f6dd2fb13107618e.tar.gz cpython-0085c3ae8f067abd4f6540d0f6dd2fb13107618e.tar.bz2 |
gh-116871: Improve name suggestions in tracebacks (GH-116930)
Only include underscored names in name suggestions for AttributeError and
ImportError if the original name was underscored.
-rw-r--r-- | Lib/test/test_traceback.py | 32 | ||||
-rw-r--r-- | Lib/traceback.py | 11 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2024-03-17-18-24-23.gh-issue-116871.9uSl8M.rst | 2 |
3 files changed, 45 insertions, 0 deletions
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7e48510..5987ec3 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -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" diff --git a/Lib/traceback.py b/Lib/traceback.py index 1878779..9401b46 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -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 index 0000000..f3caa63 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-03-17-18-24-23.gh-issue-116871.9uSl8M.rst @@ -0,0 +1,2 @@ +Name suggestions for :exc:`AttributeError` and :exc:`ImportError` now only +include underscored names if the original name was underscored. |