home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Lib / stdwin / wdb.py < prev    next >
Text File  |  1994-03-15  |  7KB  |  308 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.         self.settitle(exc_type + ': ' + repr.repr(exc_value))
  79.         stdwin.fleep()
  80.         self.interaction(frame, exc_traceback)
  81.         if not self.closed:
  82.             self.settitle('--Stack--')
  83.     
  84.     # Change the title
  85.     
  86.     def settitle(self, title):
  87.         self.savetitle = self.win.gettitle()
  88.         self.win.settitle(title)
  89.     
  90.     # General interaction function
  91.     
  92.     def interaction(self, frame, traceback):
  93.         import mainloop
  94.         self.popup()
  95.         self.setup(frame, traceback)
  96.         try:
  97.             mainloop.mainloop()
  98.         except WdbDone:
  99.             pass
  100.         self.forget()
  101.     
  102.     # Functions whose name is do_X for some character X
  103.     # are callable directly from the keyboard.
  104.     
  105.     def do_up(self):
  106.         if self.curindex == 0:
  107.             stdwin.fleep()
  108.         else:
  109.             self.curindex = self.curindex - 1
  110.             self.curframe = self.stack[self.curindex][0]
  111.             self.refreshstack()
  112.     do_u = do_up
  113.     
  114.     def do_down(self):
  115.         if self.curindex + 1 == len(self.stack):
  116.             stdwin.fleep()
  117.         else:
  118.             self.curindex = self.curindex + 1
  119.             self.curframe = self.stack[self.curindex][0]
  120.             self.refreshstack()
  121.     do_d = do_down
  122.     
  123.     def do_step(self):
  124.         self.set_step()
  125.         raise WdbDone
  126.     do_s = do_step
  127.     
  128.     def do_next(self):
  129.         self.set_next(self.curframe)
  130.         raise WdbDone
  131.     do_n = do_next
  132.     
  133.     def do_return(self):
  134.         self.set_return(self.curframe)
  135.         raise WdbDone
  136.     do_r = do_return
  137.     
  138.     def do_continue(self):
  139.         self.set_continue()
  140.         raise WdbDone
  141.     do_c = do_cont = do_continue
  142.     
  143.     def do_quit(self):
  144.         self.close()
  145.         raise WdbDone
  146.     do_q = do_quit
  147.     
  148.     def do_list(self):
  149.         fn = self.curframe.f_code.co_filename
  150.         if not self.sourcewindows.has_key(fn):
  151.             import wdbsrcwin
  152.             try:
  153.                 self.sourcewindows[fn] = wdbsrcwin. \
  154.                       DebuggerSourceWindow(self, fn)
  155.             except IOError:
  156.                 stdwin.fleep()
  157.                 return
  158.         w = self.sourcewindows[fn]
  159.         lineno = self.stack[self.curindex][1]
  160.         w.setlineno(lineno)
  161.         w.popup()
  162.     do_l = do_list
  163.     
  164.     def do_frame(self):
  165.         name = 'locals' + `self.curframe`[16:-1]
  166.         if self.framewindows.has_key(name):
  167.             self.framewindows[name].popup()
  168.         else:
  169.             import wdbframewin
  170.             self.framewindows[name] = \
  171.                 wdbframewin.FrameWindow(self, \
  172.                     self.curframe, \
  173.                     self.curframe.f_locals, name)
  174.     do_f = do_frame
  175.     
  176.     def do_globalframe(self):
  177.         name = 'globals' + `self.curframe`[16:-1]
  178.         if self.framewindows.has_key(name):
  179.             self.framewindows[name].popup()
  180.         else:
  181.             import wdbframewin
  182.             self.framewindows[name] = \
  183.                 wdbframewin.FrameWindow(self, \
  184.                     self.curframe, \
  185.                     self.curframe.f_globals, name)
  186.     do_g = do_globalframe
  187.     
  188.     # Link between the debugger and the window
  189.     
  190.     def refreshstack(self):
  191.         height = stdwin.lineheight() * (1 + len(self.stack))
  192.         self.win.setdocsize((0, height))
  193.         self.refreshall() # XXX be more subtle later
  194.         # Also pass the information on to the source windows
  195.         filename = self.curframe.f_code.co_filename
  196.         lineno = self.curframe.f_lineno
  197.         for fn in self.sourcewindows.keys():
  198.             w = self.sourcewindows[fn]
  199.             if fn == filename:
  200.                 w.setlineno(lineno)
  201.             else:
  202.                 w.resetlineno()
  203.     
  204.     # The remaining methods override BaseWindow methods
  205.     
  206.     def close(self):
  207.         if not self.closed:
  208.             basewin.BaseWindow.close(self)
  209.         self.closed = 1
  210.         for key in self.sourcewindows.keys():
  211.             self.sourcewindows[key].close()
  212.         for key in self.framewindows.keys():
  213.             self.framewindows[key].close()
  214.         self.set_quit()
  215.     
  216.     def char(self, detail):
  217.         try:
  218.             func = eval('self.do_' + detail)
  219.         except (AttributeError, SyntaxError):
  220.             stdwin.fleep()
  221.             return
  222.         func()
  223.     
  224.     def command(self, detail):
  225.         if detail == WC_UP:
  226.             self.do_up()
  227.         elif detail == WC_DOWN:
  228.             self.do_down()
  229.     
  230.     def mouse_down(self, detail):
  231.         (h, v), clicks, button, mask = detail
  232.         i = v / stdwin.lineheight()
  233.         if 0 <= i < len(self.stack):
  234.             if i != self.curindex:
  235.                 self.curindex = i
  236.                 self.curframe = self.stack[self.curindex][0]
  237.                 self.refreshstack()
  238.             elif clicks == 2:
  239.                 self.do_frame()
  240.         else:
  241.             stdwin.fleep()
  242.     
  243.     def draw(self, detail):
  244.         import linecache, string
  245.         d = self.win.begindrawing()
  246.         try:
  247.             h, v = 0, 0
  248.             for f, lineno in self.stack:
  249.                 fn = f.f_code.co_filename
  250.                 if f is self.curframe:
  251.                     s = '> '
  252.                 else:
  253.                     s = '  '
  254.                 s = s + fn + '(' + `lineno` + ')'
  255.                 s = s + f.f_code.co_name
  256.                 if f.f_locals.has_key('__args__'):
  257.                     args = f.f_locals['__args__']
  258.                     if args is not None:
  259.                         s = s + repr.repr(args)
  260.                 if f.f_locals.has_key('__return__'):
  261.                     rv = f.f_locals['__return__']
  262.                     s = s + '->'
  263.                     s = s + repr.repr(rv)
  264.                 line = linecache.getline(fn, lineno)
  265.                 if line: s = s + ': ' + string.strip(line)
  266.                 d.text((h, v), s)
  267.                 v = v + d.lineheight()
  268.         finally:
  269.             d.close()
  270.  
  271.  
  272. # Simplified interface
  273.  
  274. def run(statement):
  275.     x = Wdb()
  276.     try: x.run(statement)
  277.     finally: x.close()
  278.  
  279. def runctx(statement, globals, locals):
  280.     x = Wdb()
  281.     try: x.runctx(statement, globals, locals)
  282.     finally: x.close()
  283.  
  284. def runcall(*args):
  285.     x = Wdb()
  286.     try: apply(x.runcall, args)
  287.     finally: x.close()
  288.  
  289.  
  290. # Post-Mortem interface
  291.  
  292. def post_mortem(traceback):
  293.     x = Wdb()
  294.     x.reset()
  295.     x.interaction(None, traceback)
  296.  
  297. def pm():
  298.     import sys
  299.     post_mortem(sys.last_traceback)
  300.  
  301.  
  302. # Main program for testing
  303.  
  304. TESTCMD = 'import x; x.main()'
  305.  
  306. def test():
  307.     run(TESTCMD)
  308.