?? pdb.py
字號:
#! /usr/bin/env python"""A Python debugger."""# (See pdb.doc for documentation.)import sysimport linecacheimport cmdimport bdbfrom repr import Reprimport osimport re# Create a custom safe Repr instance and increase its maxstring.# The default of 30 truncates error messages too easily._repr = Repr()_repr.maxstring = 200_saferepr = _repr.repr__all__ = ["run", "pm", "Pdb", "runeval", "runctx", "runcall", "set_trace", "post_mortem", "help"]def find_function(funcname, filename): cre = re.compile(r'def\s+%s\s*[(]' % funcname) try: fp = open(filename) except IOError: return None # consumer of this info expects the first line to be 1 lineno = 1 answer = None while 1: line = fp.readline() if line == '': break if cre.match(line): answer = funcname, filename, lineno break lineno = lineno + 1 fp.close() return answer# Interaction prompt line will separate file and call info from code# text using value of line_prefix string. A newline and arrow may# be to your liking. You can set it once pdb is imported using the# command "pdb.line_prefix = '\n% '".# line_prefix = ': ' # Use this to get the old situation backline_prefix = '\n-> ' # Probably a better defaultclass Pdb(bdb.Bdb, cmd.Cmd): def __init__(self): bdb.Bdb.__init__(self) cmd.Cmd.__init__(self) self.prompt = '(Pdb) ' self.aliases = {} # Try to load readline if it exists try: import readline except ImportError: pass # Read $HOME/.pdbrc and ./.pdbrc self.rcLines = [] if os.environ.has_key('HOME'): envHome = os.environ['HOME'] try: rcFile = open(os.path.join(envHome, ".pdbrc")) except IOError: pass else: for line in rcFile.readlines(): self.rcLines.append(line) rcFile.close() try: rcFile = open(".pdbrc") except IOError: pass else: for line in rcFile.readlines(): self.rcLines.append(line) rcFile.close() def reset(self): bdb.Bdb.reset(self) self.forget() def forget(self): self.lineno = None self.stack = [] self.curindex = 0 self.curframe = None def setup(self, f, t): self.forget() self.stack, self.curindex = self.get_stack(f, t) self.curframe = self.stack[self.curindex][0] self.execRcLines() # Can be executed earlier than 'setup' if desired def execRcLines(self): if self.rcLines: # Make local copy because of recursion rcLines = self.rcLines # executed only once self.rcLines = [] for line in rcLines: line = line[:-1] if len (line) > 0 and line[0] != '#': self.onecmd (line) # Override Bdb methods (except user_call, for now) def user_line(self, frame): """This function is called when we stop or break at this line.""" self.interaction(frame, None) def user_return(self, frame, return_value): """This function is called when a return trap is set here.""" frame.f_locals['__return__'] = return_value print '--Return--' self.interaction(frame, None) def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): """This function is called if an exception occurs, but only if we are to stop at or just below this level.""" frame.f_locals['__exception__'] = exc_type, exc_value if type(exc_type) == type(''): exc_type_name = exc_type else: exc_type_name = exc_type.__name__ print exc_type_name + ':', _saferepr(exc_value) self.interaction(frame, exc_traceback) # General interaction function def interaction(self, frame, traceback): self.setup(frame, traceback) self.print_stack_entry(self.stack[self.curindex]) self.cmdloop() self.forget() def default(self, line): if line[:1] == '!': line = line[1:] locals = self.curframe.f_locals globals = self.curframe.f_globals try: code = compile(line + '\n', '<stdin>', 'single') exec code in globals, locals except: t, v = sys.exc_info()[:2] if type(t) == type(''): exc_type_name = t else: exc_type_name = t.__name__ print '***', exc_type_name + ':', v def precmd(self, line): """Handle alias expansion and ';;' separator.""" if not line.strip(): return line args = line.split() while self.aliases.has_key(args[0]): line = self.aliases[args[0]] ii = 1 for tmpArg in args[1:]: line = line.replace("%" + str(ii), tmpArg) ii = ii + 1 line = line.replace("%*", ' '.join(args[1:])) args = line.split() # split into ';;' separated commands # unless it's an alias command if args[0] != 'alias': marker = line.find(';;') if marker >= 0: # queue up everything after marker next = line[marker+2:].lstrip() self.cmdqueue.append(next) line = line[:marker].rstrip() return line # Command definitions, called by cmdloop() # The argument is the remaining string on the command line # Return true to exit from the command loop do_h = cmd.Cmd.do_help def do_break(self, arg, temporary = 0): # break [ ([filename:]lineno | function) [, "condition"] ] if not arg: if self.breaks: # There's at least one print "Num Type Disp Enb Where" for bp in bdb.Breakpoint.bpbynumber: if bp: bp.bpprint() return # parse arguments; comma has lowest precedence # and cannot occur in filename filename = None lineno = None cond = None comma = arg.find(',') if comma > 0: # parse stuff after comma: "condition" cond = arg[comma+1:].lstrip() arg = arg[:comma].rstrip() # parse stuff before comma: [filename:]lineno | function colon = arg.rfind(':') if colon >= 0: filename = arg[:colon].rstrip() f = self.lookupmodule(filename) if not f: print '*** ', `filename`, print 'not found from sys.path' return else: filename = f arg = arg[colon+1:].lstrip() try: lineno = int(arg) except ValueError, msg: print '*** Bad lineno:', arg return else: # no colon; can be lineno or function try: lineno = int(arg) except ValueError: try: func = eval(arg, self.curframe.f_globals, self.curframe.f_locals) except: func = arg try: if hasattr(func, 'im_func'): func = func.im_func code = func.func_code lineno = code.co_firstlineno filename = code.co_filename except: # last thing to try (ok, filename, ln) = self.lineinfo(arg) if not ok: print '*** The specified object', print `arg`, print 'is not a function' print ('or was not found ' 'along sys.path.') return lineno = int(ln) if not filename: filename = self.defaultFile() # Check for reasonable breakpoint line = self.checkline(filename, lineno) if line: # now set the break point err = self.set_break(filename, line, temporary, cond) if err: print '***', err else: bp = self.get_breaks(filename, line)[-1] print "Breakpoint %d at %s:%d" % (bp.number, bp.file, bp.line) # To be overridden in derived debuggers def defaultFile(self): """Produce a reasonable default.""" filename = self.curframe.f_code.co_filename if filename == '<string>' and mainpyfile: filename = mainpyfile return filename do_b = do_break def do_tbreak(self, arg): self.do_break(arg, 1) def lineinfo(self, identifier): failed = (None, None, None) # Input is identifier, may be in single quotes idstring = identifier.split("'") if len(idstring) == 1: # not in single quotes id = idstring[0].strip() elif len(idstring) == 3: # quoted id = idstring[1].strip() else: return failed if id == '': return failed parts = id.split('.') # Protection for derived debuggers if parts[0] == 'self': del parts[0] if len(parts) == 0: return failed # Best first guess at file to look at fname = self.defaultFile() if len(parts) == 1: item = parts[0] else: # More than one part. # First is module, second is method/class f = self.lookupmodule(parts[0]) if f: fname = f item = parts[1] answer = find_function(item, fname) return answer or failed def checkline(self, filename, lineno): """Return line number of first line at or after input argument such that if the input points to a 'def', the returned line number is the first non-blank/non-comment line to follow. If the input points to a blank or comment line, return 0. At end of file, also return 0.""" line = linecache.getline(filename, lineno) if not line: print 'End of file' return 0 line = line.strip() # Don't allow setting breakpoint at a blank line if ( not line or (line[0] == '#') or
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -