Hi, First a brief introduction, since this is my first post to python-dev: I'm a professional software engineer, mostly using C/C++ and Python. I use Python a lot for my own projects and some of you will know me from the spambayes project, as the author of pop3proxy.py. I was interested to see Armin's patch [617312] to "allow the C profile and trace functions to alter some fields of the current PyFrameObject". I'm writing a Python debugger, and as Armin says, his patch "could also be used by advanced debuggers to allow the execution point to be modified by the user." A "Set-next-statement" feature is on my list of nice-to-have-but-hard-to-do jobs, and this patch could make it easy. (I know the blockstack presents a problem, but if it's insurmountable I'm happy to ignore that and to only allow skipping to lines in the same block - 90% of my use of the equivalent feature in MSVC is to skip back one line or forward one line.) There's one fly in the ointment - I'm trying to keep my debugger in pure Python, and Armin's patch only applies to C trace functions. If frame.f_lasti were writable by Python trace functions, pure Python debuggers (including pdb) could implement Set-Next-Statement. Here's a small script that demonstrates what I mean, and the one-line patch to frameobject.c that enables it: ----------------------------------------------------------------------- """Demonstration of debugger 'Set-next-statement' feature. Requires Python 2.2.2 with writeable frame.f_lasti. Prints "1, 2, 2, 3".""" import sys, pprint def example(): print 1, print 2, print 3 # Line 9; we skip back to 8 the first time we hit this. class DebuggerHook: def __init__(self): self.done = False # Have we done the Set-next-statement yet? self.lasti = 0 # The frame.f_lasti of the previous line. sys.settrace(self.trace) def trace(self, frame, action, arg): if not self.done and frame.f_lineno == 9: # This is the first time we've hit line 9; skip back to 8. frame.f_lasti = self.lasti self.done = True else: # Store the instruction offset of this line. self.lasti = frame.f_lasti return self.trace debugger = DebuggerHook() example() # Prints "1, 2, 2, 3" ----------------------------------------------------------------------- *** frameobject.c Tue Oct 8 08:16:39 2002 --- frameobject-222b1.c Tue Oct 8 08:16:12 2002 *************** *** 16,20 **** {"f_builtins", T_OBJECT, OFF(f_builtins),RO}, {"f_globals", T_OBJECT, OFF(f_globals), RO}, ! {"f_lasti", T_INT, OFF(f_lasti)}, {"f_lineno", T_INT, OFF(f_lineno), RO}, {"f_restricted",T_INT, OFF(f_restricted),RO}, --- 16,20 ---- {"f_builtins", T_OBJECT, OFF(f_builtins),RO}, {"f_globals", T_OBJECT, OFF(f_globals), RO}, ! {"f_lasti", T_INT, OFF(f_lasti), RO}, {"f_lineno", T_INT, OFF(f_lineno), RO}, {"f_restricted",T_INT, OFF(f_restricted),RO}, ----------------------------------------------------------------------- For completeness, f_lineno should probably be writable as well, but I'm keeping the changes minimal for the purposes of discussion. Is this a reasonable suggestion for 2.3, or is it giving people too much rope? A nasty consequence is that you can write Python code that causes Python to seg-fault, but you have to be doing some fairly advanced stuff for that to happen. I would say that the power of a Set-next-statement feature in pdb and other debuggers is worth the price, but others may disagree...? -- Richie Hindle richie@entrian.com
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4