bdb.py
来自「mallet是自然语言处理、机器学习领域的一个开源项目。」· Python 代码 · 共 564 行 · 第 1/2 页
PY
564 行
"""Debugger basics"""import sysimport osimport types__all__ = ["BdbQuit","Bdb","Breakpoint"]BdbQuit = 'bdb.BdbQuit' # Exception to give up completelyclass Bdb: """Generic Python debugger base class. This class takes care of details of the trace facility; a derived class should implement user interaction. The standard debugger class (pdb.Pdb) is an example. """ def __init__(self): self.breaks = {} self.fncache = {} def canonic(self, filename): if filename == "<" + filename[1:-1] + ">": return filename canonic = self.fncache.get(filename) if not canonic: canonic = os.path.abspath(filename) canonic = os.path.normcase(canonic) self.fncache[filename] = canonic return canonic def reset(self): import linecache linecache.checkcache() self.botframe = None self.stopframe = None self.returnframe = None self.quitting = 0 def trace_dispatch(self, frame, event, arg): if self.quitting: return # None if event == 'line': return self.dispatch_line(frame) if event == 'call': return self.dispatch_call(frame, arg) if event == 'return': return self.dispatch_return(frame, arg) if event == 'exception': return self.dispatch_exception(frame, arg) print 'bdb.Bdb.dispatch: unknown debugging event:', `event` return self.trace_dispatch def dispatch_line(self, frame): if self.stop_here(frame) or self.break_here(frame): self.user_line(frame) if self.quitting: raise BdbQuit return self.trace_dispatch def dispatch_call(self, frame, arg): # XXX 'arg' is no longer used if self.botframe is None: # First call of dispatch since reset() self.botframe = frame.f_back # (CT) Note that this may also be None! return self.trace_dispatch if not (self.stop_here(frame) or self.break_anywhere(frame)): # No need to trace this function return # None self.user_call(frame, arg) if self.quitting: raise BdbQuit return self.trace_dispatch def dispatch_return(self, frame, arg): if self.stop_here(frame) or frame == self.returnframe: self.user_return(frame, arg) if self.quitting: raise BdbQuit return self.trace_dispatch def dispatch_exception(self, frame, arg): if self.stop_here(frame): self.user_exception(frame, arg) if self.quitting: raise BdbQuit return self.trace_dispatch # Normally derived classes don't override the following # methods, but they may if they want to redefine the # definition of stopping and breakpoints. def stop_here(self, frame): # (CT) stopframe may now also be None, see dispatch_call. # (CT) the former test for None is therefore removed from here. if frame is self.stopframe: return 1 while frame is not None and frame is not self.stopframe: if frame is self.botframe: return 1 frame = frame.f_back return 0 def break_here(self, frame): filename = self.canonic(frame.f_code.co_filename) if not self.breaks.has_key(filename): return 0 lineno = frame.f_lineno if not lineno in self.breaks[filename]: return 0 # flag says ok to delete temp. bp (bp, flag) = effective(filename, lineno, frame) if bp: self.currentbp = bp.number if (flag and bp.temporary): self.do_clear(str(bp.number)) return 1 else: return 0 def do_clear(self, arg): raise NotImplementedError, "subclass of bdb must implement do_clear()" def break_anywhere(self, frame): return self.breaks.has_key( self.canonic(frame.f_code.co_filename)) # Derived classes should override the user_* methods # to gain control. def user_call(self, frame, argument_list): """This method is called when there is the remote possibility that we ever need to stop in this function.""" pass def user_line(self, frame): """This method is called when we stop or break at this line.""" pass def user_return(self, frame, return_value): """This method is called when a return trap is set here.""" pass def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): """This method is called if an exception occurs, but only if we are to stop at or just below this level.""" pass # Derived classes and clients can call the following methods # to affect the stepping state. def set_step(self): """Stop after one line of code.""" self.stopframe = None self.returnframe = None self.quitting = 0 def set_next(self, frame): """Stop on the next line in or below the given frame.""" self.stopframe = frame self.returnframe = None self.quitting = 0 def set_return(self, frame): """Stop when returning from the given frame.""" self.stopframe = frame.f_back self.returnframe = frame self.quitting = 0 def set_trace(self): """Start debugging from here.""" frame = sys._getframe().f_back self.reset() while frame: frame.f_trace = self.trace_dispatch self.botframe = frame frame = frame.f_back self.set_step() sys.settrace(self.trace_dispatch) def set_continue(self): # Don't stop except at breakpoints or when finished self.stopframe = self.botframe self.returnframe = None self.quitting = 0 if not self.breaks: # no breakpoints; run without debugger overhead sys.settrace(None) frame = sys._getframe().f_back while frame and frame is not self.botframe: del frame.f_trace frame = frame.f_back def set_quit(self): self.stopframe = self.botframe self.returnframe = None self.quitting = 1 sys.settrace(None) # Derived classes and clients can call the following methods # to manipulate breakpoints. These methods return an # error message is something went wrong, None if all is well. # Set_break prints out the breakpoint line and file:lineno. # Call self.get_*break*() to see the breakpoints or better # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint(). def set_break(self, filename, lineno, temporary=0, cond = None): filename = self.canonic(filename) import linecache # Import as late as possible line = linecache.getline(filename, lineno) if not line: return 'Line %s:%d does not exist' % (filename, lineno) if not self.breaks.has_key(filename): self.breaks[filename] = [] list = self.breaks[filename] if not lineno in list: list.append(lineno) bp = Breakpoint(filename, lineno, temporary, cond) def clear_break(self, filename, lineno): filename = self.canonic(filename) if not self.breaks.has_key(filename): return 'There are no breakpoints in %s' % filename if lineno not in self.breaks[filename]: return 'There is no breakpoint at %s:%d' % (filename, lineno) # If there's only one bp in the list for that file,line # pair, then remove the breaks entry for bp in Breakpoint.bplist[filename, lineno][:]: bp.deleteMe() if not Breakpoint.bplist.has_key((filename, lineno)): self.breaks[filename].remove(lineno) if not self.breaks[filename]: del self.breaks[filename] def clear_bpbynumber(self, arg): try: number = int(arg) except: return 'Non-numeric breakpoint number (%s)' % arg try: bp = Breakpoint.bpbynumber[number] except IndexError: return 'Breakpoint number (%d) out of range' % number if not bp: return 'Breakpoint (%d) already deleted' % number self.clear_break(bp.file, bp.line) def clear_all_file_breaks(self, filename): filename = self.canonic(filename) if not self.breaks.has_key(filename): return 'There are no breakpoints in %s' % filename for line in self.breaks[filename]: blist = Breakpoint.bplist[filename, line] for bp in blist: bp.deleteMe() del self.breaks[filename] def clear_all_breaks(self): if not self.breaks: return 'There are no breakpoints' for bp in Breakpoint.bpbynumber: if bp: bp.deleteMe() self.breaks = {} def get_break(self, filename, lineno): filename = self.canonic(filename) return self.breaks.has_key(filename) and \ lineno in self.breaks[filename] def get_breaks(self, filename, lineno): filename = self.canonic(filename) return self.breaks.has_key(filename) and \ lineno in self.breaks[filename] and \ Breakpoint.bplist[filename, lineno] or [] def get_file_breaks(self, filename): filename = self.canonic(filename) if self.breaks.has_key(filename): return self.breaks[filename] else:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?