Skip to content

Commit

Permalink
bpo-38530: Make sure that failing to generate suggestions on failure …
Browse files Browse the repository at this point in the history
…will not propagate exceptions (GH-25408)
  • Loading branch information
pablogsal committed Apr 14, 2021
1 parent 0c4c436 commit e07f4ab
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 7 deletions.
14 changes: 14 additions & 0 deletions Lib/test/test_exceptions.py
Expand Up @@ -1695,6 +1695,20 @@ def __getattr__(self, attr):

self.assertIn("blech", err.getvalue())

def test_attribute_error_with_failing_dict(self):
class T:
bluch = 1
def __dir__(self):
raise AttributeError("oh no!")

try:
T().blich
except AttributeError as exc:
with support.captured_stderr() as err:
sys.__excepthook__(*sys.exc_info())

self.assertNotIn("blech", err.getvalue())
self.assertNotIn("oh no!", err.getvalue())

class ImportErrorTests(unittest.TestCase):

Expand Down
2 changes: 2 additions & 0 deletions Python/pythonrun.c
Expand Up @@ -962,6 +962,8 @@ print_exception(PyObject *f, PyObject *value)
err += PyFile_WriteString("?", f);
}
Py_DECREF(suggestions);
} else if (PyErr_Occurred()) {
PyErr_Clear();
}
err += PyFile_WriteString("\n", f);
Py_XDECREF(tb);
Expand Down
10 changes: 3 additions & 7 deletions Python/suggestions.c
Expand Up @@ -89,14 +89,12 @@ calculate_suggestions(PyObject *dir,
PyObject *suggestion = NULL;
const char *name_str = PyUnicode_AsUTF8(name);
if (name_str == NULL) {
PyErr_Clear();
return NULL;
}
for (int i = 0; i < dir_size; ++i) {
PyObject *item = PyList_GET_ITEM(dir, i);
const char *item_str = PyUnicode_AsUTF8(item);
if (item_str == NULL) {
PyErr_Clear();
return NULL;
}
Py_ssize_t current_distance = levenshtein_distance(name_str, item_str);
Expand Down Expand Up @@ -156,7 +154,6 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) {
assert(code != NULL && code->co_varnames != NULL);
PyObject *dir = PySequence_List(code->co_varnames);
if (dir == NULL) {
PyErr_Clear();
return NULL;
}

Expand All @@ -168,7 +165,6 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) {

dir = PySequence_List(frame->f_globals);
if (dir == NULL) {
PyErr_Clear();
return NULL;
}
suggestions = calculate_suggestions(dir, name);
Expand All @@ -178,16 +174,16 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) {
}

// Offer suggestions for a given exception. Returns a python string object containing the
// suggestions. This function does not raise exceptions and returns NULL if no suggestion was found.
// suggestions. This function returns NULL if no suggestion was found or if an exception happened,
// users must call PyErr_Occurred() to disambiguate.
PyObject *_Py_Offer_Suggestions(PyObject *exception) {
PyObject *result = NULL;
assert(!PyErr_Occurred()); // Check that we are not going to clean any existing exception
assert(!PyErr_Occurred());
if (PyErr_GivenExceptionMatches(exception, PyExc_AttributeError)) {
result = offer_suggestions_for_attribute_error((PyAttributeErrorObject *) exception);
} else if (PyErr_GivenExceptionMatches(exception, PyExc_NameError)) {
result = offer_suggestions_for_name_error((PyNameErrorObject *) exception);
}
assert(!PyErr_Occurred());
return result;
}

0 comments on commit e07f4ab

Please sign in to comment.