55#include "pycore_code.h" // CO_FAST_LOCAL, etc.
66#include "pycore_function.h" // _PyFunction_FromConstructor()
77#include "pycore_moduleobject.h" // _PyModule_GetDict()
8+ #include "pycore_modsupport.h" // _PyArg_CheckPositional()
89#include "pycore_object.h" // _PyObject_GC_UNTRACK()
910#include "pycore_opcode_metadata.h" // _PyOpcode_Deopt, _PyOpcode_Caches
1011
@@ -158,16 +159,16 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
158159 PyObject * * fast = _PyFrame_GetLocalsArray (frame -> f_frame );
159160 PyCodeObject * co = _PyFrame_GetCode (frame -> f_frame );
160161
161- if (value == NULL ) {
162- PyErr_SetString (PyExc_TypeError , "cannot remove variables from FrameLocalsProxy" );
163- return -1 ;
164- }
165-
166162 int i = framelocalsproxy_getkeyindex (frame , key , false);
167163 if (i == -2 ) {
168164 return -1 ;
169165 }
170166 if (i >= 0 ) {
167+ if (value == NULL ) {
168+ PyErr_SetString (PyExc_ValueError , "cannot remove local variables from FrameLocalsProxy" );
169+ return -1 ;
170+ }
171+
171172 _Py_Executors_InvalidateDependency (PyInterpreterState_Get (), co , 1 );
172173
173174 _PyLocals_Kind kind = _PyLocals_GetKind (co -> co_localspluskinds , i );
@@ -200,6 +201,10 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
200201 PyObject * extra = frame -> f_extra_locals ;
201202
202203 if (extra == NULL ) {
204+ if (value == NULL ) {
205+ _PyErr_SetKeyError (key );
206+ return -1 ;
207+ }
203208 extra = PyDict_New ();
204209 if (extra == NULL ) {
205210 return -1 ;
@@ -209,7 +214,11 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
209214
210215 assert (PyDict_Check (extra ));
211216
212- return PyDict_SetItem (extra , key , value );
217+ if (value == NULL ) {
218+ return PyDict_DelItem (extra , key );
219+ } else {
220+ return PyDict_SetItem (extra , key , value );
221+ }
213222}
214223
215224static int
@@ -674,6 +683,59 @@ framelocalsproxy_setdefault(PyObject* self, PyObject *const *args, Py_ssize_t na
674683 return result ;
675684}
676685
686+ static PyObject *
687+ framelocalsproxy_pop (PyObject * self , PyObject * const * args , Py_ssize_t nargs )
688+ {
689+ if (!_PyArg_CheckPositional ("pop" , nargs , 1 , 2 )) {
690+ return NULL ;
691+ }
692+
693+ PyObject * key = args [0 ];
694+ PyObject * default_value = NULL ;
695+
696+ if (nargs == 2 ) {
697+ default_value = args [1 ];
698+ }
699+
700+ PyFrameObject * frame = ((PyFrameLocalsProxyObject * )self )-> frame ;
701+
702+ int i = framelocalsproxy_getkeyindex (frame , key , false);
703+ if (i == -2 ) {
704+ return NULL ;
705+ }
706+
707+ if (i >= 0 ) {
708+ PyErr_SetString (PyExc_ValueError , "cannot remove local variables from FrameLocalsProxy" );
709+ return NULL ;
710+ }
711+
712+ PyObject * result = NULL ;
713+
714+ if (frame -> f_extra_locals == NULL ) {
715+ if (default_value != NULL ) {
716+ return Py_XNewRef (default_value );
717+ } else {
718+ _PyErr_SetKeyError (key );
719+ return NULL ;
720+ }
721+ }
722+
723+ if (PyDict_Pop (frame -> f_extra_locals , key , & result ) < 0 ) {
724+ return NULL ;
725+ }
726+
727+ if (result == NULL ) {
728+ if (default_value != NULL ) {
729+ return Py_XNewRef (default_value );
730+ } else {
731+ _PyErr_SetKeyError (key );
732+ return NULL ;
733+ }
734+ }
735+
736+ return result ;
737+ }
738+
677739static PyObject *
678740framelocalsproxy_copy (PyObject * self , PyObject * Py_UNUSED (ignored ))
679741{
@@ -741,6 +803,8 @@ static PyMethodDef framelocalsproxy_methods[] = {
741803 NULL },
742804 {"get" , _PyCFunction_CAST (framelocalsproxy_get ), METH_FASTCALL ,
743805 NULL },
806+ {"pop" , _PyCFunction_CAST (framelocalsproxy_pop ), METH_FASTCALL ,
807+ NULL },
744808 {"setdefault" , _PyCFunction_CAST (framelocalsproxy_setdefault ), METH_FASTCALL ,
745809 NULL },
746810 {NULL , NULL } /* sentinel */
0 commit comments