Title: [PATCH] Debuggers need a way to change the locals of a frame
Type: enhancement Stage: patch review
Components: Interpreter Core Versions: Python 3.3
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: arigo, fabioz, loewis, rhettinger
Priority: normal Keywords: patch

Created on 2007-02-07 17:12 by fabioz, last changed 2014-02-06 15:47 by fabioz.

File name Uploaded Description Edit fabioz, 2007-02-07 17:12 fabioz, 2014-02-04 22:41 Some cases where changing frame.f_locals fails
Messages (14)
msg55003 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2007-02-07 17:12
Debuggers need a way to change the local variables in a given frame... currently, this works only if this change is done in the topmost frame (and under certain circumstances), but it should work for any frame.

Initial discussion at:

Apparently, the problem is the order in which PyFrame_LocalsToFast / PyFrame_FastToLocals is called.

The proposed solution to this is having a savelocals() method in the frame object and have it reflect the changes in its returned dict into its locals. It will simply enable users to call PyFrame_LocalsToFast externally after a change, to be sure that it will not be changed (and it must be done before another call to PyFrame_LocalsToFast -- which I don't see as a large problem, because it is of restrict use -- mainly for debuggers).

--------- frameobject.c Patch part 1: -----------------

static PyObject *
PyFrame_SaveLocals(PyFrameObject *f)
    PyFrame_LocalsToFast(f, 0);
	return Py_None;

static PyMethodDef frame_methodlist[] = {
    {"savelocals", (PyCFunction)PyFrame_SaveLocals, METH_NOARGS,
     "After a change in f_locals, this method should be called to save the changes internally."
    {NULL}  /* Sentinel */

---------- frameobject.c Patch part 2: ---------------
Add to PyTypeObject PyFrame_Type:

frame_methodlist,/* tp_methods */

------------------ end patch -------------------------

I'm sorry that this is not in an actual patch format... but as I didn't get it from the cvs, it is easier for me to explain it (as it is a rather small patch).

Attached is a test-case for this patch.


msg55004 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2007-02-08 08:38
Why don't you set the clear parameter to 1?

Please do submit a patch, you can use 'diff -ur' to create a recursive unified diff between source trees. Please also try to come up with a patch to the documentation.
msg55005 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2007-02-10 20:16
A point of detail probably, but I suppose that instead of introducing a new method on frame objects, we could allow f_locals to be a writeable attribute.  Setting it to a dictionary would update the value of the local variables.  It's a bit of a hack, but so is the need for an explicit savelocals() method.

A cleaner solution is to have f_locals return a dict-like object instead of a real dict when appropriate, but it takes more efforts to implement.
msg110520 - (view) Author: Mark Lawrence (BreamoreBoy) * Date: 2010-07-16 22:37
Fabio, could you please supply a patch as requested by Martin in msg55004?  Also note Armin's comments in msg55005.
msg113625 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2010-08-11 20:07
I think this falls under the language moratorium in that it requires core changes that make it more difficult for other implementations to catch-up.
msg114415 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2010-08-19 23:40
I agree that it'd be cleaner making the frame locals a dict-like object with write access, but I wouldn't be able to do that because of time constraints (and I'd have to research more how to do it and it'd be much more intrusive I guess).

So, if it's guaranteed that it'll be accepted I can provide a patch (changing the clear to 1) of the savelocals() version.

I guess I don't agree this falls in the language moratorium, but if that's the case I can wait 1 or 2 more years before submitting the patch :)
msg210233 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2014-02-04 14:22
Just a note for anyone interested: ctypes can be used to access that function:

So, I think that the changes I proposed shouldn't be applied (it'd only be worth if someone provided an implementation that did frame.f_locals writable...).
msg210265 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2014-02-04 21:01
Hi Fabio!  This is admittedly a corner-case use case, but if you think it would be worth it, we can very easily add this as a feature to PyPy (by making frame.f_locals writeable).  Then we can add the write inside pdb, and you could do the same for PyDev when running on PyPy.  It's certainly something that goes beyond the standard of CPython 2.7 but we'd consider it because it's obviously debug-only.
msg210266 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2014-02-04 21:12
Also, can you provide a concrete case?  Trying around in CPython 2.7, it seems that locals of the current frame can always be modified from a pdb.set_trace().
msg210275 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2014-02-04 22:41
Hi Armin,

Sure, just attached the test case with tests failing (on the top, comment the save_locals(frame) which has a 'pass' to see it working).

Mostly, it happens when editing something not in the top-frame (but sometimes I think it could fail there too, depending whether it's a cellvar or freevar).
msg210374 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2014-02-06 11:09
Sorry to hijack CPython's bug tracker for that, but can you check if this makes sense to you?  I added a function 'locals_to_fast()' to the __pypy__ built-in module which just calls the PyPy equivalent to PyFrame_LocalsToFast().  Your tests are passing, so I guess there should be no problem.  The diff is here: (are you ok with having your name put into the test file?).
msg210400 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2014-02-06 15:15
Hi Armin,

That does make sense to me, but maybe it could be nice providing a standard API across Python implementations to make that call (even if the CPython version uses ctypes underneath and the PyPy version uses RPython), but I'll leave that up to CPython and PyPy devs to discuss -- so, for me, if that call is in the __pypy__ namespace, I'll do the proper check and use it in the PyDev debugger :)

p.s.: no problem on putting my name on the test case (and distributing in whatever license PyPy or CPython is under).
msg210402 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2014-02-06 15:45
CPython 2.7 is in feature-freeze, so we need to add it to __pypy__.  If people here decide to add it more officially to CPython 3.x, then we'll also add it into pypy3, obviously.  I'm sure a debugger can cope with a few extra ifs to check on which platform it is really running :-)
msg210403 - (view) Author: Fabio Zadrozny (fabioz) * Date: 2014-02-06 15:47
Sure, no problems on my side :)
Date User Action Args
2014-02-06 15:47:40fabiozsetmessages: + msg210403
2014-02-06 15:45:02arigosetmessages: + msg210402
2014-02-06 15:15:16fabiozsetmessages: + msg210400
2014-02-06 11:09:44arigosetmessages: + msg210374
2014-02-04 22:41:30fabiozsetfiles: +

messages: + msg210275
2014-02-04 21:12:14arigosetmessages: + msg210266
2014-02-04 21:01:12arigosetmessages: + msg210265
2014-02-04 14:22:09fabiozsetmessages: + msg210233
2014-02-03 19:48:40BreamoreBoysetnosy: - BreamoreBoy
2010-08-19 23:40:52fabiozsetmessages: + msg114415
2010-08-11 20:07:34rhettingersetnosy: + rhettinger

messages: + msg113625
versions: + Python 3.3, - Python 3.2
2010-08-09 04:20:57terry.reedysetversions: + Python 3.2, - Python 3.1, Python 2.7
2010-07-16 22:37:50BreamoreBoysetnosy: + BreamoreBoy
messages: + msg110520
2009-03-30 21:24:06ajaksu2setkeywords: + patch
stage: patch review
versions: + Python 3.1, Python 2.7, - Python 2.6
2007-02-07 17:12:28fabiozcreate