""" Provides a breakpoint registry that can be sent to another process (via getBreakpointList()). """ import os try: from cPickle import Pickler, Unpickler except: from pickle import Pickler, Unpickler class FileBreakpointList: def __init__(self): self.lines = {} # lineno -> [{'temporary', 'cond', 'enabled', 'ignore'}] def loadBreakpoints(self, fn): try: if os.path.exists(fn): f = open(fn, 'rb') u = Unpickler(f) newlines = u.load() # The following line isn't quite correct # when multiple breakpoints are set on a # single line. self.lines.update(newlines) return 1 else: return 0 except: self.lines = {} return 0 def saveBreakpoints(self, fn): try: if len(self.lines): savelines = {} # Filter out the temporary lines when saving. for lineno, linebreaks in self.lines.items(): savelines[lineno] = saveline = [] for brk in linebreaks: if not brk['temporary']: saveline.append(brk) f = open(fn, 'wb') p = Pickler(f) p.dump(savelines) else: os.remove(fn) except: pass def addBreakpoint(self, lineno, temp=0, cond='', ignore=0): newbrk = {'temporary':temp, 'cond':cond, 'enabled':1, 'ignore':ignore} if self.lines.has_key(lineno): linebreaks = self.lines[lineno] for brk in linebreaks: if brk['temporary'] == temp and brk['cond'] == cond: # Already added. return linebreaks.append(newbrk) else: self.lines[lineno] = linebreaks = [newbrk] def deleteBreakpoints(self, lineno): if self.lines.has_key(lineno): del self.lines[lineno] def moveBreakpoint(self, lineno, newlineno): if lineno != newlineno and self.lines.has_key(lineno): bp = self.lines[lineno] del self.lines[lineno] self.lines[lineno] = bp def adjustBreakpoints(self, lineno, delta): set_breaks = [] # traverse list twice, first deleting then re-adding to avoid stepping # on our own toes for brklineno, breaks in self.lines.items(): if lineno < brklineno-1: del self.lines[brklineno] set_breaks.append( (brklineno+delta, breaks) ) for brklineno, breaks in set_breaks: self.lines[brklineno] = breaks def enableBreakpoints(self, lineno, enable=1): if self.lines.has_key(lineno): linebreaks = self.lines[lineno] for brk in linebreaks: brk['enabled'] = enable def ignoreBreakpoints(self, lineno, ignore=0): if self.lines.has_key(lineno): linebreaks = self.lines[lineno] for brk in linebreaks: brk['ignore'] = ignore def conditionalBreakpoints(self, lineno, cond=''): if self.lines.has_key(lineno): linebreaks = self.lines[lineno] for brk in linebreaks: brk['cond'] = cond def listBreakpoints(self): rval = [] for lineno, linebreaks in self.lines.items(): for brk in linebreaks: brkinfo = {'lineno':lineno} brkinfo.update(brk) rval.append(brkinfo) return rval def hasBreakpoint(self, lineno, endlineno=-1): if endlineno < 0: return self.lines.has_key(lineno) else: for line in self.lines.keys(): if line >= lineno and line <= endlineno: return 1 return 0 def clearTemporaryBreakpoints(self, lineno): if self.lines.has_key(lineno): linebreaks = self.lines[lineno] idx = 0 while idx < len(linebreaks): brk = linebreaks[idx] if brk['temporary']: del linebreaks[idx] else: idx = idx + 1 def clearAllBreakpoints(self): self.lines = {} class BreakpointList: def __init__(self): self.files = {} # filename -> FileBreakpointList def normalize(self, filename): if filename.find('://') < 0: filename = 'file://' + filename return filename def addBreakpoint(self, filename, lineno, temp=0, cond='', ignore=0): filename = self.normalize(filename) filelist = self.getFileBreakpoints(filename) filelist.addBreakpoint(lineno, temp, cond, ignore) def deleteBreakpoints(self, filename, lineno): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] filelist.deleteBreakpoints(lineno) def moveBreakpoint(self, filename, lineno, newlineno): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] filelist.moveBreakpoint(lineno, newlineno) def adjustBreakpoints(self, filename, lineno, delta): if self.files.has_key(filename): filelist = self.files[filename] return filelist.adjustBreakpoints(lineno, delta) return 0 def enableBreakpoints(self, filename, lineno, enable=1): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] filelist.enableBreakpoints(lineno, enable) def ignoreBreakpoints(self, filename, lineno, ignore=0): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] filelist.ignoreBreakpoints(lineno, ignore) def conditionalBreakpoints(self, filename, lineno, cond=''): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] filelist.conditionalBreakpoints(lineno, cond) def clearTemporaryBreakpoints(self, filename, lineno): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] filelist.clearTemporaryBreakpoints(lineno) def renameFileBreakpoints(self, oldname, newname): oldname = self.normalize(oldname) newname = self.normalize(newname) if self.files.has_key(oldname): filelist = self.files[oldname] filelist.clearAllBreakpoints() del self.files[oldname] self.files[newname] = filelist def getFileBreakpoints(self, filename): filename = self.normalize(filename) if self.files.has_key(filename): return self.files[filename] else: self.files[filename] = filelist = FileBreakpointList() return filelist def hasBreakpoint(self, filename, lineno, endlineno=-1): filename = self.normalize(filename) if self.files.has_key(filename): filelist = self.files[filename] return filelist.hasBreakpoint(lineno, endlineno) return 0 def getBreakpointList(self, fn=None): """Returns a list designed to pass to the setAllBreakpoints() debugger method. The optional fn constrains the return value to breakpoints in a specified file.""" rval = [] if fn is not None: fn = self.normalize(fn) for filename, filelist in self.files.items(): if fn is None or filename == fn: for lineno, linebreaks in filelist.lines.items(): for brk in linebreaks: brkinfo = {'filename': filename, 'lineno': lineno} brkinfo.update(brk) rval.append(brkinfo) return rval # ??? Should this really be a global variable? bplist = BreakpointList()