Skip to content

Commit 1de2683

Browse files
committed
Add clearer message when deleting builtins with del
1 parent d873fb4 commit 1de2683

File tree

6 files changed

+71
-24
lines changed

6 files changed

+71
-24
lines changed

Lib/test/test_scope.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,5 +835,29 @@ def g(self, __arg):
835835
with self.assertRaises(TypeError):
836836
closure(_MultiplyNested__arg=2)
837837

838+
def test_builtin_deletion_err_message(self):
839+
with self.assertRaisesRegex(
840+
NameError, "cannot delete builtin 'all'"
841+
):
842+
del all
843+
844+
def f():
845+
del all
846+
847+
with self.assertRaisesRegex(
848+
UnboundLocalError, "cannot delete builtin 'all'"
849+
):
850+
f()
851+
852+
def g():
853+
global all
854+
del all
855+
856+
with self.assertRaisesRegex(
857+
NameError, "cannot delete builtin 'all'"
858+
):
859+
g()
860+
861+
838862
if __name__ == '__main__':
839863
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Deleting builtin names with ``del`` now gives a clearer error message.

Python/bytecodes.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,9 +1577,10 @@ dummy_func(
15771577
err = PyObject_DelItem(ns, name);
15781578
// Can't use ERROR_IF here.
15791579
if (err != 0) {
1580-
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
1581-
NAME_ERROR_MSG,
1582-
name);
1580+
const char *err_msg = PyMapping_HasKey(BUILTINS(), name)
1581+
? CANNOT_DELETE_BUILTIN_ERROR_MSG
1582+
: NAME_ERROR_MSG;
1583+
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError, err_msg, name);
15831584
ERROR_NO_POP();
15841585
}
15851586
}
@@ -1720,8 +1721,11 @@ dummy_func(
17201721
ERROR_NO_POP();
17211722
}
17221723
if (err == 0) {
1724+
const char *err_msg = PyMapping_HasKey(BUILTINS(), name)
1725+
? CANNOT_DELETE_BUILTIN_ERROR_MSG
1726+
: NAME_ERROR_MSG;
17231727
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
1724-
NAME_ERROR_MSG, name);
1728+
err_msg, name);
17251729
ERROR_NO_POP();
17261730
}
17271731
}
@@ -1888,10 +1892,13 @@ dummy_func(
18881892
inst(DELETE_FAST, (--)) {
18891893
_PyStackRef v = GETLOCAL(oparg);
18901894
if (PyStackRef_IsNull(v)) {
1891-
_PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError,
1892-
UNBOUNDLOCAL_ERROR_MSG,
1893-
PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg)
1894-
);
1895+
PyObject *name;
1896+
name = PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames,
1897+
oparg);
1898+
const char *err_msg = PyMapping_HasKey(BUILTINS(), name)
1899+
? CANNOT_DELETE_BUILTIN_ERROR_MSG
1900+
: UNBOUNDLOCAL_ERROR_MSG;
1901+
_PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, err_msg);
18951902
ERROR_IF(true);
18961903
}
18971904
_PyStackRef tmp = GETLOCAL(oparg);

Python/ceval_macros.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
303303
"cannot access free variable '%s' where it is not associated with a value" \
304304
" in enclosing scope"
305305
#define NAME_ERROR_MSG "name '%.200s' is not defined"
306+
#define CANNOT_DELETE_BUILTIN_ERROR_MSG "cannot delete builtin '%.200s'"
306307

307308
// If a trace function sets a new f_lineno and
308309
// *then* raises, we use the destination when searching

Python/executor_cases.c.h

Lines changed: 15 additions & 8 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: 15 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)