Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Lib/test/test_scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,5 +835,29 @@ def g(self, __arg):
with self.assertRaises(TypeError):
closure(_MultiplyNested__arg=2)

def test_builtin_deletion_err_message(self):
with self.assertRaisesRegex(
NameError, "cannot delete builtin 'all'"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting makes this a bit difficult to read. This isn't coming near PEP 8's 79 character limit, so let's just keep all the arguments on the same line. This applies to all the assertRaisesRegex calls below.

):
del all

def f():
del all

with self.assertRaisesRegex(
UnboundLocalError, "cannot delete builtin 'all'"
):
f()

def g():
global all
del all

with self.assertRaisesRegex(
NameError, "cannot delete builtin 'all'"
):
g()


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deleting builtin names with ``del`` now gives a clearer error message.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Deleting builtin names with ``del`` now gives a clearer error message.
Deleting built-in names with :keyword:`del` now gives a clearer error message.

23 changes: 15 additions & 8 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1577,9 +1577,10 @@ dummy_func(
err = PyObject_DelItem(ns, name);
// Can't use ERROR_IF here.
if (err != 0) {
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
NAME_ERROR_MSG,
name);
const char *err_msg = PyMapping_HasKey(BUILTINS(), name)
? CANNOT_DELETE_BUILTIN_ERROR_MSG
: NAME_ERROR_MSG;
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError, err_msg, name);
ERROR_NO_POP();
}
}
Expand Down Expand Up @@ -1720,8 +1721,11 @@ dummy_func(
ERROR_NO_POP();
}
if (err == 0) {
const char *err_msg = PyMapping_HasKey(BUILTINS(), name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is safe to use PyDict_* here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no PyDict_* equivalent of PyMapping_HasKey, but we should be using PyMapping_HasKeyWithError here.

? CANNOT_DELETE_BUILTIN_ERROR_MSG
: NAME_ERROR_MSG;
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
err_msg, name);
ERROR_NO_POP();
}
}
Expand Down Expand Up @@ -1888,10 +1892,13 @@ dummy_func(
inst(DELETE_FAST, (--)) {
_PyStackRef v = GETLOCAL(oparg);
if (PyStackRef_IsNull(v)) {
_PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG,
PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg)
);
PyObject *name;
name = PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyTuple_GetItem can fail. We should be able to expect that it can't, so let's use PyTuple_GET_ITEM.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we leave this as is? This seems like an unrelated change.

oparg);
const char *err_msg = PyMapping_HasKey(BUILTINS(), name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto -- we should be using PyMapping_HasKeyWithError.

? CANNOT_DELETE_BUILTIN_ERROR_MSG
: UNBOUNDLOCAL_ERROR_MSG;
_PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, err_msg, name);
ERROR_IF(true);
}
_PyStackRef tmp = GETLOCAL(oparg);
Expand Down
1 change: 1 addition & 0 deletions Python/ceval_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
"cannot access free variable '%s' where it is not associated with a value" \
" in enclosing scope"
#define NAME_ERROR_MSG "name '%.200s' is not defined"
#define CANNOT_DELETE_BUILTIN_ERROR_MSG "cannot delete builtin '%.200s'"

// If a trace function sets a new f_lineno and
// *then* raises, we use the destination when searching
Expand Down
23 changes: 15 additions & 8 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 15 additions & 8 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading