home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / Debugger.py < prev    next >
Text File  |  2003-12-30  |  15KB  |  476 lines

  1. import os
  2. import bdb
  3. import types
  4. from Tkinter import *
  5. from WindowList import ListedToplevel
  6. from ScrolledList import ScrolledList
  7.  
  8.  
  9. class Idb(bdb.Bdb):
  10.  
  11.     def __init__(self, gui):
  12.         self.gui = gui
  13.         bdb.Bdb.__init__(self)
  14.  
  15.     def user_line(self, frame):
  16.         if self.in_rpc_code(frame):
  17.             self.set_step()
  18.             return
  19.         message = self.__frame2message(frame)
  20.         self.gui.interaction(message, frame)
  21.  
  22.     def user_exception(self, frame, info):
  23.         if self.in_rpc_code(frame):
  24.             self.set_step()
  25.             return
  26.         message = self.__frame2message(frame)
  27.         self.gui.interaction(message, frame, info)
  28.  
  29.     def in_rpc_code(self, frame):
  30.         if frame.f_code.co_filename.count('rpc.py'):
  31.             return True
  32.         else:
  33.             prev_frame = frame.f_back
  34.             if prev_frame.f_code.co_filename.count('Debugger.py'):
  35.                 # (that test will catch both Debugger.py and RemoteDebugger.py)
  36.                 return False
  37.             return self.in_rpc_code(prev_frame)
  38.  
  39.     def __frame2message(self, frame):
  40.         code = frame.f_code
  41.         filename = code.co_filename
  42.         lineno = frame.f_lineno
  43.         basename = os.path.basename(filename)
  44.         message = "%s:%s" % (basename, lineno)
  45.         if code.co_name != "?":
  46.             message = "%s: %s()" % (message, code.co_name)
  47.         return message
  48.  
  49.  
  50. class Debugger:
  51.  
  52.     vstack = vsource = vlocals = vglobals = None
  53.  
  54.     def __init__(self, pyshell, idb=None):
  55.         if idb is None:
  56.             idb = Idb(self)
  57.         self.pyshell = pyshell
  58.         self.idb = idb
  59.         self.frame = None
  60.         self.make_gui()
  61.         self.interacting = 0
  62.  
  63.     def run(self, *args):
  64.         try:
  65.             self.interacting = 1
  66.             return self.idb.run(*args)
  67.         finally:
  68.             self.interacting = 0
  69.  
  70.     def close(self, event=None):
  71.         if self.interacting:
  72.             self.top.bell()
  73.             return
  74.         if self.stackviewer:
  75.             self.stackviewer.close(); self.stackviewer = None
  76.         # Clean up pyshell if user clicked debugger control close widget.
  77.         # (Causes a harmless extra cycle through close_debugger() if user
  78.         # toggled debugger from pyshell Debug menu)
  79.         self.pyshell.close_debugger()
  80.         # Now close the debugger control window....
  81.         self.top.destroy()
  82.  
  83.     def make_gui(self):
  84.         pyshell = self.pyshell
  85.         self.flist = pyshell.flist
  86.         self.root = root = pyshell.root
  87.         self.top = top =ListedToplevel(root)
  88.         self.top.wm_title("Debug Control")
  89.         self.top.wm_iconname("Debug")
  90.         top.wm_protocol("WM_DELETE_WINDOW", self.close)
  91.         self.top.bind("<Escape>", self.close)
  92.         #
  93.         self.bframe = bframe = Frame(top)
  94.         self.bframe.pack(anchor="w")
  95.         self.buttons = bl = []
  96.         #
  97.         self.bcont = b = Button(bframe, text="Go", command=self.cont)
  98.         bl.append(b)
  99.         self.bstep = b = Button(bframe, text="Step", command=self.step)
  100.         bl.append(b)
  101.         self.bnext = b = Button(bframe, text="Over", command=self.next)
  102.         bl.append(b)
  103.         self.bret = b = Button(bframe, text="Out", command=self.ret)
  104.         bl.append(b)
  105.         self.bret = b = Button(bframe, text="Quit", command=self.quit)
  106.         bl.append(b)
  107.         #
  108.         for b in bl:
  109.             b.configure(state="disabled")
  110.             b.pack(side="left")
  111.         #
  112.         self.cframe = cframe = Frame(bframe)
  113.         self.cframe.pack(side="left")
  114.         #
  115.         if not self.vstack:
  116.             self.__class__.vstack = BooleanVar(top)
  117.             self.vstack.set(1)
  118.         self.bstack = Checkbutton(cframe,
  119.             text="Stack", command=self.show_stack, variable=self.vstack)
  120.         self.bstack.grid(row=0, column=0)
  121.         if not self.vsource:
  122.             self.__class__.vsource = BooleanVar(top)
  123.         self.bsource = Checkbutton(cframe,
  124.             text="Source", command=self.show_source, variable=self.vsource)
  125.         self.bsource.grid(row=0, column=1)
  126.         if not self.vlocals:
  127.             self.__class__.vlocals = BooleanVar(top)
  128.             self.vlocals.set(1)
  129.         self.blocals = Checkbutton(cframe,
  130.             text="Locals", command=self.show_locals, variable=self.vlocals)
  131.         self.blocals.grid(row=1, column=0)
  132.         if not self.vglobals:
  133.             self.__class__.vglobals = BooleanVar(top)
  134.         self.bglobals = Checkbutton(cframe,
  135.             text="Globals", command=self.show_globals, variable=self.vglobals)
  136.         self.bglobals.grid(row=1, column=1)
  137.         #
  138.         self.status = Label(top, anchor="w")
  139.         self.status.pack(anchor="w")
  140.         self.error = Label(top, anchor="w")
  141.         self.error.pack(anchor="w", fill="x")
  142.         self.errorbg = self.error.cget("background")
  143.         #
  144.         self.fstack = Frame(top, height=1)
  145.         self.fstack.pack(expand=1, fill="both")
  146.         self.flocals = Frame(top)
  147.         self.flocals.pack(expand=1, fill="both")
  148.         self.fglobals = Frame(top, height=1)
  149.         self.fglobals.pack(expand=1, fill="both")
  150.         #
  151.         if self.vstack.get():
  152.             self.show_stack()
  153.         if self.vlocals.get():
  154.             self.show_locals()
  155.         if self.vglobals.get():
  156.             self.show_globals()
  157.  
  158.  
  159.     def interaction(self, message, frame, info=None):
  160.         self.frame = frame
  161.         self.status.configure(text=message)
  162.         #
  163.         if info:
  164.             type, value, tb = info
  165.             try:
  166.                 m1 = type.__name__
  167.             except AttributeError:
  168.                 m1 = "%s" % str(type)
  169.             if value is not None:
  170.                 try:
  171.                     m1 = "%s: %s" % (m1, str(value))
  172.                 except:
  173.                     pass
  174.             bg = "yellow"
  175.         else:
  176.             m1 = ""
  177.             tb = None
  178.             bg = self.errorbg
  179.         self.error.configure(text=m1, background=bg)
  180.         #
  181.         sv = self.stackviewer
  182.         if sv:
  183.             stack, i = self.idb.get_stack(self.frame, tb)
  184.             sv.load_stack(stack, i)
  185.         #
  186.         self.show_variables(1)
  187.         #
  188.         if self.vsource.get():
  189.             self.sync_source_line()
  190.         #
  191.         for b in self.buttons:
  192.             b.configure(state="normal")
  193.         #
  194.         self.top.tkraise()
  195.         self.root.mainloop()
  196.         #
  197.         for b in self.buttons:
  198.             b.configure(state="disabled")
  199.         self.status.configure(text="")
  200.         self.error.configure(text="", background=self.errorbg)
  201.         self.frame = None
  202.  
  203.     def sync_source_line(self):
  204.         frame = self.frame
  205.         if not frame:
  206.             return
  207.         filename, lineno = self.__frame2fileline(frame)
  208.         if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
  209.             self.flist.gotofileline(filename, lineno)
  210.  
  211.     def __frame2fileline(self, frame):
  212.         code = frame.f_code
  213.         filename = code.co_filename
  214.         lineno = frame.f_lineno
  215.         return filename, lineno
  216.  
  217.     def cont(self):
  218.         self.idb.set_continue()
  219.         self.root.quit()
  220.  
  221.     def step(self):
  222.         self.idb.set_step()
  223.         self.root.quit()
  224.  
  225.     def next(self):
  226.         self.idb.set_next(self.frame)
  227.         self.root.quit()
  228.  
  229.     def ret(self):
  230.         self.idb.set_return(self.frame)
  231.         self.root.quit()
  232.  
  233.     def quit(self):
  234.         self.idb.set_quit()
  235.         self.root.quit()
  236.  
  237.     stackviewer = None
  238.  
  239.     def show_stack(self):
  240.         if not self.stackviewer and self.vstack.get():
  241.             self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
  242.             if self.frame:
  243.                 stack, i = self.idb.get_stack(self.frame, None)
  244.                 sv.load_stack(stack, i)
  245.         else:
  246.             sv = self.stackviewer
  247.             if sv and not self.vstack.get():
  248.                 self.stackviewer = None
  249.                 sv.close()
  250.             self.fstack['height'] = 1
  251.  
  252.     def show_source(self):
  253.         if self.vsource.get():
  254.             self.sync_source_line()
  255.  
  256.     def show_frame(self, (frame, lineno)):
  257.         self.frame = frame
  258.         self.show_variables()
  259.  
  260.     localsviewer = None
  261.     globalsviewer = None
  262.  
  263.     def show_locals(self):
  264.         lv = self.localsviewer
  265.         if self.vlocals.get():
  266.             if not lv:
  267.                 self.localsviewer = NamespaceViewer(self.flocals, "Locals")
  268.         else:
  269.             if lv:
  270.                 self.localsviewer = None
  271.                 lv.close()
  272.                 self.flocals['height'] = 1
  273.         self.show_variables()
  274.  
  275.     def show_globals(self):
  276.         gv = self.globalsviewer
  277.         if self.vglobals.get():
  278.             if not gv:
  279.                 self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
  280.         else:
  281.             if gv:
  282.                 self.globalsviewer = None
  283.                 gv.close()
  284.                 self.fglobals['height'] = 1
  285.         self.show_variables()
  286.  
  287.     def show_variables(self, force=0):
  288.         lv = self.localsviewer
  289.         gv = self.globalsviewer
  290.         frame = self.frame
  291.         if not frame:
  292.             ldict = gdict = None
  293.         else:
  294.             ldict = frame.f_locals
  295.             gdict = frame.f_globals
  296.             if lv and gv and ldict is gdict:
  297.                 ldict = None
  298.         if lv:
  299.             lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
  300.         if gv:
  301.             gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
  302.  
  303.     def set_breakpoint_here(self, filename, lineno):
  304.         self.idb.set_break(filename, lineno)
  305.  
  306.     def clear_breakpoint_here(self, filename, lineno):
  307.         self.idb.clear_break(filename, lineno)
  308.  
  309.     def clear_file_breaks(self, filename):
  310.         self.idb.clear_all_file_breaks(filename)
  311.  
  312.     def load_breakpoints(self):
  313.         "Load PyShellEditorWindow breakpoints into subprocess debugger"
  314.         pyshell_edit_windows = self.pyshell.flist.inversedict.keys()
  315.         for editwin in pyshell_edit_windows:
  316.             filename = editwin.io.filename
  317.             try:
  318.                 for lineno in editwin.breakpoints:
  319.                     self.set_breakpoint_here(filename, lineno)
  320.             except AttributeError:
  321.                 continue
  322.  
  323. class StackViewer(ScrolledList):
  324.  
  325.     def __init__(self, master, flist, gui):
  326.         ScrolledList.__init__(self, master, width=80)
  327.         self.flist = flist
  328.         self.gui = gui
  329.         self.stack = []
  330.  
  331.     def load_stack(self, stack, index=None):
  332.         self.stack = stack
  333.         self.clear()
  334.         for i in range(len(stack)):
  335.             frame, lineno = stack[i]
  336.             try:
  337.                 modname = frame.f_globals["__name__"]
  338.             except:
  339.                 modname = "?"
  340.             code = frame.f_code
  341.             filename = code.co_filename
  342.             funcname = code.co_name
  343.             import linecache
  344.             sourceline = linecache.getline(filename, lineno)
  345.             import string
  346.             sourceline = string.strip(sourceline)
  347.             if funcname in ("?", "", None):
  348.                 item = "%s, line %d: %s" % (modname, lineno, sourceline)
  349.             else:
  350.                 item = "%s.%s(), line %d: %s" % (modname, funcname,
  351.                                                  lineno, sourceline)
  352.             if i == index:
  353.                 item = "> " + item
  354.             self.append(item)
  355.         if index is not None:
  356.             self.select(index)
  357.  
  358.     def popup_event(self, event):
  359.         "override base method"
  360.         if self.stack:
  361.             return ScrolledList.popup_event(self, event)
  362.  
  363.     def fill_menu(self):
  364.         "override base method"
  365.         menu = self.menu
  366.         menu.add_command(label="Go to source line",
  367.                          command=self.goto_source_line)
  368.         menu.add_command(label="Show stack frame",
  369.                          command=self.show_stack_frame)
  370.  
  371.     def on_select(self, index):
  372.         "override base method"
  373.         if 0 <= index < len(self.stack):
  374.             self.gui.show_frame(self.stack[index])
  375.  
  376.     def on_double(self, index):
  377.         "override base method"
  378.         self.show_source(index)
  379.  
  380.     def goto_source_line(self):
  381.         index = self.listbox.index("active")
  382.         self.show_source(index)
  383.  
  384.     def show_stack_frame(self):
  385.         index = self.listbox.index("active")
  386.         if 0 <= index < len(self.stack):
  387.             self.gui.show_frame(self.stack[index])
  388.  
  389.     def show_source(self, index):
  390.         if not (0 <= index < len(self.stack)):
  391.             return
  392.         frame, lineno = self.stack[index]
  393.         code = frame.f_code
  394.         filename = code.co_filename
  395.         if os.path.isfile(filename):
  396.             edit = self.flist.open(filename)
  397.             if edit:
  398.                 edit.gotoline(lineno)
  399.  
  400.  
  401. class NamespaceViewer:
  402.  
  403.     def __init__(self, master, title, dict=None):
  404.         width = 0
  405.         height = 40
  406.         if dict:
  407.             height = 20*len(dict) # XXX 20 == observed height of Entry widget
  408.         self.master = master
  409.         self.title = title
  410.         import repr
  411.         self.repr = repr.Repr()
  412.         self.repr.maxstring = 60
  413.         self.repr.maxother = 60
  414.         self.frame = frame = Frame(master)
  415.         self.frame.pack(expand=1, fill="both")
  416.         self.label = Label(frame, text=title, borderwidth=2, relief="groove")
  417.         self.label.pack(fill="x")
  418.         self.vbar = vbar = Scrollbar(frame, name="vbar")
  419.         vbar.pack(side="right", fill="y")
  420.         self.canvas = canvas = Canvas(frame,
  421.                                       height=min(300, max(40, height)),
  422.                                       scrollregion=(0, 0, width, height))
  423.         canvas.pack(side="left", fill="both", expand=1)
  424.         vbar["command"] = canvas.yview
  425.         canvas["yscrollcommand"] = vbar.set
  426.         self.subframe = subframe = Frame(canvas)
  427.         self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
  428.         self.load_dict(dict)
  429.  
  430.     dict = -1
  431.  
  432.     def load_dict(self, dict, force=0, rpc_client=None):
  433.         if dict is self.dict and not force:
  434.             return
  435.         subframe = self.subframe
  436.         frame = self.frame
  437.         for c in subframe.children.values():
  438.             c.destroy()
  439.         self.dict = None
  440.         if not dict:
  441.             l = Label(subframe, text="None")
  442.             l.grid(row=0, column=0)
  443.         else:
  444.             names = dict.keys()
  445.             names.sort()
  446.             row = 0
  447.             for name in names:
  448.                 value = dict[name]
  449.                 svalue = self.repr.repr(value) # repr(value)
  450.                 # Strip extra quotes caused by calling repr on the (already)
  451.                 # repr'd value sent across the RPC interface:
  452.                 if rpc_client:
  453.                     svalue = svalue[1:-1]
  454.                 l = Label(subframe, text=name)
  455.                 l.grid(row=row, column=0, sticky="nw")
  456.                 l = Entry(subframe, width=0, borderwidth=0)
  457.                 l.insert(0, svalue)
  458.                 l.grid(row=row, column=1, sticky="nw")
  459.                 row = row+1
  460.         self.dict = dict
  461.         # XXX Could we use a <Configure> callback for the following?
  462.         subframe.update_idletasks() # Alas!
  463.         width = subframe.winfo_reqwidth()
  464.         height = subframe.winfo_reqheight()
  465.         canvas = self.canvas
  466.         self.canvas["scrollregion"] = (0, 0, width, height)
  467.         if height > 300:
  468.             canvas["height"] = 300
  469.             frame.pack(expand=1)
  470.         else:
  471.             canvas["height"] = height
  472.             frame.pack(expand=0)
  473.  
  474.     def close(self):
  475.         self.frame.destroy()
  476.