blob: 2cca2d9c5bd2e9bdd8e4629e8803d66b0149becd [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001import os
2import bdb
Chui Tey5d2af632002-05-26 13:36:41 +00003import types
David Scherer7aced172000-08-15 01:13:23 +00004import traceback
5from Tkinter import *
6from WindowList import ListedToplevel
7
8import StackViewer
9
10
Chui Tey5d2af632002-05-26 13:36:41 +000011class Idb(bdb.Bdb):
12
13 def __init__(self, gui):
14 self.gui = gui
15 bdb.Bdb.__init__(self)
16
17 def user_line(self, frame):
18 # get the currently executing function
19 co_filename = frame.f_code.co_filename
20 co_name = frame.f_code.co_name
21 try:
22 func = frame.f_locals[co_name]
23 if getattr(func, "DebuggerStepThrough", 0):
24 print "XXXX DEBUGGER STEPPING THROUGH"
25 self.set_step()
26 return
27 except:
28 pass
29 if co_filename in ('rpc.py', '<string>'):
30 self.set_step()
31 return
32 if co_filename.endswith('threading.py'):
33 self.set_step()
34 return
35 message = self.__frame2message(frame)
36 self.gui.interaction(message, frame)
37
38 def user_exception(self, frame, info):
39 message = self.__frame2message(frame)
40 self.gui.interaction(message, frame, info)
41
42 def __frame2message(self, frame):
43 code = frame.f_code
44 filename = code.co_filename
45 lineno = frame.f_lineno
46 basename = os.path.basename(filename)
47 message = "%s:%s" % (basename, lineno)
48 if code.co_name != "?":
49 message = "%s: %s()" % (message, code.co_name)
50 return message
51
52
53class Debugger:
David Scherer7aced172000-08-15 01:13:23 +000054
David Scherer7aced172000-08-15 01:13:23 +000055 vstack = vsource = vlocals = vglobals = None
56
Chui Tey5d2af632002-05-26 13:36:41 +000057 def __init__(self, pyshell, idb=None):
58 if idb is None:
59 idb = Idb(self)
David Scherer7aced172000-08-15 01:13:23 +000060 self.pyshell = pyshell
Chui Tey5d2af632002-05-26 13:36:41 +000061 self.idb = idb
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +000062 self.frame = None
David Scherer7aced172000-08-15 01:13:23 +000063 self.make_gui()
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +000064 self.interacting = 0
65
Chui Tey5d2af632002-05-26 13:36:41 +000066 def run(self, *args):
67 try:
68 self.interacting = 1
69 return self.idb.run(*args)
70 finally:
71 self.interacting = 0
David Scherer7aced172000-08-15 01:13:23 +000072
73 def close(self, event=None):
74 if self.interacting:
75 self.top.bell()
76 return
77 if self.stackviewer:
78 self.stackviewer.close(); self.stackviewer = None
Kurt B. Kaiserf8096fb2002-06-25 03:28:38 +000079 # Remove all EditWindow BREAK tags when closing debugger:
80 edit_windows = self.pyshell.flist.inversedict.keys()
81 for window in edit_windows:
82 window.text.tag_remove("BREAK", 1.0, END)
83 # Clean up pyshell if user clicked debugger control close widget.
84 # (Causes a harmless extra cycle through close_debugger() if user
85 # toggled debugger from pyshell Debug menu)
David Scherer7aced172000-08-15 01:13:23 +000086 self.pyshell.close_debugger()
Kurt B. Kaiserf8096fb2002-06-25 03:28:38 +000087 # Now close the debugger control window....
David Scherer7aced172000-08-15 01:13:23 +000088 self.top.destroy()
89
David Scherer7aced172000-08-15 01:13:23 +000090 def make_gui(self):
91 pyshell = self.pyshell
92 self.flist = pyshell.flist
93 self.root = root = pyshell.root
94 self.top = top =ListedToplevel(root)
95 self.top.wm_title("Debug Control")
96 self.top.wm_iconname("Debug")
97 top.wm_protocol("WM_DELETE_WINDOW", self.close)
98 self.top.bind("<Escape>", self.close)
99 #
100 self.bframe = bframe = Frame(top)
101 self.bframe.pack(anchor="w")
102 self.buttons = bl = []
103 #
104 self.bcont = b = Button(bframe, text="Go", command=self.cont)
105 bl.append(b)
106 self.bstep = b = Button(bframe, text="Step", command=self.step)
107 bl.append(b)
108 self.bnext = b = Button(bframe, text="Over", command=self.next)
109 bl.append(b)
110 self.bret = b = Button(bframe, text="Out", command=self.ret)
111 bl.append(b)
112 self.bret = b = Button(bframe, text="Quit", command=self.quit)
113 bl.append(b)
114 #
115 for b in bl:
116 b.configure(state="disabled")
117 b.pack(side="left")
118 #
119 self.cframe = cframe = Frame(bframe)
120 self.cframe.pack(side="left")
121 #
122 if not self.vstack:
123 self.__class__.vstack = BooleanVar(top)
124 self.vstack.set(1)
125 self.bstack = Checkbutton(cframe,
126 text="Stack", command=self.show_stack, variable=self.vstack)
127 self.bstack.grid(row=0, column=0)
128 if not self.vsource:
129 self.__class__.vsource = BooleanVar(top)
130 ##self.vsource.set(1)
131 self.bsource = Checkbutton(cframe,
132 text="Source", command=self.show_source, variable=self.vsource)
133 self.bsource.grid(row=0, column=1)
134 if not self.vlocals:
135 self.__class__.vlocals = BooleanVar(top)
136 self.vlocals.set(1)
137 self.blocals = Checkbutton(cframe,
138 text="Locals", command=self.show_locals, variable=self.vlocals)
139 self.blocals.grid(row=1, column=0)
140 if not self.vglobals:
141 self.__class__.vglobals = BooleanVar(top)
142 ##self.vglobals.set(1)
143 self.bglobals = Checkbutton(cframe,
144 text="Globals", command=self.show_globals, variable=self.vglobals)
145 self.bglobals.grid(row=1, column=1)
146 #
147 self.status = Label(top, anchor="w")
148 self.status.pack(anchor="w")
149 self.error = Label(top, anchor="w")
150 self.error.pack(anchor="w", fill="x")
151 self.errorbg = self.error.cget("background")
152 #
153 self.fstack = Frame(top, height=1)
154 self.fstack.pack(expand=1, fill="both")
155 self.flocals = Frame(top)
156 self.flocals.pack(expand=1, fill="both")
157 self.fglobals = Frame(top, height=1)
158 self.fglobals.pack(expand=1, fill="both")
159 #
160 if self.vstack.get():
161 self.show_stack()
162 if self.vlocals.get():
163 self.show_locals()
164 if self.vglobals.get():
165 self.show_globals()
166
David Scherer7aced172000-08-15 01:13:23 +0000167
Chui Tey5d2af632002-05-26 13:36:41 +0000168 def interaction(self, message, frame, info=None):
David Scherer7aced172000-08-15 01:13:23 +0000169 self.frame = frame
David Scherer7aced172000-08-15 01:13:23 +0000170 self.status.configure(text=message)
171 #
172 if info:
173 type, value, tb = info
174 try:
175 m1 = type.__name__
176 except AttributeError:
177 m1 = "%s" % str(type)
178 if value is not None:
179 try:
180 m1 = "%s: %s" % (m1, str(value))
181 except:
182 pass
183 bg = "yellow"
184 else:
185 m1 = ""
186 tb = None
187 bg = self.errorbg
188 self.error.configure(text=m1, background=bg)
189 #
190 sv = self.stackviewer
191 if sv:
Chui Tey5d2af632002-05-26 13:36:41 +0000192 stack, i = self.idb.get_stack(self.frame, tb)
David Scherer7aced172000-08-15 01:13:23 +0000193 sv.load_stack(stack, i)
194 #
195 self.show_variables(1)
196 #
197 if self.vsource.get():
198 self.sync_source_line()
199 #
200 for b in self.buttons:
201 b.configure(state="normal")
202 #
203 self.top.tkraise()
204 self.root.mainloop()
205 #
206 for b in self.buttons:
207 b.configure(state="disabled")
208 self.status.configure(text="")
209 self.error.configure(text="", background=self.errorbg)
210 self.frame = None
211
212 def sync_source_line(self):
213 frame = self.frame
214 if not frame:
215 return
Chui Tey5d2af632002-05-26 13:36:41 +0000216 filename, lineno = self.__frame2fileline(frame)
217 if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
218 self.flist.gotofileline(filename, lineno)
219
220 def __frame2fileline(self, frame):
David Scherer7aced172000-08-15 01:13:23 +0000221 code = frame.f_code
Chui Tey5d2af632002-05-26 13:36:41 +0000222 filename = code.co_filename
David Scherer7aced172000-08-15 01:13:23 +0000223 lineno = frame.f_lineno
Chui Tey5d2af632002-05-26 13:36:41 +0000224 return filename, lineno
David Scherer7aced172000-08-15 01:13:23 +0000225
226 def cont(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000227 self.idb.set_continue()
David Scherer7aced172000-08-15 01:13:23 +0000228 self.root.quit()
229
230 def step(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000231 self.idb.set_step()
David Scherer7aced172000-08-15 01:13:23 +0000232 self.root.quit()
233
234 def next(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000235 self.idb.set_next(self.frame)
David Scherer7aced172000-08-15 01:13:23 +0000236 self.root.quit()
237
238 def ret(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000239 self.idb.set_return(self.frame)
David Scherer7aced172000-08-15 01:13:23 +0000240 self.root.quit()
241
242 def quit(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000243 self.idb.set_quit()
David Scherer7aced172000-08-15 01:13:23 +0000244 self.root.quit()
245
246 stackviewer = None
247
248 def show_stack(self):
249 if not self.stackviewer and self.vstack.get():
250 self.stackviewer = sv = StackViewer.StackViewer(
251 self.fstack, self.flist, self)
252 if self.frame:
Chui Tey5d2af632002-05-26 13:36:41 +0000253 stack, i = self.idb.get_stack(self.frame, None)
David Scherer7aced172000-08-15 01:13:23 +0000254 sv.load_stack(stack, i)
255 else:
256 sv = self.stackviewer
257 if sv and not self.vstack.get():
258 self.stackviewer = None
259 sv.close()
260 self.fstack['height'] = 1
261
262 def show_source(self):
263 if self.vsource.get():
264 self.sync_source_line()
265
266 def show_frame(self, (frame, lineno)):
Chui Tey5d2af632002-05-26 13:36:41 +0000267 # Called from OldStackViewer
David Scherer7aced172000-08-15 01:13:23 +0000268 self.frame = frame
269 self.show_variables()
270
271 localsviewer = None
272 globalsviewer = None
273
274 def show_locals(self):
275 lv = self.localsviewer
276 if self.vlocals.get():
277 if not lv:
278 self.localsviewer = StackViewer.NamespaceViewer(
279 self.flocals, "Locals")
280 else:
281 if lv:
282 self.localsviewer = None
283 lv.close()
284 self.flocals['height'] = 1
285 self.show_variables()
286
287 def show_globals(self):
288 gv = self.globalsviewer
289 if self.vglobals.get():
290 if not gv:
291 self.globalsviewer = StackViewer.NamespaceViewer(
292 self.fglobals, "Globals")
293 else:
294 if gv:
295 self.globalsviewer = None
296 gv.close()
297 self.fglobals['height'] = 1
298 self.show_variables()
299
300 def show_variables(self, force=0):
301 lv = self.localsviewer
302 gv = self.globalsviewer
303 frame = self.frame
304 if not frame:
305 ldict = gdict = None
306 else:
307 ldict = frame.f_locals
308 gdict = frame.f_globals
309 if lv and gv and ldict is gdict:
310 ldict = None
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000311 # Calls OldStackviewer.NamespaceViewer.load_dict():
David Scherer7aced172000-08-15 01:13:23 +0000312 if lv:
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000313 lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000314 if gv:
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000315 gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000316
317 def set_breakpoint_here(self, edit):
318 text = edit.text
319 filename = edit.io.filename
320 if not filename:
321 text.bell()
322 return
323 lineno = int(float(text.index("insert")))
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000324 msg = self.idb.set_break(filename, lineno)
David Scherer7aced172000-08-15 01:13:23 +0000325 if msg:
326 text.bell()
327 return
328 text.tag_add("BREAK", "insert linestart", "insert lineend +1char")
329
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000330 def clear_breakpoint_here(self, edit):
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000331 text = edit.text
332 filename = edit.io.filename
333 if not filename:
334 text.bell()
335 return
336 lineno = int(float(text.index("insert")))
337 msg = self.idb.clear_break(filename, lineno)
338 if msg:
339 text.bell()
340 return
341 text.tag_remove("BREAK", "insert linestart",\
342 "insert lineend +1char")
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000343
Kurt B. Kaiser83118c62002-06-24 17:03:37 +0000344 def clear_file_breaks(self, edit):
345 text = edit.text
346 filename = edit.io.filename
347 if not filename:
348 text.bell()
349 return
350 msg = self.idb.clear_all_file_breaks(filename)
351 if msg:
352 text.bell()
353 return
354 text.tag_delete("BREAK")