summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_exceptions.py14
-rw-r--r--Python/pythonrun.c2
-rw-r--r--Python/suggestions.c10
3 files changed, 19 insertions, 7 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 4f3c9ab..ebeb67b 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -1695,6 +1695,20 @@ class AttributeErrorTests(unittest.TestCase):
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):
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 321b04e..6f84cab 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -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);
diff --git a/Python/suggestions.c b/Python/suggestions.c
index 058294f..bdc8e2f 100644
--- a/Python/suggestions.c
+++ b/Python/suggestions.c
@@ -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);
@@ -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;
}
@@ -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);
@@ -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;
}