home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pytho152.zip / emx / lib / python1.5 / lib-stdwin / wdb.py < prev    next >
Text File  |  2000-08-10  |  7KB  |  317 lines

  1. # wdb.py -- a window-based Python debugger
  2.  
  3. # XXX To do:
  4. # - don't fall out of bottom frame
  5.  
  6.  
  7. import stdwin
  8. from stdwinevents import *
  9. import sys
  10. import basewin
  11. import bdb
  12. import repr
  13.  
  14. WIDTH = 40
  15. HEIGHT = 8
  16.  
  17. WdbDone = 'wdb.WdbDone' # Exception to continue execution
  18.  
  19.  
  20. class Wdb(bdb.Bdb, basewin.BaseWindow): # Window debugger
  21.     
  22.     def __init__(self):
  23.         self.sourcewindows = {}
  24.         self.framewindows = {}
  25.         bdb.Bdb.__init__(self)
  26.         width = WIDTH*stdwin.textwidth('0')
  27.         height = HEIGHT*stdwin.lineheight()
  28.         stdwin.setdefwinsize(width, height)
  29.         basewin.BaseWindow.__init__(self, '--Stack--')
  30.         self.closed = 0
  31.     
  32.     def reset(self):
  33.         if self.closed: raise RuntimeError, 'already closed'
  34.         bdb.Bdb.reset(self)
  35.         self.forget()
  36.     
  37.     def forget(self):
  38.         self.lineno = None
  39.         self.stack = []
  40.         self.curindex = 0
  41.         self.curframe = None
  42.         for fn in self.sourcewindows.keys():
  43.             self.sourcewindows[fn].resetlineno()
  44.     
  45.     def setup(self, f, t):
  46.         self.forget()
  47.         self.stack, self.curindex = self.get_stack(f, t)
  48.         self.curframe = self.stack[self.curindex][0]
  49.         # Build a list of current frames
  50.         cfl = []
  51.         for f, i in self.stack: cfl.append(f)
  52.         # Remove deactivated frame windows
  53.         for name in self.framewindows.keys():
  54.             fw = self.framewindows[name]
  55.             if fw.frame not in cfl: fw.close()
  56.             else: fw.refreshframe()
  57.         # Refresh the stack window
  58.         self.refreshstack()
  59.     
  60.     # Override Bdb methods (except user_call, for now)
  61.     
  62.     def user_line(self, frame):
  63.         # This function is called when we stop or break at this line
  64.         self.interaction(frame, None)
  65.     
  66.     def user_return(self, frame, return_value):
  67.         # This function is called when a return trap is set here
  68.         frame.f_locals['__return__'] = return_value
  69.         self.settitle('--Return--')
  70.         self.interaction(frame, None)
  71.         if not self.closed:
  72.             self.settitle('--Stack--')
  73.     
  74.     def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
  75.         # This function is called if an exception occurs,
  76.         # but only if we are to stop at or just below this level
  77.         frame.f_locals['__exception__'] = exc_type, exc_value
  78.         if type(exc_type) == type(''):
  79.             exc_type_name = exc_type
  80.         else: exc_type_name = exc_type.__name__
  81.         self.settitle(exc_type_name + ': ' + repr.repr(exc_value))
  82.         stdwin.fleep()
  83.         self.interaction(frame, exc_traceback)
  84.         if not self.closed:
  85.             self.settitle('--Stack--')
  86.     
  87.     # Change the title
  88.     
  89.     def settitle(self, title):
  90.         self.savetitle = self.win.gettitle()
  91.         self.win.settitle(title)
  92.     
  93.     # General interaction function
  94.     
  95.     def interaction(self, frame, traceback):
  96.         import mainloop
  97.         self.popup()
  98.         self.setup(frame, traceback)
  99.         try:
  100.             mainloop.mainloop()
  101.         except WdbDone:
  102.             pass
  103.         self.forget()
  104.     
  105.     # Functions whose name is do_X for some character X
  106.     # are callable directly from the keyboard.
  107.     
  108.     def do_up(self):
  109.         if self.curindex == 0:
  110.             stdwin.fleep()
  111.         else:
  112.             self.curindex = self.curindex - 1
  113.             self.curframe = self.stack[self.curindex][0]
  114.             self.refreshstack()
  115.     do_u = do_up
  116.     
  117.     def do_down(self):
  118.         if self.curindex + 1 == len(self.stack):
  119.             stdwin.fleep()
  120.         else:
  121.             self.curindex = self.curindex + 1
  122.             self.curframe = self.stack[self.curindex][0]
  123.             self.refreshstack()
  124.     do_d = do_down
  125.     
  126.     def do_step(self):
  127.         self.set_step()
  128.         raise WdbDone
  129.     do_s = do_step
  130.     
  131.     def do_next(self):
  132.         self.set_next(self.curframe)
  133.         raise WdbDone
  134.     do_n = do_next
  135.     
  136.     def do_return(self):
  137.         self.set_return(self.curframe)
  138.         raise WdbDone
  139.     do_r = do_return
  140.     
  141.     def do_continue(self):
  142.         self.set_continue()
  143.         raise WdbDone
  144.     do_c = do_cont = do_continue
  145.     
  146.     def do_quit(self):
  147.         self.close()
  148.         raise WdbDone
  149.     do_q = do_quit
  150.     
  151.     def do_list(self):
  152.         fn = self.curframe.f_code.co_filename
  153.         if not self.sourcewindows.has_key(fn):
  154.             import wdbsrcwin
  155.             try:
  156.                 self.sourcewindows[fn] = wdbsrcwin. \
  157.                       DebuggerSourceWindow(self, fn)
  158.             except IOError:
  159.                 stdwin.fleep()
  160.                 return
  161.         w = self.sourcewindows[fn]
  162.         lineno = self.stack[self.curindex][1]
  163.         w.setlineno(lineno)
  164.         w.popup()
  165.     do_l = do_list
  166.     
  167.     def do_frame(self):
  168.         name = 'locals' + `self.curframe`[16:-1]
  169.         if self.framewindows.has_key(name):
  170.             self.framewindows[name].popup()
  171.         else:
  172.             import wdbframewin
  173.             self.framewindows[name] = \
  174.                 wdbframewin.FrameWindow(self, \
  175.                     self.curframe, \
  176.                     self.curframe.f_locals, name)
  177.     do_f = do_frame
  178.     
  179.     def do_globalframe(self):
  180.         name = 'globals' + `self.curframe`[16:-1]
  181.         if self.framewindows.has_key(name):
  182.             self.framewindows[name].popup()
  183.         else:
  184.             import wdbframewin
  185.             self.framewindows[name] = \
  186.                 wdbframewin.FrameWindow(self, \
  187.                     self.curframe, \
  188.                     self.curframe.f_globals, name)
  189.     do_g = do_globalframe
  190.     
  191.     # Link between the debugger and the window
  192.     
  193.     def refreshstack(self):
  194.         height = stdwin.lineheight() * (1 + len(self.stack))
  195.         self.win.setdocsize((0, height))
  196.         self.refreshall() # XXX be more subtle later
  197.         # Also pass the information on to the source windows
  198.         filename = self.curframe.f_code.co_filename
  199.         lineno = self.curframe.f_lineno
  200.         for fn in self.sourcewindows.keys():
  201.             w = self.sourcewindows[fn]
  202.             if fn == filename:
  203.                 w.setlineno(lineno)
  204.             else:
  205.                 w.resetlineno()
  206.     
  207.     # The remaining methods override BaseWindow methods
  208.     
  209.     def close(self):
  210.         if not self.closed:
  211.             basewin.BaseWindow.close(self)
  212.         self.closed = 1
  213.         for key in self.sourcewindows.keys():
  214.             self.sourcewindows[key].close()
  215.         for key in self.framewindows.keys():
  216.             self.framewindows[key].close()
  217.         self.set_quit()
  218.     
  219.     def char(self, detail):
  220.         try:
  221.             func = eval('self.do_' + detail)
  222.         except (AttributeError, SyntaxError):
  223.             stdwin.fleep()
  224.             return
  225.         func()
  226.     
  227.     def command(self, detail):
  228.         if detail == WC_UP:
  229.             self.do_up()
  230.         elif detail == WC_DOWN:
  231.             self.do_down()
  232.     
  233.     def mouse_down(self, detail):
  234.         (h, v), clicks, button, mask = detail
  235.         i = v / stdwin.lineheight()
  236.         if 0 <= i < len(self.stack):
  237.             if i != self.curindex:
  238.                 self.curindex = i
  239.                 self.curframe = self.stack[self.curindex][0]
  240.                 self.refreshstack()
  241.             elif clicks == 2:
  242.                 self.do_frame()
  243.         else:
  244.             stdwin.fleep()
  245.     
  246.     def draw(self, detail):
  247.         import linecache, string
  248.         d = self.win.begindrawing()
  249.         try:
  250.             h, v = 0, 0
  251.             for f, lineno in self.stack:
  252.                 fn = f.f_code.co_filename
  253.                 if f is self.curframe:
  254.                     s = '> '
  255.                 else:
  256.                     s = '  '
  257.                 s = s + fn + '(' + `lineno` + ')'
  258.                 s = s + f.f_code.co_name
  259.                 if f.f_locals.has_key('__args__'):
  260.                     args = f.f_locals['__args__']
  261.                     if args is not None:
  262.                         s = s + repr.repr(args)
  263.                 if f.f_locals.has_key('__return__'):
  264.                     rv = f.f_locals['__return__']
  265.                     s = s + '->'
  266.                     s = s + repr.repr(rv)
  267.                 line = linecache.getline(fn, lineno)
  268.                 if line: s = s + ': ' + string.strip(line)
  269.                 d.text((h, v), s)
  270.                 v = v + d.lineheight()
  271.         finally:
  272.             d.close()
  273.  
  274.  
  275. # Simplified interface
  276.  
  277. def run(statement, globals=None, locals=None):
  278.     x = Wdb()
  279.     try: x.run(statement, globals, locals)
  280.     finally: x.close()
  281.  
  282. def runeval(expression, globals=None, locals=None):
  283.     x = Wdb()
  284.     try: return x.runeval(expression, globals, locals)
  285.     finally: x.close()
  286.  
  287. def runctx(statement, globals, locals):
  288.     # B/W compatibility
  289.     run(statement, globals, locals)
  290.  
  291. def runcall(*args):
  292.     x = Wdb()
  293.     try: return apply(x.runcall, args)
  294.     finally: x.close()
  295.  
  296. def set_trace():
  297.     Wdb().set_trace()
  298.  
  299. # Post-Mortem interface
  300.  
  301. def post_mortem(traceback):
  302.     x = Wdb()
  303.     x.reset()
  304.     x.interaction(None, traceback)
  305.  
  306. def pm():
  307.     import sys
  308.     post_mortem(sys.last_traceback)
  309.  
  310.  
  311. # Main program for testing
  312.  
  313. TESTCMD = 'import x; x.main()'
  314.  
  315. def test():
  316.     run(TESTCMD)
  317.