Skip to content

Commit 3ab4bea

Browse files
authored
bpo-38530: Include builtins in NameError suggestions (GH-25460)
1 parent 7f1305e commit 3ab4bea

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

Lib/test/test_exceptions.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,16 @@ def func():
14771477
sys.__excepthook__(*sys.exc_info())
14781478
self.assertIn("global_for_suggestions?", err.getvalue())
14791479

1480+
def test_name_error_suggestions_from_builtins(self):
1481+
def func():
1482+
print(AttributeErrop)
1483+
try:
1484+
func()
1485+
except NameError as exc:
1486+
with support.captured_stderr() as err:
1487+
sys.__excepthook__(*sys.exc_info())
1488+
self.assertIn("AttributeError?", err.getvalue())
1489+
14801490
def test_name_error_suggestions_do_not_trigger_for_long_names(self):
14811491
def f():
14821492
somethingverywronghehehehehehe = None
@@ -1490,7 +1500,7 @@ def f():
14901500

14911501
self.assertNotIn("somethingverywronghehe", err.getvalue())
14921502

1493-
def test_name_error_suggestions_do_not_trigger_for_big_dicts(self):
1503+
def test_name_error_suggestions_do_not_trigger_for_too_many_locals(self):
14941504
def f():
14951505
# Mutating locals() is unreliable, so we need to do it by hand
14961506
a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = a10 = a11 = a12 = a13 = \
@@ -1501,7 +1511,13 @@ def f():
15011511
a62 = a63 = a64 = a65 = a66 = a67 = a68 = a69 = a70 = a71 = a72 = a73 = \
15021512
a74 = a75 = a76 = a77 = a78 = a79 = a80 = a81 = a82 = a83 = a84 = a85 = \
15031513
a86 = a87 = a88 = a89 = a90 = a91 = a92 = a93 = a94 = a95 = a96 = a97 = \
1504-
a98 = a99 = a100 = a101 = a102 = a103 = None
1514+
a98 = a99 = a100 = a101 = a102 = a103 = a104 = a105 = a106 = a107 = \
1515+
a108 = a109 = a110 = a111 = a112 = a113 = a114 = a115 = a116 = a117 = \
1516+
a118 = a119 = a120 = a121 = a122 = a123 = a124 = a125 = a126 = \
1517+
a127 = a128 = a129 = a130 = a131 = a132 = a133 = a134 = a135 = a136 = \
1518+
a137 = a138 = a139 = a140 = a141 = a142 = a143 = a144 = a145 = \
1519+
a146 = a147 = a148 = a149 = a150 = a151 = a152 = a153 = a154 = a155 = \
1520+
a156 = a157 = a158 = a159 = a160 = a161 = None
15051521
print(a0)
15061522

15071523
try:
@@ -1510,7 +1526,7 @@ def f():
15101526
with support.captured_stderr() as err:
15111527
sys.__excepthook__(*sys.exc_info())
15121528

1513-
self.assertNotIn("a10", err.getvalue())
1529+
self.assertNotIn("a1", err.getvalue())
15141530

15151531
def test_name_error_with_custom_exceptions(self):
15161532
def f():
@@ -1643,7 +1659,7 @@ class A:
16431659
blech = None
16441660
# A class with a very big __dict__ will not be consider
16451661
# for suggestions.
1646-
for index in range(101):
1662+
for index in range(160):
16471663
setattr(A, f"index_{index}", None)
16481664

16491665
try:

Python/suggestions.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "pycore_pyerrors.h"
55

66
#define MAX_DISTANCE 3
7-
#define MAX_CANDIDATE_ITEMS 100
7+
#define MAX_CANDIDATE_ITEMS 160
88
#define MAX_STRING_SIZE 25
99

1010
/* Calculate the Levenshtein distance between string1 and string2 */
@@ -171,6 +171,16 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) {
171171
}
172172
suggestions = calculate_suggestions(dir, name);
173173
Py_DECREF(dir);
174+
if (suggestions != NULL) {
175+
return suggestions;
176+
}
177+
178+
dir = PySequence_List(frame->f_builtins);
179+
if (dir == NULL) {
180+
return NULL;
181+
}
182+
suggestions = calculate_suggestions(dir, name);
183+
Py_DECREF(dir);
174184

175185
return suggestions;
176186
}

0 commit comments

Comments
 (0)