Skip to content

Commit c760303

Browse files
committed
fixup! Return the suggestion as a object and handle it in print_exception
1 parent a3dd16a commit c760303

File tree

8 files changed

+23
-31
lines changed

8 files changed

+23
-31
lines changed

Doc/library/exceptions.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ The following exceptions are the exceptions that are usually raised.
154154
that was attempted to be accessed and the object that was accessed for said
155155
attribute, respectively.
156156

157+
.. versionchanged:: 3.10
158+
Added the :attr:`name` and :attr:`obj` attributes.
157159

158160
.. exception:: EOFError
159161

Include/internal/pycore_pyerrors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ PyAPI_FUNC(int) _PyErr_CheckSignalsTstate(PyThreadState *tstate);
8686

8787
PyAPI_FUNC(void) _Py_DumpExtensionModules(int fd, PyInterpreterState *interp);
8888

89+
extern PyObject* _Py_Offer_Suggestions(PyObject* exception);
90+
8991
#ifdef __cplusplus
9092
}
9193
#endif

Include/internal/pycore_suggestions.h

Lines changed: 0 additions & 12 deletions
This file was deleted.

Makefile.pre.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,6 @@ PYTHON_HEADERS= \
11621162
$(srcdir)/Include/internal/pycore_list.h \
11631163
$(srcdir)/Include/internal/pycore_long.h \
11641164
$(srcdir)/Include/internal/pycore_object.h \
1165-
$(srcdir)/Include/internal/pycore_suggestions.h \
11661165
$(srcdir)/Include/internal/pycore_pathconfig.h \
11671166
$(srcdir)/Include/internal/pycore_pyarena.h \
11681167
$(srcdir)/Include/internal/pycore_pyerrors.h \

Objects/object.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "pycore_pystate.h" // _PyThreadState_GET()
1313
#include "pycore_symtable.h" // PySTEntry_Type
1414
#include "pycore_unionobject.h" // _Py_UnionType
15-
#include "pycore_suggestions.h"
1615
#include "frameobject.h"
1716
#include "interpreteridobject.h"
1817

@@ -911,14 +910,14 @@ PyObject *
911910
PyObject_GetAttr(PyObject *v, PyObject *name)
912911
{
913912
PyTypeObject *tp = Py_TYPE(v);
914-
PyObject* result = NULL;
915-
916913
if (!PyUnicode_Check(name)) {
917914
PyErr_Format(PyExc_TypeError,
918915
"attribute name must be string, not '%.200s'",
919916
Py_TYPE(name)->tp_name);
920917
return NULL;
921918
}
919+
920+
PyObject* result = NULL;
922921
if (tp->tp_getattro != NULL) {
923922
result = (*tp->tp_getattro)(v, name);
924923
}

PCbuild/pythoncore.vcxproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@
215215
<ClInclude Include="..\Include\internal\pycore_ucnhash.h" />
216216
<ClInclude Include="..\Include\internal\pycore_unionobject.h" />
217217
<ClInclude Include="..\Include\internal\pycore_warnings.h" />
218-
<ClInclude Include="..\Include\internal\pycore_suggestions.h" />
219218
<ClInclude Include="..\Include\interpreteridobject.h" />
220219
<ClInclude Include="..\Include\intrcheck.h" />
221220
<ClInclude Include="..\Include\iterobject.h" />

Python/pythonrun.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "pycore_interp.h" // PyInterpreterState.importlib
1616
#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
1717
#include "pycore_parser.h" // _PyParser_ASTFromString()
18-
#include "pycore_pyerrors.h" // _PyErr_Fetch
18+
#include "pycore_pyerrors.h" // _PyErr_Fetch, _Py_Offer_Suggestions
1919
#include "pycore_pylifecycle.h" // _Py_UnhandledKeyboardInterrupt
2020
#include "pycore_pystate.h" // _PyInterpreterState_GET()
2121
#include "pycore_sysmodule.h" // _PySys_Audit()
@@ -24,7 +24,6 @@
2424
#include "errcode.h" // E_EOF
2525
#include "code.h" // PyCodeObject
2626
#include "marshal.h" // PyMarshal_ReadLongFromFile()
27-
#include "pycore_suggestions.h" // _Py_Offer_Suggestions
2827

2928
#ifdef MS_WINDOWS
3029
# include "malloc.h" // alloca()
@@ -956,9 +955,11 @@ print_exception(PyObject *f, PyObject *value)
956955
}
957956
PyObject* suggestions = _Py_Offer_Suggestions(value);
958957
if (suggestions) {
959-
err = PyFile_WriteString(". ", f);
958+
// Add a trailer ". Did you mean: (...)?"
959+
err = PyFile_WriteString(". Did you mean: ", f);
960960
if (err == 0) {
961961
err = PyFile_WriteObject(suggestions, f, Py_PRINT_RAW);
962+
err += PyFile_WriteString("?", f);
962963
}
963964
Py_DECREF(suggestions);
964965
}
@@ -1089,7 +1090,6 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
10891090
if (file == Py_None) {
10901091
return;
10911092
}
1092-
10931093
Py_INCREF(file);
10941094
_PyErr_Display(file, exception, value, tb);
10951095
Py_DECREF(file);

Python/suggestions.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#include "Python.h"
22

3-
#include "pycore_suggestions.h"
3+
#include "pycore_pyerrors.h"
44

55
#define MAX_GETATTR_PREDICT_DIST 3
66
#define MAX_GETATTR_PREDICT_ITEMS 100
77
#define MAX_GETATTR_STRING_SIZE 20
88

99
/* Calculate the Levenshtein distance between string1 and string2 */
1010
static Py_ssize_t
11-
distance(const char *string1, const char *string2)
11+
levenshtein_distance(const char *string1, const char *string2)
1212
{
1313
Py_ssize_t len1 = strlen(string1);
1414
Py_ssize_t len2 = strlen(string2);
@@ -150,8 +150,8 @@ calculate_suggestions(PyObject* dir,
150150
PyErr_Clear();
151151
continue;
152152
}
153-
Py_ssize_t current_distance = distance(PyUnicode_AsUTF8(name),
154-
PyUnicode_AsUTF8(item));
153+
Py_ssize_t current_distance = levenshtein_distance(PyUnicode_AsUTF8(name),
154+
PyUnicode_AsUTF8(item));
155155
if (current_distance > MAX_GETATTR_PREDICT_DIST){
156156
continue;
157157
}
@@ -163,7 +163,8 @@ calculate_suggestions(PyObject* dir,
163163
if (!suggestion) {
164164
return NULL;
165165
}
166-
return PyUnicode_FromFormat("Did you mean: %U?", suggestion);
166+
Py_INCREF(suggestion);
167+
return suggestion;
167168
}
168169

169170
static PyObject*
@@ -187,13 +188,15 @@ offer_suggestions_for_attribute_error(PyAttributeErrorObject* exc) {
187188
}
188189

189190

190-
// Offer suggestions for a given exception. This function does not raise exceptions
191-
// and returns NULL if no exception was found.
191+
// Offer suggestions for a given exception. Returns a python string object containing the
192+
// suggestions. This function does not raise exceptions and returns NULL if no suggestion was found.
192193
PyObject* _Py_Offer_Suggestions(PyObject* exception) {
193-
assert(!PyErr_Occurred());
194+
PyObject* result = NULL;
195+
assert(!PyErr_Occurred()); // Check that we are not going to clean any existing exception
194196
if (PyErr_GivenExceptionMatches(exception, PyExc_AttributeError)) {
195-
return offer_suggestions_for_attribute_error((PyAttributeErrorObject*) exception);
197+
result = offer_suggestions_for_attribute_error((PyAttributeErrorObject*) exception);
196198
}
197-
return NULL;
199+
assert(!PyErr_Occurred());
200+
return result;
198201
}
199202

0 commit comments

Comments
 (0)