diff options
author | Kurt B. Kaiser <kbk@shore.net> | 2002-10-23 04:48:08 +0000 |
---|---|---|
committer | Kurt B. Kaiser <kbk@shore.net> | 2002-10-23 04:48:08 +0000 |
commit | 45186c4ce08093d5f0d2f141f6e557e9726aedb4 (patch) | |
tree | c0372b3d6da9fd10493365df9f589d9b7e9996c5 /Lib/idlelib/PyShell.py | |
parent | 88f015dc8890960108e98a3114213ab258fda0c9 (diff) | |
download | cpython-git-45186c4ce08093d5f0d2f141f6e557e9726aedb4.tar.gz |
Implement Restoring Breakpoints in Subprocess Debugger
M Debugger.py
M EditorWindow.py
M PyShell.py
0. Polish PyShell.linecache_checkcache()
1. Move break clearing code to PyShell.PyShellEditorWindow from
EditorWindow.
2. Add PyShellEditorWindow.breakpoints attribute to __init__, a list of
line numbers which are breakpoints for that edit window.
3. Remove the code in Debugger which removes all module breakpoints when
debugger is closed. Want to be able to reload into debugger when
restarted.
4. Moved the code which sets EditorWindow.text breakpoints from Debugger
to PyShell.PyShellEditorWindow and refactored.
5. Implement reloading subprocess debugger with breakpoints from all open
PyShellEditorWindows when debugger is opened or subprocess restarted.
6. Eliminate the break_set attribute, use the breakpoint list instead.
Diffstat (limited to 'Lib/idlelib/PyShell.py')
-rw-r--r-- | Lib/idlelib/PyShell.py | 130 |
1 files changed, 96 insertions, 34 deletions
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 790609a366..2320ccd446 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -44,11 +44,15 @@ else: file.write(warnings.formatwarning(message, category, filename, lineno)) warnings.showwarning = idle_showwarning -# We need to patch linecache.checkcache, because we don't want it -# to throw away our <pyshell#...> entries. -# Rather than repeating its code here, we save those entries, -# then call the original function, and then restore the saved entries. -def linecache_checkcache(orig_checkcache=linecache.checkcache): +def linecache_checkcache(): + """Extend linecache.checkcache to preserve the <pyshell#...> entries + + Rather than repeating the linecache code, patch it by saving the pyshell# + entries, call linecache.checkcache(), and then restore the saved + entries. + + """ + orig_checkcache=linecache.checkcache cache = linecache.cache save = {} for filename in cache.keys(): @@ -56,36 +60,91 @@ def linecache_checkcache(orig_checkcache=linecache.checkcache): save[filename] = cache[filename] orig_checkcache() cache.update(save) + linecache.checkcache = linecache_checkcache + class PyShellEditorWindow(EditorWindow): "Regular text edit window when a shell is present" - # XXX ought to merge with regular editor window + + # XXX KBK 19Oct02 Breakpoints are currently removed if module is + # changed or closed. Future plans include saving breakpoints in a + # project file and possibly preserving breakpoints by changing their + # line numbers as a module is modified. def __init__(self, *args): + self.breakpoints = [] apply(EditorWindow.__init__, (self,) + args) self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here) - self.text.bind("<<clear-breakpoint-here>>", - self.clear_breakpoint_here) + self.text.bind("<<clear-breakpoint-here>>", self.clear_breakpoint_here) self.text.bind("<<open-python-shell>>", self.flist.open_shell) - rmenu_specs = [ - ("Set Breakpoint", "<<set-breakpoint-here>>"), - ("Clear Breakpoint", "<<clear-breakpoint-here>>") - ] + rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"), + ("Clear Breakpoint", "<<clear-breakpoint-here>>")] def set_breakpoint_here(self, event=None): - if not self.flist.pyshell or not self.flist.pyshell.interp.debugger: - self.text.bell() + text = self.text + filename = self.io.filename + if not filename: + text.bell() return - self.flist.pyshell.interp.debugger.set_breakpoint_here(self) + lineno = int(float(text.index("insert"))) + try: + i = self.breakpoints.index(lineno) + except: # only add if missing, i.e. do once + self.breakpoints.append(lineno) + text.tag_add("BREAK", "insert linestart", "insert lineend +1char") + try: # update the subprocess debugger + debug = self.flist.pyshell.interp.debugger + debug.set_breakpoint_here(filename, lineno) + except: # but debugger may not be active right now.... + pass def clear_breakpoint_here(self, event=None): - if not self.flist.pyshell or not self.flist.pyshell.interp.debugger: - self.text.bell() + text = self.text + filename = self.io.filename + if not filename: + text.bell() return - self.flist.pyshell.interp.debugger.clear_breakpoint_here(self) - + lineno = int(float(text.index("insert"))) + try: + self.breakpoints.remove(lineno) + except: + pass + text.tag_remove("BREAK", "insert linestart",\ + "insert lineend +1char") + try: + debug = self.flist.pyshell.interp.debugger + debug.clear_breakpoint_here(filename, lineno) + except: + pass + + def clear_file_breaks(self): + if self.breakpoints: + text = self.text + filename = self.io.filename + if not filename: + text.bell() + return + self.breakpoints = [] + text.tag_remove("BREAK", "1.0", END) + try: + debug = self.flist.pyshell.interp.debugger + debug.clear_file_breaks(filename) + except: + pass + + def saved_change_hook(self): + "Extend base method - clear breaks if module is modified" + if not self.get_saved(): + self.clear_file_breaks() + EditorWindow.saved_change_hook(self) + + def _close(self): + "Extend base method - clear breaks when module is closed" + self.clear_file_breaks() + EditorWindow._close(self) + class PyShellFileList(FileList): "Extend base class: file list when a shell is present" @@ -174,7 +233,8 @@ class ModifiedInterpreter(InteractiveInterpreter): # Instead, find the executable by looking relative to # sys.prefix. executable = os.path.join(sys.prefix, 'Resources', - 'Python.app', 'Contents', 'MacOS', 'python') + 'Python.app', 'Contents', + 'MacOS', 'python') return executable else: return sys.executable @@ -207,19 +267,19 @@ class ModifiedInterpreter(InteractiveInterpreter): def restart_subprocess(self): # close only the subprocess debugger - db = self.getdebugger() - if db: + debug = self.getdebugger() + if debug: RemoteDebugger.close_subprocess_debugger(self.rpcclt) # kill subprocess, spawn a new one, accept connection self.rpcclt.close() self.spawn_subprocess() self.rpcclt.accept() # restart remote debugger - if db: + if debug: gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt) - # reload remote debugger breakpoints - pass # XXX KBK 04Sep02 TBD - + # reload remote debugger breakpoints for all PyShellEditWindows + debug.load_breakpoints() + active_seq = None def poll_subprocess(self): @@ -265,6 +325,14 @@ class ModifiedInterpreter(InteractiveInterpreter): if clt is not None: clt.close() + debugger = None + + def setdebugger(self, debugger): + self.debugger = debugger + + def getdebugger(self): + return self.debugger + def remote_stack_viewer(self): import RemoteObjectBrowser oid = self.rpcclt.remotecall("exec", "stackviewer", ("flist",), {}) @@ -382,14 +450,6 @@ class ModifiedInterpreter(InteractiveInterpreter): if key[:1] + key[-1:] != "<>": del c[key] - debugger = None - - def setdebugger(self, debugger): - self.debugger = debugger - - def getdebugger(self): - return self.debugger - def display_executing_dialog(self): tkMessageBox.showerror( "Already executing", @@ -567,6 +627,8 @@ class PyShell(OutputWindow): def open_remote_debugger(self): gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self) self.interp.setdebugger(gui) + # Load all PyShellEditorWindow breakpoints: + gui.load_breakpoints() sys.ps1 = "[DEBUG ON]\n>>> " self.showprompt() self.set_debugger_indicator() |