Skip to content

Commit e3a009b

Browse files
NameError new attribute op
1 parent b85e10f commit e3a009b

File tree

9 files changed

+74
-31
lines changed

9 files changed

+74
-31
lines changed

Include/cpython/pyerrors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ typedef struct {
7575
typedef struct {
7676
PyException_HEAD
7777
PyObject *name;
78+
PyObject *op;
7879
} PyNameErrorObject;
7980

8081
typedef struct {

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject
293293
PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right);
294294
PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest);
295295
PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg);
296-
PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj);
297-
PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
296+
PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj, PyObject* op);
297+
PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg, int op_type);
298298
PyAPI_FUNC(void) _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwargs);
299299
PyAPI_FUNC(PyObject *) _PyEval_ImportFrom(PyThreadState *, PyObject *, PyObject *);
300300
PyAPI_FUNC(PyObject *) _PyEval_ImportName(PyThreadState *, _PyInterpreterFrame *, PyObject *, PyObject *, PyObject *);

Lib/test/test_traceback.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4648,6 +4648,19 @@ def func():
46484648
actual = self.get_suggestion(func)
46494649
self.assertIn("'ZeroDivisionError'?", actual)
46504650

4651+
def test_name_error_ignore_suggestions_from_builtins_in_deleting(self):
4652+
try:
4653+
exec("del next")
4654+
except NameError:
4655+
msg = traceback.format_exc()
4656+
self.assertNotIn("anext", msg)
4657+
4658+
def func():
4659+
del next
4660+
4661+
actual = self.get_suggestion(func)
4662+
self.assertNotIn("anext", actual)
4663+
46514664
def test_name_error_suggestions_with_non_string_candidates(self):
46524665
def func():
46534666
abc = 1

Lib/traceback.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,11 +1674,15 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
16741674
while tb.tb_next is not None:
16751675
tb = tb.tb_next
16761676
frame = tb.tb_frame
1677-
d = (
1678-
list(frame.f_locals)
1679-
+ list(frame.f_globals)
1680-
+ list(frame.f_builtins)
1681-
)
1677+
if getattr(exc_value, "op", "getting") == "deleting":
1678+
d = (list(frame.f_locals)
1679+
+ list(frame.f_globals))
1680+
else:
1681+
d = (
1682+
list(frame.f_locals)
1683+
+ list(frame.f_globals)
1684+
+ list(frame.f_builtins)
1685+
)
16821686
d = [x for x in d if isinstance(x, str)]
16831687

16841688
# Check first if we are in a method and the instance

Objects/exceptions.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,8 +2506,9 @@ PyNameErrorObject_CAST(PyObject *self)
25062506
static int
25072507
NameError_init(PyObject *op, PyObject *args, PyObject *kwds)
25082508
{
2509-
static char *kwlist[] = {"name", NULL};
2509+
static char *kwlist[] = {"name", "op", NULL};
25102510
PyObject *name = NULL;
2511+
PyObject* op_type = NULL;
25112512

25122513
if (BaseException_init(op, args, NULL) == -1) {
25132514
return -1;
@@ -2518,14 +2519,15 @@ NameError_init(PyObject *op, PyObject *args, PyObject *kwds)
25182519
return -1;
25192520
}
25202521
if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$O:NameError", kwlist,
2521-
&name)) {
2522+
&name ,&op_type)) {
25222523
Py_DECREF(empty_tuple);
25232524
return -1;
25242525
}
25252526
Py_DECREF(empty_tuple);
25262527

25272528
PyNameErrorObject *self = PyNameErrorObject_CAST(op);
25282529
Py_XSETREF(self->name, Py_XNewRef(name));
2530+
Py_XSETREF(self->op, Py_XNewRef(op_type));
25292531

25302532
return 0;
25312533
}
@@ -2535,6 +2537,7 @@ NameError_clear(PyObject *op)
25352537
{
25362538
PyNameErrorObject *self = PyNameErrorObject_CAST(op);
25372539
Py_CLEAR(self->name);
2540+
Py_CLEAR(self->op);
25382541
return BaseException_clear(op);
25392542
}
25402543

@@ -2551,11 +2554,14 @@ NameError_traverse(PyObject *op, visitproc visit, void *arg)
25512554
{
25522555
PyNameErrorObject *self = PyNameErrorObject_CAST(op);
25532556
Py_VISIT(self->name);
2557+
Py_VISIT(self->op);
25542558
return BaseException_traverse(op, visit, arg);
25552559
}
25562560

25572561
static PyMemberDef NameError_members[] = {
25582562
{"name", _Py_T_OBJECT, offsetof(PyNameErrorObject, name), 0, PyDoc_STR("name")},
2563+
{"op", _Py_T_OBJECT, offsetof(PyNameErrorObject, op), 0,
2564+
PyDoc_STR("operation that caused the NameError ('getting' or 'deleting')")},
25592565
{NULL} /* Sentinel */
25602566
};
25612567

Python/bytecodes.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,7 +1917,7 @@ dummy_func(
19171917
// Fortunately we don't need its superpower.
19181918
PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL);
19191919
if (oldobj == NULL) {
1920-
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
1920+
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg, 1);
19211921
ERROR_NO_POP();
19221922
}
19231923
Py_DECREF(oldobj);
@@ -1939,7 +1939,7 @@ dummy_func(
19391939
PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg));
19401940
value_o = PyCell_GetRef(cell);
19411941
if (value_o == NULL) {
1942-
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
1942+
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg, 0);
19431943
ERROR_NO_POP();
19441944
}
19451945
}
@@ -1951,7 +1951,7 @@ dummy_func(
19511951
PyCellObject *cell = (PyCellObject *)PyStackRef_AsPyObjectBorrow(GETLOCAL(oparg));
19521952
value = _PyCell_GetStackRef(cell);
19531953
if (PyStackRef_IsNull(value)) {
1954-
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
1954+
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg, 0);
19551955
ERROR_IF(true);
19561956
}
19571957
}

Python/ceval.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,7 +3320,7 @@ _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwarg
33203320

33213321
void
33223322
_PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc,
3323-
const char *format_str, PyObject *obj)
3323+
const char *format_str, PyObject *obj, PyObject *op)
33243324
{
33253325
const char *obj_str;
33263326

@@ -3342,25 +3342,35 @@ _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc,
33423342
// NameError anyway.
33433343
(void)PyObject_SetAttr(exc, &_Py_ID(name), obj);
33443344
}
3345+
if (((PyNameErrorObject*)exc)->op == NULL) {
3346+
(void)PyObject_SetAttrString(exc, "op", op);
3347+
}
33453348
}
33463349
PyErr_SetRaisedException(exc);
33473350
}
33483351
}
33493352

33503353
void
3351-
_PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg)
3354+
_PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg, int op_type)
33523355
{
33533356
PyObject *name;
3357+
PyObject* op;
3358+
if (op_type == 0) {
3359+
op = PyUnicode_FromString("getting");
3360+
}
3361+
else {
3362+
op = PyUnicode_FromString("deleting");
3363+
}
33543364
/* Don't stomp existing exception */
33553365
if (_PyErr_Occurred(tstate))
33563366
return;
33573367
name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg);
33583368
if (oparg < PyUnstable_Code_GetFirstFree(co)) {
33593369
_PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError,
3360-
UNBOUNDLOCAL_ERROR_MSG, name);
3370+
UNBOUNDLOCAL_ERROR_MSG, name, op);
33613371
} else {
33623372
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
3363-
UNBOUNDFREE_ERROR_MSG, name);
3373+
UNBOUNDFREE_ERROR_MSG, name, op);
33643374
}
33653375
}
33663376

@@ -3453,6 +3463,7 @@ _PyEval_GetANext(PyObject *aiter)
34533463
void
34543464
_PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name, _PyStackRef *writeto)
34553465
{
3466+
PyObject* op = PyUnicode_FromString("getting");
34563467
if (PyDict_CheckExact(globals) && PyDict_CheckExact(builtins)) {
34573468
_PyDict_LoadGlobalStackRef((PyDictObject *)globals,
34583469
(PyDictObject *)builtins,
@@ -3461,7 +3472,7 @@ _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name
34613472
/* _PyDict_LoadGlobal() returns NULL without raising
34623473
* an exception if the key doesn't exist */
34633474
_PyEval_FormatExcCheckArg(PyThreadState_GET(), PyExc_NameError,
3464-
NAME_ERROR_MSG, name);
3475+
NAME_ERROR_MSG, name, op);
34653476
}
34663477
}
34673478
else {
@@ -3481,7 +3492,7 @@ _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name
34813492
if (res == NULL) {
34823493
_PyEval_FormatExcCheckArg(
34833494
PyThreadState_GET(), PyExc_NameError,
3484-
NAME_ERROR_MSG, name);
3495+
NAME_ERROR_MSG, name, op);
34853496
*writeto = PyStackRef_NULL;
34863497
return;
34873498
}
@@ -3519,6 +3530,7 @@ _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *na
35193530
{
35203531

35213532
PyObject *value;
3533+
PyObject* op = PyUnicode_FromString("getting");
35223534
if (frame->f_locals == NULL) {
35233535
_PyErr_SetString(tstate, PyExc_SystemError,
35243536
"no locals found");
@@ -3542,7 +3554,7 @@ _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *na
35423554
if (value == NULL) {
35433555
_PyEval_FormatExcCheckArg(
35443556
tstate, PyExc_NameError,
3545-
NAME_ERROR_MSG, name);
3557+
NAME_ERROR_MSG, name, op);
35463558
}
35473559
return value;
35483560
}

Python/executor_cases.c.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 16 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)