diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py index 520fbc1b66237b..2e775911c0ae68 100644 --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -835,5 +835,23 @@ 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'"): + 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() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-18-01-13-22.gh-issue-138890.x2QKfy.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-18-01-13-22.gh-issue-138890.x2QKfy.rst new file mode 100644 index 00000000000000..a96ab13e5b4cb7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-18-01-13-22.gh-issue-138890.x2QKfy.rst @@ -0,0 +1 @@ +Deleting built-in names with :keyword:`del` now gives a clearer error message. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6c3609d293890f..f1abb4cb1f5707 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1577,9 +1577,13 @@ 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); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + } else { + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } ERROR_NO_POP(); } } @@ -1720,8 +1724,13 @@ dummy_func( ERROR_NO_POP(); } if (err == 0) { - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + } else { + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } ERROR_NO_POP(); } } @@ -1888,10 +1897,15 @@ 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 *localsplusnames = _PyFrame_GetCode(frame)->co_localsplusnames; + PyObject *name = PyTuple_GetItem(localsplusnames, oparg); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + } else { + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, name); + } ERROR_IF(true); } _PyStackRef tmp = GETLOCAL(oparg); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 64ca7716fdbdee..59b3b9a12eff31 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -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 diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1309c1317a6615..a981db32c0e250 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2209,11 +2209,17 @@ err = PyObject_DelItem(ns, name); stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, - name); - stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } else { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } JUMP_TO_ERROR(); } break; @@ -2420,10 +2426,17 @@ JUMP_TO_ERROR(); } if (err == 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } else { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } JUMP_TO_ERROR(); } break; @@ -2588,12 +2601,21 @@ oparg = CURRENT_OPARG(); _PyStackRef v = GETLOCAL(oparg); if (PyStackRef_IsNull(v)) { + PyObject *localsplusnames = _PyFrame_GetCode(frame)->co_localsplusnames; _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, - UNBOUNDLOCAL_ERROR_MSG, - PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) - ); + PyObject *name = PyTuple_GetItem(localsplusnames, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } else { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } JUMP_TO_ERROR(); } _PyStackRef tmp = GETLOCAL(oparg); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c1f6f5c85cdd88..34c378732ed05a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5192,12 +5192,21 @@ INSTRUCTION_STATS(DELETE_FAST); _PyStackRef v = GETLOCAL(oparg); if (PyStackRef_IsNull(v)) { + PyObject *localsplusnames = _PyFrame_GetCode(frame)->co_localsplusnames; _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, - UNBOUNDLOCAL_ERROR_MSG, - PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) - ); + PyObject *name = PyTuple_GetItem(localsplusnames, oparg); stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } else { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } JUMP_TO_LABEL(error); } _PyStackRef tmp = GETLOCAL(oparg); @@ -5224,10 +5233,17 @@ JUMP_TO_LABEL(error); } if (err == 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } else { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } JUMP_TO_LABEL(error); } DISPATCH(); @@ -5255,11 +5271,17 @@ err = PyObject_DelItem(ns, name); stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, - name); - stack_pointer = _PyFrame_GetStackPointer(frame); + if (PyMapping_HasKeyWithError(BUILTINS(), name) == 1) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + CANNOT_DELETE_BUILTIN_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } else { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + stack_pointer = _PyFrame_GetStackPointer(frame); + } JUMP_TO_LABEL(error); } DISPATCH();