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
):
17 co_filename
= frame
.f_code
.co_filename
18 ## co_name = frame.f_code.co_name
20 ## print>>sys.__stderr__, "*function: ", frame.f_code.co_name
21 ## print>>sys.__stderr__, "*file: ", frame.f_code.co_filename
22 ## print>>sys.__stderr__, "*line number: ", frame.f_code.co_firstlineno
23 ## print>>sys.__stderr__, "*name: ", co_name
24 ## print>>sys.__stderr__, "*function: ", frame.f_locals.get(co_name,None)
27 ## # XXX 12 Dec 2002 CGT TO DO: Find way to get a reference to the
28 ## # XXX currently running function. If the function has an
29 ## # attribute called "DebuggerStepThrough", prevent the debugger
30 ## # from stepping through Idle code. The following doesn't work
31 ## # in instance methods. Hard coded some workarounds.
32 ## func = frame.f_locals[co_name]
33 ## if getattr(func, "DebuggerStepThrough", 0):
34 ## print "XXXX DEBUGGER STEPPING THROUGH"
40 # workaround for the problem above
41 exclude
= ('rpc.py', 'threading.py', '<string>')
42 for rpcfile
in exclude
:
43 if co_filename
.count(rpcfile
):
46 message
= self
.__frame
2message
(frame
)
47 self
.gui
.interaction(message
, frame
)
49 def user_exception(self
, frame
, info
):
50 message
= self
.__frame
2message
(frame
)
51 self
.gui
.interaction(message
, frame
, info
)
53 def __frame2message(self
, frame
):
55 filename
= code
.co_filename
56 lineno
= frame
.f_lineno
57 basename
= os
.path
.basename(filename
)
58 message
= "%s:%s" % (basename
, lineno
)
59 if code
.co_name
!= "?":
60 message
= "%s: %s()" % (message
, code
.co_name
)
66 vstack
= vsource
= vlocals
= vglobals
= None
68 def __init__(self
, pyshell
, idb
=None):
71 self
.pyshell
= pyshell
80 return self
.idb
.run(*args
)
84 def close(self
, event
=None):
89 self
.stackviewer
.close(); self
.stackviewer
= None
90 # Clean up pyshell if user clicked debugger control close widget.
91 # (Causes a harmless extra cycle through close_debugger() if user
92 # toggled debugger from pyshell Debug menu)
93 self
.pyshell
.close_debugger()
94 # Now close the debugger control window....
98 pyshell
= self
.pyshell
99 self
.flist
= pyshell
.flist
100 self
.root
= root
= pyshell
.root
101 self
.top
= top
=ListedToplevel(root
)
102 self
.top
.wm_title("Debug Control")
103 self
.top
.wm_iconname("Debug")
104 top
.wm_protocol("WM_DELETE_WINDOW", self
.close
)
105 self
.top
.bind("<Escape>", self
.close
)
107 self
.bframe
= bframe
= Frame(top
)
108 self
.bframe
.pack(anchor
="w")
109 self
.buttons
= bl
= []
111 self
.bcont
= b
= Button(bframe
, text
="Go", command
=self
.cont
)
113 self
.bstep
= b
= Button(bframe
, text
="Step", command
=self
.step
)
115 self
.bnext
= b
= Button(bframe
, text
="Over", command
=self
.next
)
117 self
.bret
= b
= Button(bframe
, text
="Out", command
=self
.ret
)
119 self
.bret
= b
= Button(bframe
, text
="Quit", command
=self
.quit
)
123 b
.configure(state
="disabled")
126 self
.cframe
= cframe
= Frame(bframe
)
127 self
.cframe
.pack(side
="left")
130 self
.__class
__.vstack
= BooleanVar(top
)
132 self
.bstack
= Checkbutton(cframe
,
133 text
="Stack", command
=self
.show_stack
, variable
=self
.vstack
)
134 self
.bstack
.grid(row
=0, column
=0)
136 self
.__class
__.vsource
= BooleanVar(top
)
137 self
.bsource
= Checkbutton(cframe
,
138 text
="Source", command
=self
.show_source
, variable
=self
.vsource
)
139 self
.bsource
.grid(row
=0, column
=1)
141 self
.__class
__.vlocals
= BooleanVar(top
)
143 self
.blocals
= Checkbutton(cframe
,
144 text
="Locals", command
=self
.show_locals
, variable
=self
.vlocals
)
145 self
.blocals
.grid(row
=1, column
=0)
146 if not self
.vglobals
:
147 self
.__class
__.vglobals
= BooleanVar(top
)
148 self
.bglobals
= Checkbutton(cframe
,
149 text
="Globals", command
=self
.show_globals
, variable
=self
.vglobals
)
150 self
.bglobals
.grid(row
=1, column
=1)
152 self
.status
= Label(top
, anchor
="w")
153 self
.status
.pack(anchor
="w")
154 self
.error
= Label(top
, anchor
="w")
155 self
.error
.pack(anchor
="w", fill
="x")
156 self
.errorbg
= self
.error
.cget("background")
158 self
.fstack
= Frame(top
, height
=1)
159 self
.fstack
.pack(expand
=1, fill
="both")
160 self
.flocals
= Frame(top
)
161 self
.flocals
.pack(expand
=1, fill
="both")
162 self
.fglobals
= Frame(top
, height
=1)
163 self
.fglobals
.pack(expand
=1, fill
="both")
165 if self
.vstack
.get():
167 if self
.vlocals
.get():
169 if self
.vglobals
.get():
173 def interaction(self
, message
, frame
, info
=None):
175 self
.status
.configure(text
=message
)
178 type, value
, tb
= info
181 except AttributeError:
182 m1
= "%s" % str(type)
183 if value
is not None:
185 m1
= "%s: %s" % (m1
, str(value
))
193 self
.error
.configure(text
=m1
, background
=bg
)
195 sv
= self
.stackviewer
197 stack
, i
= self
.idb
.get_stack(self
.frame
, tb
)
198 sv
.load_stack(stack
, i
)
200 self
.show_variables(1)
202 if self
.vsource
.get():
203 self
.sync_source_line()
205 for b
in self
.buttons
:
206 b
.configure(state
="normal")
211 for b
in self
.buttons
:
212 b
.configure(state
="disabled")
213 self
.status
.configure(text
="")
214 self
.error
.configure(text
="", background
=self
.errorbg
)
217 def sync_source_line(self
):
221 filename
, lineno
= self
.__frame
2fileline
(frame
)
222 if filename
[:1] + filename
[-1:] != "<>" and os
.path
.exists(filename
):
223 self
.flist
.gotofileline(filename
, lineno
)
225 def __frame2fileline(self
, frame
):
227 filename
= code
.co_filename
228 lineno
= frame
.f_lineno
229 return filename
, lineno
232 self
.idb
.set_continue()
240 self
.idb
.set_next(self
.frame
)
244 self
.idb
.set_return(self
.frame
)
253 def show_stack(self
):
254 if not self
.stackviewer
and self
.vstack
.get():
255 self
.stackviewer
= sv
= StackViewer(self
.fstack
, self
.flist
, self
)
257 stack
, i
= self
.idb
.get_stack(self
.frame
, None)
258 sv
.load_stack(stack
, i
)
260 sv
= self
.stackviewer
261 if sv
and not self
.vstack
.get():
262 self
.stackviewer
= None
264 self
.fstack
['height'] = 1
266 def show_source(self
):
267 if self
.vsource
.get():
268 self
.sync_source_line()
270 def show_frame(self
, (frame
, lineno
)):
272 self
.show_variables()
277 def show_locals(self
):
278 lv
= self
.localsviewer
279 if self
.vlocals
.get():
281 self
.localsviewer
= NamespaceViewer(self
.flocals
, "Locals")
284 self
.localsviewer
= None
286 self
.flocals
['height'] = 1
287 self
.show_variables()
289 def show_globals(self
):
290 gv
= self
.globalsviewer
291 if self
.vglobals
.get():
293 self
.globalsviewer
= NamespaceViewer(self
.fglobals
, "Globals")
296 self
.globalsviewer
= None
298 self
.fglobals
['height'] = 1
299 self
.show_variables()
301 def show_variables(self
, force
=0):
302 lv
= self
.localsviewer
303 gv
= self
.globalsviewer
308 ldict
= frame
.f_locals
309 gdict
= frame
.f_globals
310 if lv
and gv
and ldict
is gdict
:
313 lv
.load_dict(ldict
, force
, self
.pyshell
.interp
.rpcclt
)
315 gv
.load_dict(gdict
, force
, self
.pyshell
.interp
.rpcclt
)
317 def set_breakpoint_here(self
, filename
, lineno
):
318 self
.idb
.set_break(filename
, lineno
)
320 def clear_breakpoint_here(self
, filename
, lineno
):
321 self
.idb
.clear_break(filename
, lineno
)
323 def clear_file_breaks(self
, filename
):
324 self
.idb
.clear_all_file_breaks(filename
)
326 def load_breakpoints(self
):
327 "Load PyShellEditorWindow breakpoints into subprocess debugger"
328 pyshell_edit_windows
= self
.pyshell
.flist
.inversedict
.keys()
329 for editwin
in pyshell_edit_windows
:
330 filename
= editwin
.io
.filename
332 for lineno
in editwin
.breakpoints
:
333 self
.set_breakpoint_here(filename
, lineno
)
334 except AttributeError:
337 class StackViewer(ScrolledList
):
339 def __init__(self
, master
, flist
, gui
):
340 ScrolledList
.__init
__(self
, master
, width
=80)
345 def load_stack(self
, stack
, index
=None):
348 for i
in range(len(stack
)):
349 frame
, lineno
= stack
[i
]
351 modname
= frame
.f_globals
["__name__"]
355 filename
= code
.co_filename
356 funcname
= code
.co_name
358 sourceline
= linecache
.getline(filename
, lineno
)
360 sourceline
= string
.strip(sourceline
)
361 if funcname
in ("?", "", None):
362 item
= "%s, line %d: %s" % (modname
, lineno
, sourceline
)
364 item
= "%s.%s(), line %d: %s" % (modname
, funcname
,
369 if index
is not None:
372 def popup_event(self
, event
):
373 "override base method"
375 return ScrolledList
.popup_event(self
, event
)
378 "override base method"
380 menu
.add_command(label
="Go to source line",
381 command
=self
.goto_source_line
)
382 menu
.add_command(label
="Show stack frame",
383 command
=self
.show_stack_frame
)
385 def on_select(self
, index
):
386 "override base method"
387 if 0 <= index
< len(self
.stack
):
388 self
.gui
.show_frame(self
.stack
[index
])
390 def on_double(self
, index
):
391 "override base method"
392 self
.show_source(index
)
394 def goto_source_line(self
):
395 index
= self
.listbox
.index("active")
396 self
.show_source(index
)
398 def show_stack_frame(self
):
399 index
= self
.listbox
.index("active")
400 if 0 <= index
< len(self
.stack
):
401 self
.gui
.show_frame(self
.stack
[index
])
403 def show_source(self
, index
):
404 if not (0 <= index
< len(self
.stack
)):
406 frame
, lineno
= self
.stack
[index
]
408 filename
= code
.co_filename
409 if os
.path
.isfile(filename
):
410 edit
= self
.flist
.open(filename
)
412 edit
.gotoline(lineno
)
415 class NamespaceViewer
:
417 def __init__(self
, master
, title
, dict=None):
421 height
= 20*len(dict) # XXX 20 == observed height of Entry widget
425 self
.repr = repr.Repr()
426 self
.repr.maxstring
= 60
427 self
.repr.maxother
= 60
428 self
.frame
= frame
= Frame(master
)
429 self
.frame
.pack(expand
=1, fill
="both")
430 self
.label
= Label(frame
, text
=title
, borderwidth
=2, relief
="groove")
431 self
.label
.pack(fill
="x")
432 self
.vbar
= vbar
= Scrollbar(frame
, name
="vbar")
433 vbar
.pack(side
="right", fill
="y")
434 self
.canvas
= canvas
= Canvas(frame
,
435 height
=min(300, max(40, height
)),
436 scrollregion
=(0, 0, width
, height
))
437 canvas
.pack(side
="left", fill
="both", expand
=1)
438 vbar
["command"] = canvas
.yview
439 canvas
["yscrollcommand"] = vbar
.set
440 self
.subframe
= subframe
= Frame(canvas
)
441 self
.sfid
= canvas
.create_window(0, 0, window
=subframe
, anchor
="nw")
446 def load_dict(self
, dict, force
=0, rpc_client
=None):
447 if dict is self
.dict and not force
:
449 subframe
= self
.subframe
451 for c
in subframe
.children
.values():
455 l
= Label(subframe
, text
="None")
456 l
.grid(row
=0, column
=0)
463 svalue
= self
.repr.repr(value
) # repr(value)
464 # Strip extra quotes caused by calling repr on the (already)
465 # repr'd value sent across the RPC interface:
467 svalue
= svalue
[1:-1]
468 l
= Label(subframe
, text
=name
)
469 l
.grid(row
=row
, column
=0, sticky
="nw")
470 l
= Entry(subframe
, width
=0, borderwidth
=0)
472 l
.grid(row
=row
, column
=1, sticky
="nw")
475 # XXX Could we use a <Configure> callback for the following?
476 subframe
.update_idletasks() # Alas!
477 width
= subframe
.winfo_reqwidth()
478 height
= subframe
.winfo_reqheight()
480 self
.canvas
["scrollregion"] = (0, 0, width
, height
)
482 canvas
["height"] = 300
485 canvas
["height"] = height