Skip to content

Commit 944c632

Browse files
committed
Add helpful default error messages to AttributeError and NameError
1 parent fca7fec commit 944c632

4 files changed

Lines changed: 62 additions & 2 deletions

File tree

Lib/test/test_exceptions.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,25 @@ class TestClass:
20032003

20042004
self.assertRaises(NameError, f)
20052005

2006+
def test_gh_143811(self):
2007+
def f():
2008+
span = 42
2009+
try:
2010+
spam
2011+
except NameError as exc:
2012+
# Clear the message.
2013+
exc.args = ()
2014+
raise
2015+
2016+
try:
2017+
f()
2018+
except NameError:
2019+
with support.captured_stderr() as err:
2020+
sys.__excepthook__(*sys.exc_info())
2021+
2022+
# 'spam' should appear even when message was empty.
2023+
self.assertIn("'spam'", err.getvalue())
2024+
20062025
# Note: name suggestion tests live in `test_traceback`.
20072026

20082027

@@ -2046,6 +2065,24 @@ def blech(self):
20462065
self.assertEqual("bluch", exc.name)
20472066
self.assertEqual(obj, exc.obj)
20482067

2068+
def test_gh_143811(self):
2069+
def f():
2070+
class A:
2071+
def __getattr__(self, attr):
2072+
# Provide no message.
2073+
raise AttributeError
2074+
2075+
A.bluch
2076+
2077+
try:
2078+
f()
2079+
except AttributeError:
2080+
with support.captured_stderr() as err:
2081+
sys.__excepthook__(*sys.exc_info())
2082+
2083+
# 'bluch' should appear even when message was empty.
2084+
self.assertIn("'bluch'", err.getvalue())
2085+
20492086
# Note: name suggestion tests live in `test_traceback`.
20502087

20512088

Lib/test/test_traceback.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4259,6 +4259,7 @@ def __getattr__(self, attr):
42594259
raise AttributeError()
42604260

42614261
actual = self.get_suggestion(A(), 'bluch')
4262+
self.assertIn("'A' object has no attribute 'bluch'.", actual)
42624263
self.assertIn("blech", actual)
42634264

42644265
class A:
@@ -4267,6 +4268,7 @@ def __getattr__(self, attr):
42674268
raise AttributeError
42684269

42694270
actual = self.get_suggestion(A(), 'bluch')
4271+
self.assertIn("'A' object has no attribute 'bluch'.", actual)
42704272
self.assertIn("blech", actual)
42714273

42724274
def test_suggestions_invalid_args(self):
@@ -4930,6 +4932,18 @@ def func():
49304932
actual = self.get_suggestion(func)
49314933
self.assertIn("forget to import '_io'", actual)
49324934

4935+
def test_name_error_empty(self):
4936+
"""See GH-143811."""
4937+
def func():
4938+
span = 42
4939+
try:
4940+
spam
4941+
except NameError as exc:
4942+
exc.args = ()
4943+
raise
4944+
actual = self.get_suggestion(func)
4945+
self.assertIn("'spam'", actual)
4946+
self.assertIn("'span'?", actual)
49334947

49344948

49354949
class PurePythonSuggestionFormattingTests(

Lib/traceback.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,9 +1125,15 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
11251125
+ "add the site-packages directory to sys.path "
11261126
+ "or to enable your virtual environment?")
11271127
elif exc_type and issubclass(exc_type, (NameError, AttributeError)) and \
1128-
getattr(exc_value, "name", None) is not None:
1129-
wrong_name = getattr(exc_value, "name", None)
1128+
(wrong_name := getattr(exc_value, "name", None)) is not None:
11301129
suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name)
1130+
if not self._str:
1131+
if issubclass(exc_type, AttributeError):
1132+
if (obj_type := type(getattr(exc_value, "obj", None))) is not type(None):
1133+
obj_type_name = object.__getattribute__(obj_type, "__name__")
1134+
self._str = f"{obj_type_name!r} object has no attribute {wrong_name!r}"
1135+
else: # NameError
1136+
self._str = repr(wrong_name)
11311137
if suggestion:
11321138
self._str += f". Did you mean: '{suggestion}'?"
11331139
if issubclass(exc_type, NameError):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:exc:`AttributeError` and :exc:`NameError` exceptions raised with no message
2+
now get helpful default messages when displaying traceback. Patch by Bartosz
3+
Sławecki.

0 commit comments

Comments
 (0)