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 _PyStackRef * 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 );
@@ -202,6 +203,10 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
202203 PyObject * extra = frame -> f_extra_locals ;
203204
204205 if (extra == NULL ) {
206+ if (value == NULL ) {
207+ _PyErr_SetKeyError (key );
208+ return -1 ;
209+ }
205210 extra = PyDict_New ();
206211 if (extra == NULL ) {
207212 return -1 ;
@@ -211,7 +216,11 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
211216
212217 assert (PyDict_Check (extra ));
213218
214- return PyDict_SetItem (extra , key , value );
219+ if (value == NULL ) {
220+ return PyDict_DelItem (extra , key );
221+ } else {
222+ return PyDict_SetItem (extra , key , value );
223+ }
215224}
216225
217226static int
@@ -676,6 +685,59 @@ framelocalsproxy_setdefault(PyObject* self, PyObject *const *args, Py_ssize_t na
676685 return result ;
677686}
678687
688+ static PyObject *
689+ framelocalsproxy_pop (PyObject * self , PyObject * const * args , Py_ssize_t nargs )
690+ {
691+ if (!_PyArg_CheckPositional ("pop" , nargs , 1 , 2 )) {
692+ return NULL ;
693+ }
694+
695+ PyObject * key = args [0 ];
696+ PyObject * default_value = NULL ;
697+
698+ if (nargs == 2 ) {
699+ default_value = args [1 ];
700+ }
701+
702+ PyFrameObject * frame = ((PyFrameLocalsProxyObject * )self )-> frame ;
703+
704+ int i = framelocalsproxy_getkeyindex (frame , key , false);
705+ if (i == -2 ) {
706+ return NULL ;
707+ }
708+
709+ if (i >= 0 ) {
710+ PyErr_SetString (PyExc_ValueError , "cannot remove local variables from FrameLocalsProxy" );
711+ return NULL ;
712+ }
713+
714+ PyObject * result = NULL ;
715+
716+ if (frame -> f_extra_locals == NULL ) {
717+ if (default_value != NULL ) {
718+ return Py_XNewRef (default_value );
719+ } else {
720+ _PyErr_SetKeyError (key );
721+ return NULL ;
722+ }
723+ }
724+
725+ if (PyDict_Pop (frame -> f_extra_locals , key , & result ) < 0 ) {
726+ return NULL ;
727+ }
728+
729+ if (result == NULL ) {
730+ if (default_value != NULL ) {
731+ return Py_XNewRef (default_value );
732+ } else {
733+ _PyErr_SetKeyError (key );
734+ return NULL ;
735+ }
736+ }
737+
738+ return result ;
739+ }
740+
679741static PyObject *
680742framelocalsproxy_copy (PyObject * self , PyObject * Py_UNUSED (ignored ))
681743{
@@ -743,6 +805,8 @@ static PyMethodDef framelocalsproxy_methods[] = {
743805 NULL },
744806 {"get" , _PyCFunction_CAST (framelocalsproxy_get ), METH_FASTCALL ,
745807 NULL },
808+ {"pop" , _PyCFunction_CAST (framelocalsproxy_pop ), METH_FASTCALL ,
809+ NULL },
746810 {"setdefault" , _PyCFunction_CAST (framelocalsproxy_setdefault ), METH_FASTCALL ,
747811 NULL },
748812 {NULL , NULL } /* sentinel */
0 commit comments