5 from WindowList
import ListedToplevel
6 from ScrolledList
import ScrolledList
11 def __init__(self
, gui
):
13 bdb
.Bdb
.__init
__(self
)
15 def user_line(self
, frame
):
16 # get the currently executing function
17 ##print>>sys.__stderr__, "*function: ", frame.f_code.co_name
18 ##print>>sys.__stderr__, "*file: ", frame.f_code.co_filename
19 ##print>>sys.__stderr__, "*line number: ", frame.f_code.co_firstlineno
20 co_filename
= frame
.f_code
.co_filename
21 co_name
= frame
.f_code
.co_name
23 func
= frame
.f_locals
[co_name
]
24 if getattr(func
, "DebuggerStepThrough", 0):
25 print "XXXX DEBUGGER STEPPING THROUGH"
30 if co_filename
in ('rpc.py', '<string>'):
33 if co_filename
.endswith('threading.py'):
36 message
= self
.__frame
2message
(frame
)
37 self
.gui
.interaction(message
, frame
)
39 def user_exception(self
, frame
, info
):
40 message
= self
.__frame
2message
(frame
)
41 self
.gui
.interaction(message
, frame
, info
)
43 def __frame2message(self
, frame
):
45 filename
= code
.co_filename
46 lineno
= frame
.f_lineno
47 basename
= os
.path
.basename(filename
)
48 message
= "%s:%s" % (basename
, lineno
)
49 if code
.co_name
!= "?":
50 message
= "%s: %s()" % (message
, code
.co_name
)
56 vstack
= vsource
= vlocals
= vglobals
= None
58 def __init__(self
, pyshell
, idb
=None):
61 self
.pyshell
= pyshell
70 return self
.idb
.run(*args
)
74 def close(self
, event
=None):
79 self
.stackviewer
.close(); self
.stackviewer
= None
80 # Remove all EditWindow BREAK tags when closing debugger:
81 edit_windows
= self
.pyshell
.flist
.inversedict
.keys()
82 for window
in edit_windows
:
83 window
.text
.tag_remove("BREAK", 1.0, END
)
84 window
.break_set
= False
85 # Clean up pyshell if user clicked debugger control close widget.
86 # (Causes a harmless extra cycle through close_debugger() if user
87 # toggled debugger from pyshell Debug menu)
88 self
.pyshell
.close_debugger()
89 # Now close the debugger control window....
93 pyshell
= self
.pyshell
94 self
.flist
= pyshell
.flist
95 self
.root
= root
= pyshell
.root
96 self
.top
= top
=ListedToplevel(root
)
97 self
.top
.wm_title("Debug Control")
98 self
.top
.wm_iconname("Debug")
99 top
.wm_protocol("WM_DELETE_WINDOW", self
.close
)
100 self
.top
.bind("<Escape>", self
.close
)
102 self
.bframe
= bframe
= Frame(top
)
103 self
.bframe
.pack(anchor
="w")
104 self
.buttons
= bl
= []
106 self
.bcont
= b
= Button(bframe
, text
="Go", command
=self
.cont
)
108 self
.bstep
= b
= Button(bframe
, text
="Step", command
=self
.step
)
110 self
.bnext
= b
= Button(bframe
, text
="Over", command
=self
.next
)
112 self
.bret
= b
= Button(bframe
, text
="Out", command
=self
.ret
)
114 self
.bret
= b
= Button(bframe
, text
="Quit", command
=self
.quit
)
118 b
.configure(state
="disabled")
121 self
.cframe
= cframe
= Frame(bframe
)
122 self
.cframe
.pack(side
="left")
125 self
.__class
__.vstack
= BooleanVar(top
)
127 self
.bstack
= Checkbutton(cframe
,
128 text
="Stack", command
=self
.show_stack
, variable
=self
.vstack
)
129 self
.bstack
.grid(row
=0, column
=0)
131 self
.__class
__.vsource
= BooleanVar(top
)
132 ##self.vsource.set(1)
133 self
.bsource
= Checkbutton(cframe
,
134 text
="Source", command
=self
.show_source
, variable
=self
.vsource
)
135 self
.bsource
.grid(row
=0, column
=1)
137 self
.__class
__.vlocals
= BooleanVar(top
)
139 self
.blocals
= Checkbutton(cframe
,
140 text
="Locals", command
=self
.show_locals
, variable
=self
.vlocals
)
141 self
.blocals
.grid(row
=1, column
=0)
142 if not self
.vglobals
:
143 self
.__class
__.vglobals
= BooleanVar(top
)
144 ##self.vglobals.set(1)
145 self
.bglobals
= Checkbutton(cframe
,
146 text
="Globals", command
=self
.show_globals
, variable
=self
.vglobals
)
147 self
.bglobals
.grid(row
=1, column
=1)
149 self
.status
= Label(top
, anchor
="w")
150 self
.status
.pack(anchor
="w")
151 self
.error
= Label(top
, anchor
="w")
152 self
.error
.pack(anchor
="w", fill
="x")
153 self
.errorbg
= self
.error
.cget("background")
155 self
.fstack
= Frame(top
, height
=1)
156 self
.fstack
.pack(expand
=1, fill
="both")
157 self
.flocals
= Frame(top
)
158 self
.flocals
.pack(expand
=1, fill
="both")
159 self
.fglobals
= Frame(top
, height
=1)
160 self
.fglobals
.pack(expand
=1, fill
="both")
162 if self
.vstack
.get():
164 if self
.vlocals
.get():
166 if self
.vglobals
.get():
170 def interaction(self
, message
, frame
, info
=None):
172 self
.status
.configure(text
=message
)
175 type, value
, tb
= info
178 except AttributeError:
179 m1
= "%s" % str(type)
180 if value
is not None:
182 m1
= "%s: %s" % (m1
, str(value
))
190 self
.error
.configure(text
=m1
, background
=bg
)
192 sv
= self
.stackviewer
194 stack
, i
= self
.idb
.get_stack(self
.frame
, tb
)
195 sv
.load_stack(stack
, i
)
197 self
.show_variables(1)
199 if self
.vsource
.get():
200 self
.sync_source_line()
202 for b
in self
.buttons
:
203 b
.configure(state
="normal")
208 for b
in self
.buttons
:
209 b
.configure(state
="disabled")
210 self
.status
.configure(text
="")
211 self
.error
.configure(text
="", background
=self
.errorbg
)
214 def sync_source_line(self
):
218 filename
, lineno
= self
.__frame
2fileline
(frame
)
219 if filename
[:1] + filename
[-1:] != "<>" and os
.path
.exists(filename
):
220 self
.flist
.gotofileline(filename
, lineno
)
222 def __frame2fileline(self
, frame
):
224 filename
= code
.co_filename
225 lineno
= frame
.f_lineno
226 return filename
, lineno
229 self
.idb
.set_continue()
237 self
.idb
.set_next(self
.frame
)
241 self
.idb
.set_return(self
.frame
)
250 def show_stack(self
):
251 if not self
.stackviewer
and self
.vstack
.get():
252 self
.stackviewer
= sv
= StackViewer(self
.fstack
, self
.flist
, self
)
254 stack
, i
= self
.idb
.get_stack(self
.frame
, None)
255 sv
.load_stack(stack
, i
)
257 sv
= self
.stackviewer
258 if sv
and not self
.vstack
.get():
259 self
.stackviewer
= None
261 self
.fstack
['height'] = 1
263 def show_source(self
):
264 if self
.vsource
.get():
265 self
.sync_source_line()
267 def show_frame(self
, (frame
, lineno
)):
269 self
.show_variables()
274 def show_locals(self
):
275 lv
= self
.localsviewer
276 if self
.vlocals
.get():
278 self
.localsviewer
= NamespaceViewer(self
.flocals
, "Locals")
281 self
.localsviewer
= None
283 self
.flocals
['height'] = 1
284 self
.show_variables()
286 def show_globals(self
):
287 gv
= self
.globalsviewer
288 if self
.vglobals
.get():
290 self
.globalsviewer
= NamespaceViewer(self
.fglobals
, "Globals")
293 self
.globalsviewer
= None
295 self
.fglobals
['height'] = 1
296 self
.show_variables()
298 def show_variables(self
, force
=0):
299 lv
= self
.localsviewer
300 gv
= self
.globalsviewer
305 ldict
= frame
.f_locals
306 gdict
= frame
.f_globals
307 if lv
and gv
and ldict
is gdict
:
310 lv
.load_dict(ldict
, force
, self
.pyshell
.interp
.rpcclt
)
312 gv
.load_dict(gdict
, force
, self
.pyshell
.interp
.rpcclt
)
314 def set_breakpoint_here(self
, edit
):
316 filename
= edit
.io
.filename
320 lineno
= int(float(text
.index("insert")))
321 msg
= self
.idb
.set_break(filename
, lineno
)
325 text
.tag_add("BREAK", "insert linestart", "insert lineend +1char")
326 edit
.break_set
= True
328 def clear_breakpoint_here(self
, edit
):
330 filename
= edit
.io
.filename
334 lineno
= int(float(text
.index("insert")))
335 msg
= self
.idb
.clear_break(filename
, lineno
)
339 text
.tag_remove("BREAK", "insert linestart",\
340 "insert lineend +1char")
341 # Don't bother to track break_set status
343 def clear_file_breaks(self
, edit
):
345 filename
= edit
.io
.filename
349 msg
= self
.idb
.clear_all_file_breaks(filename
)
353 text
.tag_remove("BREAK", "1.0", END
)
354 edit
.break_set
= False
357 class StackViewer(ScrolledList
):
359 def __init__(self
, master
, flist
, gui
):
360 ScrolledList
.__init
__(self
, master
, width
=80)
365 def load_stack(self
, stack
, index
=None):
368 for i
in range(len(stack
)):
369 frame
, lineno
= stack
[i
]
371 modname
= frame
.f_globals
["__name__"]
375 filename
= code
.co_filename
376 funcname
= code
.co_name
378 sourceline
= linecache
.getline(filename
, lineno
)
380 sourceline
= string
.strip(sourceline
)
381 if funcname
in ("?", "", None):
382 item
= "%s, line %d: %s" % (modname
, lineno
, sourceline
)
384 item
= "%s.%s(), line %d: %s" % (modname
, funcname
,
389 if index
is not None:
392 def popup_event(self
, event
):
393 "override base method"
395 return ScrolledList
.popup_event(self
, event
)
398 "override base method"
400 menu
.add_command(label
="Go to source line",
401 command
=self
.goto_source_line
)
402 menu
.add_command(label
="Show stack frame",
403 command
=self
.show_stack_frame
)
405 def on_select(self
, index
):
406 "override base method"
407 if 0 <= index
< len(self
.stack
):
408 self
.gui
.show_frame(self
.stack
[index
])
410 def on_double(self
, index
):
411 "override base method"
412 self
.show_source(index
)
414 def goto_source_line(self
):
415 index
= self
.listbox
.index("active")
416 self
.show_source(index
)
418 def show_stack_frame(self
):
419 index
= self
.listbox
.index("active")
420 if 0 <= index
< len(self
.stack
):
421 self
.gui
.show_frame(self
.stack
[index
])
423 def show_source(self
, index
):
424 if not (0 <= index
< len(self
.stack
)):
426 frame
, lineno
= self
.stack
[index
]
428 filename
= code
.co_filename
429 if os
.path
.isfile(filename
):
430 edit
= self
.flist
.open(filename
)
432 edit
.gotoline(lineno
)
435 class NamespaceViewer
:
437 def __init__(self
, master
, title
, dict=None):
441 height
= 20*len(dict) # XXX 20 == observed height of Entry widget
445 self
.repr = repr.Repr()
446 self
.repr.maxstring
= 60
447 self
.repr.maxother
= 60
448 self
.frame
= frame
= Frame(master
)
449 self
.frame
.pack(expand
=1, fill
="both")
450 self
.label
= Label(frame
, text
=title
, borderwidth
=2, relief
="groove")
451 self
.label
.pack(fill
="x")
452 self
.vbar
= vbar
= Scrollbar(frame
, name
="vbar")
453 vbar
.pack(side
="right", fill
="y")
454 self
.canvas
= canvas
= Canvas(frame
,
455 height
=min(300, max(40, height
)),
456 scrollregion
=(0, 0, width
, height
))
457 canvas
.pack(side
="left", fill
="both", expand
=1)
458 vbar
["command"] = canvas
.yview
459 canvas
["yscrollcommand"] = vbar
.set
460 self
.subframe
= subframe
= Frame(canvas
)
461 self
.sfid
= canvas
.create_window(0, 0, window
=subframe
, anchor
="nw")
466 def load_dict(self
, dict, force
=0, rpc_client
=None):
467 if dict is self
.dict and not force
:
469 subframe
= self
.subframe
471 for c
in subframe
.children
.values():
475 l
= Label(subframe
, text
="None")
476 l
.grid(row
=0, column
=0)
483 svalue
= self
.repr.repr(value
) # repr(value)
484 # Strip extra quotes caused by calling repr on the (already)
485 # repr'd value sent across the RPC interface:
487 svalue
= svalue
[1:-1]
488 l
= Label(subframe
, text
=name
)
489 l
.grid(row
=row
, column
=0, sticky
="nw")
490 ## l = Label(subframe, text=svalue, justify="l", wraplength=300)
491 l
= Entry(subframe
, width
=0, borderwidth
=0)
493 ## l["state"] = "disabled"
494 l
.grid(row
=row
, column
=1, sticky
="nw")
497 # XXX Could we use a <Configure> callback for the following?
498 subframe
.update_idletasks() # Alas!
499 width
= subframe
.winfo_reqwidth()
500 height
= subframe
.winfo_reqheight()
502 self
.canvas
["scrollregion"] = (0, 0, width
, height
)
504 canvas
["height"] = 300
507 canvas
["height"] = height