from WindowList
import ListedToplevel
from ScrolledList
import ScrolledList
def user_line(self
, frame
):
if self
.in_rpc_code(frame
):
message
= self
.__frame
2message
(frame
)
self
.gui
.interaction(message
, frame
)
def user_exception(self
, frame
, info
):
if self
.in_rpc_code(frame
):
message
= self
.__frame
2message
(frame
)
self
.gui
.interaction(message
, frame
, info
)
def in_rpc_code(self
, frame
):
if frame
.f_code
.co_filename
.count('rpc.py'):
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 self
.in_rpc_code(prev_frame
)
def __frame2message(self
, frame
):
filename
= code
.co_filename
basename
= os
.path
.basename(filename
)
message
= "%s:%s" % (basename
, lineno
)
message
= "%s: %s()" % (message
, code
.co_name
)
vstack
= vsource
= vlocals
= vglobals
= None
def __init__(self
, pyshell
, idb
=None):
return self
.idb
.run(*args
)
def close(self
, event
=None):
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()
# Now close the debugger control window....
self
.flist
= pyshell
.flist
self
.root
= root
= pyshell
.root
self
.top
= top
= ListedToplevel(root
)
self
.top
.wm_title("Debug Control")
self
.top
.wm_iconname("Debug")
top
.wm_protocol("WM_DELETE_WINDOW", self
.close
)
self
.top
.bind("<Escape>", self
.close
)
self
.bframe
= bframe
= Frame(top
)
self
.bframe
.pack(anchor
="w")
self
.bcont
= b
= Button(bframe
, text
="Go", command
=self
.cont
)
self
.bstep
= b
= Button(bframe
, text
="Step", command
=self
.step
)
self
.bnext
= b
= Button(bframe
, text
="Over", command
=self
.next
)
self
.bret
= b
= Button(bframe
, text
="Out", command
=self
.ret
)
self
.bret
= b
= Button(bframe
, text
="Quit", command
=self
.quit
)
b
.configure(state
="disabled")
self
.cframe
= cframe
= Frame(bframe
)
self
.cframe
.pack(side
="left")
self
.__class
__.vstack
= BooleanVar(top
)
self
.bstack
= Checkbutton(cframe
,
text
="Stack", command
=self
.show_stack
, variable
=self
.vstack
)
self
.bstack
.grid(row
=0, column
=0)
self
.__class
__.vsource
= BooleanVar(top
)
self
.bsource
= Checkbutton(cframe
,
text
="Source", command
=self
.show_source
, variable
=self
.vsource
)
self
.bsource
.grid(row
=0, column
=1)
self
.__class
__.vlocals
= BooleanVar(top
)
self
.blocals
= Checkbutton(cframe
,
text
="Locals", command
=self
.show_locals
, variable
=self
.vlocals
)
self
.blocals
.grid(row
=1, column
=0)
self
.__class
__.vglobals
= BooleanVar(top
)
self
.bglobals
= Checkbutton(cframe
,
text
="Globals", command
=self
.show_globals
, variable
=self
.vglobals
)
self
.bglobals
.grid(row
=1, column
=1)
self
.status
= Label(top
, anchor
="w")
self
.status
.pack(anchor
="w")
self
.error
= Label(top
, anchor
="w")
self
.error
.pack(anchor
="w", fill
="x")
self
.errorbg
= self
.error
.cget("background")
self
.fstack
= Frame(top
, height
=1)
self
.fstack
.pack(expand
=1, fill
="both")
self
.flocals
= Frame(top
)
self
.flocals
.pack(expand
=1, fill
="both")
self
.fglobals
= Frame(top
, height
=1)
self
.fglobals
.pack(expand
=1, fill
="both")
def interaction(self
, message
, frame
, info
=None):
self
.status
.configure(text
=message
)
m1
= "%s: %s" % (m1
, str(value
))
self
.error
.configure(text
=m1
, background
=bg
)
stack
, i
= self
.idb
.get_stack(self
.frame
, tb
)
b
.configure(state
="normal")
b
.configure(state
="disabled")
self
.status
.configure(text
="")
self
.error
.configure(text
="", background
=self
.errorbg
)
def sync_source_line(self
):
filename
, lineno
= self
.__frame
2fileline
(frame
)
if filename
[:1] + filename
[-1:] != "<>" and os
.path
.exists(filename
):
self
.flist
.gotofileline(filename
, lineno
)
def __frame2fileline(self
, frame
):
filename
= code
.co_filename
self
.idb
.set_next(self
.frame
)
self
.idb
.set_return(self
.frame
)
if not self
.stackviewer
and self
.vstack
.get():
self
.stackviewer
= sv
= StackViewer(self
.fstack
, self
.flist
, self
)
stack
, i
= self
.idb
.get_stack(self
.frame
, None)
if sv
and not self
.vstack
.get():
self
.fstack
['height'] = 1
def show_frame(self
, (frame
, lineno
)):
self
.localsviewer
= NamespaceViewer(self
.flocals
, "Locals")
self
.flocals
['height'] = 1
self
.globalsviewer
= NamespaceViewer(self
.fglobals
, "Globals")
self
.globalsviewer
= None
self
.fglobals
['height'] = 1
def show_variables(self
, force
=0):
if lv
and gv
and ldict
is gdict
:
lv
.load_dict(ldict
, force
, self
.pyshell
.interp
.rpcclt
)
gv
.load_dict(gdict
, force
, self
.pyshell
.interp
.rpcclt
)
def set_breakpoint_here(self
, filename
, lineno
):
self
.idb
.set_break(filename
, lineno
)
def clear_breakpoint_here(self
, filename
, lineno
):
self
.idb
.clear_break(filename
, lineno
)
def clear_file_breaks(self
, filename
):
self
.idb
.clear_all_file_breaks(filename
)
def load_breakpoints(self
):
"Load PyShellEditorWindow breakpoints into subprocess debugger"
pyshell_edit_windows
= self
.pyshell
.flist
.inversedict
.keys()
for editwin
in pyshell_edit_windows
:
filename
= editwin
.io
.filename
for lineno
in editwin
.breakpoints
:
self
.set_breakpoint_here(filename
, lineno
)
class StackViewer(ScrolledList
):
def __init__(self
, master
, flist
, gui
):
ScrolledList
.__init
__(self
, master
, width
=80)
def load_stack(self
, stack
, index
=None):
for i
in range(len(stack
)):
modname
= frame
.f_globals
["__name__"]
filename
= code
.co_filename
sourceline
= linecache
.getline(filename
, lineno
)
sourceline
= string
.strip(sourceline
)
if funcname
in ("?", "", None):
item
= "%s, line %d: %s" % (modname
, lineno
, sourceline
)
item
= "%s.%s(), line %d: %s" % (modname
, funcname
,
def popup_event(self
, event
):
return ScrolledList
.popup_event(self
, event
)
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
)
def on_select(self
, index
):
if 0 <= index
< len(self
.stack
):
self
.gui
.show_frame(self
.stack
[index
])
def on_double(self
, index
):
def goto_source_line(self
):
index
= self
.listbox
.index("active")
def show_stack_frame(self
):
index
= self
.listbox
.index("active")
if 0 <= index
< len(self
.stack
):
self
.gui
.show_frame(self
.stack
[index
])
def show_source(self
, index
):
if not (0 <= index
< len(self
.stack
)):
frame
, lineno
= self
.stack
[index
]
filename
= code
.co_filename
if os
.path
.isfile(filename
):
edit
= self
.flist
.open(filename
)
def __init__(self
, master
, title
, dict=None):
height
= 20*len(dict) # XXX 20 == observed height of Entry widget
self
.frame
= frame
= Frame(master
)
self
.frame
.pack(expand
=1, fill
="both")
self
.label
= Label(frame
, text
=title
, borderwidth
=2, relief
="groove")
self
.label
.pack(fill
="x")
self
.vbar
= vbar
= Scrollbar(frame
, name
="vbar")
vbar
.pack(side
="right", fill
="y")
self
.canvas
= canvas
= 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
= Frame(canvas
)
self
.sfid
= canvas
.create_window(0, 0, window
=subframe
, anchor
="nw")
def load_dict(self
, dict, force
=0, rpc_client
=None):
if dict is self
.dict and not force
:
for c
in subframe
.children
.values():
l
= Label(subframe
, text
="None")
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:
l
= Label(subframe
, text
=name
)
l
.grid(row
=row
, column
=0, sticky
="nw")
l
= Entry(subframe
, width
=0, borderwidth
=0)
l
.grid(row
=row
, column
=1, sticky
="nw")
# XXX Could we use a <Configure> callback for the following?
subframe
.update_idletasks() # Alas!
width
= subframe
.winfo_reqwidth()
height
= subframe
.winfo_reqheight()
self
.canvas
["scrollregion"] = (0, 0, width
, height
)
canvas
["height"] = height