leo_Debugger.py :  » Development » Leo » Leo-4.7.1-final » leo » core » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » Leo 
Leo » Leo 4.7.1 final » leo » core » leo_Debugger.py
#@+leo-ver=4-thin
#@+node:ekr.20060516135654.94:@thin leo_Debugger.py
#@<< imports >>
#@+node:ekr.20060516135654.95:<< imports >>
import leoGlobals as g

import leo_FileList
import leo_run
import leo_RemoteDebugger
import leo_Shell

import idlelib.ScrolledList as ScrolledList

import bdb
import os
import socket
import sys
import time
import types

import Tkinter as Tk
import tkMessageBox

import __main__
#@nonl
#@-node:ekr.20060516135654.95:<< imports >>
#@nl

LOCALHOST = '127.0.0.1'

#@+others
#@+node:ekr.20060516142615.4:go
def go (c):
    
    # From Pyshell.ctor
    interp = leo_Shell.ModifiedInterpreter(dummyShell(c))
    
    # From Pyshell.begin:
    client = interp.start_subprocess()
    g.trace('client',client,'interp',interp)
    open_debugger(c,interp.rpcclt,interp)
#@nonl
#@-node:ekr.20060516142615.4:go
#@+node:ekr.20060516142615.5:open_debugger
def open_debugger(c,rpcClient,interp):

    dbg_gui = leo_RemoteDebugger.start_remote_debugger(c,rpcClient,interp)
    interp.setdebugger(dbg_gui)
    dbg_gui.load_breakpoints()

    if 0: ### old code
        if self.interp.rpcclt:
            dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,self)
        else:
            dbg_gui = Debugger.Debugger(self)
        self.interp.setdebugger(dbg_gui)
        dbg_gui.load_breakpoints()
        sys.ps1 = "[DEBUG ON]\n>>> "
        self.showprompt()
        self.set_debugger_indicator()
#@nonl
#@-node:ekr.20060516142615.5:open_debugger
#@+node:ekr.20060516142615.6:class dummyShell
class dummyShell:
    
    def __init__ (self,c):
        self.c = c
        self.stdout = sys.__stdout__
        self.stderr = sys.__stderr__
        self.flist = []
        self.closing = False
        self.executing = False
        self.text = Tk.Text() # Ignored completely
        self.pollinterval = 50  # millisec
        # g.trace('dummyShell')
#@nonl
#@-node:ekr.20060516142615.6:class dummyShell
#@+node:ekr.20060516135654.163:class Idb (used by remote debugger code)
# Important: this class is used by the remote debugger code.

class Idb(bdb.Bdb):
    
    #@  @+others
    #@+node:ekr.20060516135654.164:__init__
    def __init__(self, gui):
    
        self.gui = gui
        bdb.Bdb.__init__(self)
    #@nonl
    #@-node:ekr.20060516135654.164:__init__
    #@+node:ekr.20060516135654.165:user_line
    def user_line(self, frame):
        
        if self.in_rpc_code(frame):
            self.set_step()
        else:
            message = self.__frame2message(frame)
            self.gui.interaction(message, frame)
    #@nonl
    #@-node:ekr.20060516135654.165:user_line
    #@+node:ekr.20060516135654.166:user_exception
    def user_exception(self, frame, info):
        
        if self.in_rpc_code(frame):
            self.set_step()
        else:
            message = self.__frame2message(frame)
            self.gui.interaction(message, frame, info)
    #@nonl
    #@-node:ekr.20060516135654.166:user_exception
    #@+node:ekr.20060516135654.167:in_rpc_code
    def in_rpc_code(self, frame):
    
        if frame.f_code.co_filename.count('rpc.py'):
            return True
        else:
            prev_frame = frame.f_back
            if prev_frame.f_code.co_filename.count('Debugger.py'):
                # (that test will catch both Debugger.py and RemoteDebugger.py)
                return False
            return self.in_rpc_code(prev_frame)
    #@-node:ekr.20060516135654.167:in_rpc_code
    #@+node:ekr.20060516135654.168:__frame2message
    def __frame2message(self, frame):
    
        code = frame.f_code
        filename = code.co_filename
        lineno = frame.f_lineno
        basename = os.path.basename(filename)
        message = "%s:%s" % (basename, lineno)
        if code.co_name != "?":
            message = "%s: %s()" % (message, code.co_name)
        return message
    #@nonl
    #@-node:ekr.20060516135654.168:__frame2message
    #@-others
#@-node:ekr.20060516135654.163:class Idb (used by remote debugger code)
#@+node:ekr.20060516135654.169:class StackViewer
class StackViewer(ScrolledList.ScrolledList):
    #@  @+others
    #@+node:ekr.20060516135654.170:__init__
    def __init__(self, master, flist, gui):
        
        g.trace('StackViewer: flist',flist,g.callers())
        
        ScrolledList.ScrolledList.__init__(self, master, width=80)
        self.flist = flist
        self.gui = gui
        self.stack = []
    #@nonl
    #@-node:ekr.20060516135654.170:__init__
    #@+node:ekr.20060516135654.171:load_stack
    def load_stack(self, stack, index=None):
        self.stack = stack
        self.clear()
        for i in range(len(stack)):
            frame, lineno = stack[i]
            try:
                modname = frame.f_globals["__name__"]
            except:
                modname = "?"
            code = frame.f_code
            filename = code.co_filename
            funcname = code.co_name
            import linecache
            sourceline = linecache.getline(filename, lineno)
            import string
            sourceline = string.strip(sourceline)
            if funcname in ("?", "", None):
                item = "%s, line %d: %s" % (modname, lineno, sourceline)
            else:
                item = "%s.%s(), line %d: %s" % (modname, funcname,
                                                 lineno, sourceline)
            if i == index:
                item = "> " + item
            self.append(item)
        if index is not None:
            self.select(index)
    #@-node:ekr.20060516135654.171:load_stack
    #@+node:ekr.20060516135654.172:popup_event
    def popup_event(self, event):
        "override base method"
        if self.stack:
            return ScrolledList.ScrolledList.popup_event(self, event)
    #@-node:ekr.20060516135654.172:popup_event
    #@+node:ekr.20060516135654.173:fill_menu
    def fill_menu(self):
        "override base method"
        menu = self.menu
        menu.add_command(label="Go to source line",
                         command=self.goto_source_line)
        menu.add_command(label="Show stack frame",
                         command=self.show_stack_frame)
    #@-node:ekr.20060516135654.173:fill_menu
    #@+node:ekr.20060516135654.174:on_select
    def on_select(self, index):
        "override base method"
        if 0 <= index < len(self.stack):
            self.gui.show_frame(self.stack[index])
    #@-node:ekr.20060516135654.174:on_select
    #@+node:ekr.20060516135654.175:on_double
    def on_double(self, index):
        "override base method"
        self.show_source(index)
    #@-node:ekr.20060516135654.175:on_double
    #@+node:ekr.20060516135654.176:goto_source_line
    def goto_source_line(self):
    
        index = self.listbox.index("active")
        self.show_source(index)
    #@-node:ekr.20060516135654.176:goto_source_line
    #@+node:ekr.20060516135654.177:show_stack_frame
    def show_stack_frame(self):
        index = self.listbox.index("active")
        if 0 <= index < len(self.stack):
            self.gui.show_frame(self.stack[index])
    #@-node:ekr.20060516135654.177:show_stack_frame
    #@+node:ekr.20060516135654.178:show_source
    def show_source(self, index):
        if not (0 <= index < len(self.stack)):
            return
        frame, lineno = self.stack[index]
        code = frame.f_code
        filename = code.co_filename
        if os.path.isfile(filename):
            edit = self.flist.open(filename)
            if edit:
                edit.gotoline(lineno)
    #@-node:ekr.20060516135654.178:show_source
    #@-others
#@-node:ekr.20060516135654.169:class StackViewer
#@+node:ekr.20060516135654.179:class NamespaceViewer


class NamespaceViewer:
    #@  @+others
    #@+node:ekr.20060516135654.180:__init__
    def __init__(self, master, title, dict=None):
        
        g.trace('NamespaceViewer','dict',dict,g.callers())
    
        width = 0
        height = 40
        if dict:
            height = 20*len(dict) # XXX 20 == observed height of Entry widget
        self.master = master
        self.title = title
        import repr
        self.repr = repr.Repr()
        self.repr.maxstring = 60
        self.repr.maxother = 60
        self.frame = frame = Tk.Frame(master)
        self.frame.pack(expand=1, fill="both")
        self.label = Tk.Label(frame, text=title, borderwidth=2, relief="groove")
        self.label.pack(fill="x")
        self.vbar = vbar = Tk.Scrollbar(frame, name="vbar")
        vbar.pack(side="right", fill="y")
        self.canvas = canvas = Tk.Canvas(frame,
                                      height=min(300, max(40, height)),
                                      scrollregion=(0, 0, width, height))
        canvas.pack(side="left", fill="both", expand=1)
        vbar["command"] = canvas.yview
        canvas["yscrollcommand"] = vbar.set
        self.subframe = subframe = Tk.Frame(canvas)
        self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
        self.load_dict(dict)
    #@nonl
    #@-node:ekr.20060516135654.180:__init__
    #@+node:ekr.20060516135654.181:load_dict
    dict = -1
    
    def load_dict(self, dict, force=0, rpc_client=None):
        if dict is self.dict and not force:
            return
        subframe = self.subframe
        frame = self.frame
        for c in subframe.children.values():
            c.destroy()
        self.dict = None
        if not dict:
            l = Tk.Label(subframe, text="None")
            l.grid(row=0, column=0)
        else:
            names = dict.keys()
            names.sort()
            row = 0
            for name in names:
                value = dict[name]
                svalue = self.repr.repr(value) # repr(value)
                # Strip extra quotes caused by calling repr on the (already)
                # repr'd value sent across the RPC interface:
                if rpc_client:
                    svalue = svalue[1:-1]
                l = Tk.Label(subframe, text=name)
                l.grid(row=row, column=0, sticky="nw")
                l = Entry(subframe, width=0, borderwidth=0)
                l.insert(0, svalue)
                l.grid(row=row, column=1, sticky="nw")
                row = row+1
        self.dict = dict
        # XXX Could we use a <Configure> callback for the following?
        subframe.update_idletasks() # Alas!
        width = subframe.winfo_reqwidth()
        height = subframe.winfo_reqheight()
        canvas = self.canvas
        self.canvas["scrollregion"] = (0, 0, width, height)
        if height > 300:
            canvas["height"] = 300
            frame.pack(expand=1)
        else:
            canvas["height"] = height
            frame.pack(expand=0)
    
    #@-node:ekr.20060516135654.181:load_dict
    #@+node:ekr.20060516135654.182:close
    def close(self):
        self.frame.destroy()
    #@-node:ekr.20060516135654.182:close
    #@-others
#@-node:ekr.20060516135654.179:class NamespaceViewer
#@+node:ekr.20060516135654.183:class Debugger
class Debugger:

    vstack = vsource = vlocals = vglobals = None

    #@    @+others
    #@+node:ekr.20060516135654.184:Birth
    #@+node:ekr.20060516135654.185:__init__
    def __init__(self, c, interp, idb=None):
        
        self.c = c
        
        # Were inited as needed.
        self.globalsviewer = None
        self.interacting = 0
        self.localsviewer = None
        self.stackviewer = None
    
        ###self.pyshell = pyshell
        self.interp = interp
        self.idb = idb or Idb(self)
        self.frame = None
        
        ### self.flist = pyshell.flist
        self.flist = leo_FileList.FileList(c)
        self.make_gui()
        
        g.trace('Debugger',interp,self.idb)
    #@nonl
    #@-node:ekr.20060516135654.185:__init__
    #@+node:ekr.20060516135654.186:make_gui
    def make_gui(self):
        
        #@    << create the top level frame >>
        #@+node:ekr.20060516135654.187:<< create the top level frame >>
        self.root = root = g.app.root
        self.top = top = Tk.Toplevel(self.root)
        top.title("Leo Debug Control")
        top.wm_iconname("Debug")
        top.wm_protocol("WM_DELETE_WINDOW", self.close)
        # self.top.bind("<Escape>", self.close)
        #@nonl
        #@-node:ekr.20060516135654.187:<< create the top level frame >>
        #@nl
        #@    << create the control buttons >>
        #@+node:ekr.20060516135654.188:<< create the control buttons >>
        self.bframe = bframe = Tk.Frame(top)
        self.bframe.pack(anchor="w")
        self.buttons = bl = []
        #
        self.bcont = b = Tk.Button(bframe, text="Go", command=self.cont)
        bl.append(b)
        self.bstep = b = Tk.Button(bframe, text="Step", command=self.step)
        bl.append(b)
        self.bnext = b = Tk.Button(bframe, text="Over", command=self.next)
        bl.append(b)
        self.bret = b = Tk.Button(bframe, text="Out", command=self.ret)
        bl.append(b)
        self.bret = b = Tk.Button(bframe, text="Quit", command=self.quit)
        bl.append(b)
        #
        for b in bl:
            b.configure(state="disabled")
            b.pack(side="left")
        #@nonl
        #@-node:ekr.20060516135654.188:<< create the control buttons >>
        #@nl
        #@    << create the check boxes >>
        #@+node:ekr.20060516135654.189:<< create the check boxes >>
        self.cframe = cframe = Tk.Frame(bframe)
        self.cframe.pack(side="left")
        
        if not self.vstack:
            self.__class__.vstack = Tk.BooleanVar(top)
            self.vstack.set(1)
        self.bstack = Tk.Checkbutton(cframe,text="Stack",
            command = self.show_stack, variable = self.vstack)
        self.bstack.grid(row=0,column=0)
        
        if not self.vsource:
            self.__class__.vsource = Tk.BooleanVar(top)
        self.bsource = Tk.Checkbutton(cframe,text="Source",
            command = self.show_source, variable = self.vsource)
        self.bsource.grid(row=0,column=1)
        
        if not self.vlocals:
            self.__class__.vlocals = Tk.BooleanVar(top)
            self.vlocals.set(1)
        self.blocals = Tk.Checkbutton(cframe,text="Locals",
            command = self.show_locals, variable = self.vlocals)
        self.blocals.grid(row=1,column=0)
        
        if not self.vglobals:
            self.__class__.vglobals = Tk.BooleanVar(top)
        self.bglobals = Tk.Checkbutton(cframe,text="Globals",
            command = self.show_globals, variable = self.vglobals)
        self.bglobals.grid(row=1,column=1)
        #@nonl
        #@-node:ekr.20060516135654.189:<< create the check boxes >>
        #@nl
        #
        self.status = Tk.Label(top, anchor="w")
        self.status.pack(anchor="w")
        self.error = Tk.Label(top, anchor="w")
        self.error.pack(anchor="w", fill="x")
        self.errorbg = self.error.cget("background")
        #
        self.fstack = Tk.Frame(top, height=1)
        self.fstack.pack(expand=1, fill="both")
        self.flocals = Tk.Frame(top)
        self.flocals.pack(expand=1, fill="both")
        self.fglobals = Tk.Frame(top, height=1)
        self.fglobals.pack(expand=1, fill="both")
        #
        if self.vstack.get():
            self.show_stack()
        if self.vlocals.get():
            self.show_locals()
        if self.vglobals.get():
            self.show_globals()
    #@-node:ekr.20060516135654.186:make_gui
    #@-node:ekr.20060516135654.184:Birth
    #@+node:ekr.20060516135654.190:run
    def run(self, *args):
        
        g.trace('Debugger',args)
    
        try:
            self.interacting = 1
            return self.idb.run(*args)
        finally:
            self.interacting = 0
    #@nonl
    #@-node:ekr.20060516135654.190:run
    #@+node:ekr.20060516135654.191:close
    def close(self, event=None):
    
        if self.interacting:
            self.top.bell()
        else:
            if self.stackviewer:
                self.stackviewer.close()
                self.stackviewer = None
    
            # Clean up pyshell if user clicked debugger control close widget.
            # (Causes a harmless extra cycle through close_debugger() if user
            # toggled debugger from pyshell Debug menu)
            ### self.pyshell.close_debugger()
            self.interp.close_debugger()
        
            # Now close the debugger control window....
            self.top.destroy()
    #@nonl
    #@-node:ekr.20060516135654.191:close
    #@+node:ekr.20060516135654.192:interaction
    def interaction(self, message, frame, info=None):
        
        g.trace('Debugger',message)
        self.frame = frame
        self.status.configure(text=message)
    
        if info:
            type, value, tb = info
            try:
                m1 = type.__name__
            except AttributeError:
                m1 = "%s" % str(type)
            if value is not None:
                try:
                    m1 = "%s: %s" % (m1, str(value))
                except:
                    pass
            bg = "yellow"
        else:
            m1 = ""
            tb = None
            bg = self.errorbg
        self.error.configure(text=m1, background=bg)
        #
        sv = self.stackviewer
        if sv:
            stack, i = self.idb.get_stack(self.frame, tb)
            sv.load_stack(stack, i)
        #
        self.show_variables(1)
        #
        if self.vsource.get():
            self.sync_source_line()
        #
        for b in self.buttons:
            b.configure(state="normal")
        #
        self.top.wakeup()
        self.root.mainloop()
        #
        for b in self.buttons:
            b.configure(state="disabled")
        self.status.configure(text="")
        self.error.configure(text="", background=self.errorbg)
        self.frame = None
    #@nonl
    #@-node:ekr.20060516135654.192:interaction
    #@+node:ekr.20060516135654.193:sync_source_line (used flist)
    def sync_source_line(self):
        
        frame = self.frame
        if not frame:
            return
        filename, lineno = self.__frame2fileline(frame)
        if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
            g.trace(filename,lineno)
            if 0: ### Not yet
                f.gotoline(filename,lineno)
                # self.flist.gotofileline(filename, lineno)
    #@nonl
    #@-node:ekr.20060516135654.193:sync_source_line (used flist)
    #@+node:ekr.20060516135654.194:__frame2fileline
    def __frame2fileline(self, frame):
        code = frame.f_code
        filename = code.co_filename
        lineno = frame.f_lineno
        return filename, lineno
    #@-node:ekr.20060516135654.194:__frame2fileline
    #@+node:ekr.20060516135654.195:Callbacks
    #@+node:ekr.20060516135654.196:cont
    def cont(self):
        self.idb.set_continue()
        self.root.quit()
    #@-node:ekr.20060516135654.196:cont
    #@+node:ekr.20060516135654.197:step
    def step(self):
        self.idb.set_step()
        self.root.quit()
    #@-node:ekr.20060516135654.197:step
    #@+node:ekr.20060516135654.198:next
    def next(self):
        self.idb.set_next(self.frame)
        self.root.quit()
    #@-node:ekr.20060516135654.198:next
    #@+node:ekr.20060516135654.199:ret
    def ret(self):
        self.idb.set_return(self.frame)
        self.root.quit()
    #@-node:ekr.20060516135654.199:ret
    #@+node:ekr.20060516135654.200:quit
    def quit(self):
    
        self.idb.set_quit()
        self.root.quit()
    #@nonl
    #@-node:ekr.20060516135654.200:quit
    #@-node:ekr.20060516135654.195:Callbacks
    #@+node:ekr.20060516135654.201:refresh
    #@+node:ekr.20060516135654.202:show_stack
    def show_stack(self):
        
        g.trace(self.stackviewer)
    
        if not self.stackviewer and self.vstack.get():
            self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
            if self.frame:
                stack, i = self.idb.get_stack(self.frame, None)
                sv.load_stack(stack, i)
        else:
            sv = self.stackviewer
            if sv and not self.vstack.get():
                self.stackviewer = None
                sv.close()
            self.fstack['height'] = 1
    #@-node:ekr.20060516135654.202:show_stack
    #@+node:ekr.20060516135654.203:show_source
    def show_source(self):
    
        if self.vsource.get():
            self.sync_source_line()
    #@-node:ekr.20060516135654.203:show_source
    #@+node:ekr.20060516135654.204:show_frame
    def show_frame(self, (frame, lineno)):
    
        self.frame = frame
        self.show_variables()
    #@-node:ekr.20060516135654.204:show_frame
    #@+node:ekr.20060516135654.205:show_locals
    def show_locals(self):
    
        lv = self.localsviewer
        if self.vlocals.get():
            if not lv:
                self.localsviewer = NamespaceViewer(self.flocals, "Locals")
        else:
            if lv:
                self.localsviewer = None
                lv.close()
                self.flocals['height'] = 1
        self.show_variables()
    #@-node:ekr.20060516135654.205:show_locals
    #@+node:ekr.20060516135654.206:show_globals
    def show_globals(self):
        
        gv = self.globalsviewer
        if self.vglobals.get():
            if not gv:
                self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
        else:
            if gv:
                self.globalsviewer = None
                gv.close()
                self.fglobals['height'] = 1
        self.show_variables()
    
    #@-node:ekr.20060516135654.206:show_globals
    #@+node:ekr.20060516135654.207:show_variables
    def show_variables(self, force=0):
    
        lv = self.localsviewer
        gv = self.globalsviewer
        frame = self.frame
        if not frame:
            ldict = gdict = None
        else:
            ldict = frame.f_locals
            gdict = frame.f_globals
            if lv and gv and ldict is gdict:
                ldict = None
    
        if 1:
            if lv:
                ### lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
                lv.load_dict(ldict, force, self.interp.rpcclt)
            if gv:
                ### gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
                gv.load_dict(gdict, force, self.interp.rpcclt)
    #@-node:ekr.20060516135654.207:show_variables
    #@-node:ekr.20060516135654.201:refresh
    #@+node:ekr.20060516135654.208:breakpoints
    #@+node:ekr.20060516135654.209:set_breakpoint_here
    def set_breakpoint_here(self, filename, lineno):
    
        self.idb.set_break(filename, lineno)
    #@nonl
    #@-node:ekr.20060516135654.209:set_breakpoint_here
    #@+node:ekr.20060516135654.210:clear_breakpoint_here
    def clear_breakpoint_here(self, filename, lineno):
    
        self.idb.clear_break(filename, lineno)
    #@-node:ekr.20060516135654.210:clear_breakpoint_here
    #@+node:ekr.20060516135654.211:clear_file_breaks
    def clear_file_breaks(self, filename):
        
        self.idb.clear_all_file_breaks(filename)
    
    #@-node:ekr.20060516135654.211:clear_file_breaks
    #@+node:ekr.20060516135654.212:load_breakpoints
    def load_breakpoints(self):
        
        g.trace()
        
        if 0: # "Load PyShellEditorWindow breakpoints into subprocess debugger"
            pyshell_edit_windows = self.pyshell.flist.inversedict.keys()
            for editwin in pyshell_edit_windows:
                filename = editwin.io.filename
                try:
                    for lineno in editwin.breakpoints:
                        self.set_breakpoint_here(filename, lineno)
                except AttributeError:
                    continue
    #@nonl
    #@-node:ekr.20060516135654.212:load_breakpoints
    #@-node:ekr.20060516135654.208:breakpoints
    #@-others
#@nonl
#@-node:ekr.20060516135654.183:class Debugger
#@-others
#@nonl
#@-node:ekr.20060516135654.94:@thin leo_Debugger.py
#@-leo
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.