blob: 46531469e87dda5766f9c44a5c8ff27153b023d1 [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
79 self.pyshell.close_debugger()
80 self.top.destroy()
81
David Scherer7aced172000-08-15 01:13:23 +000082 def make_gui(self):
83 pyshell = self.pyshell
84 self.flist = pyshell.flist
85 self.root = root = pyshell.root
86 self.top = top =ListedToplevel(root)
87 self.top.wm_title("Debug Control")
88 self.top.wm_iconname("Debug")
89 top.wm_protocol("WM_DELETE_WINDOW", self.close)
90 self.top.bind("<Escape>", self.close)
91 #
92 self.bframe = bframe = Frame(top)
93 self.bframe.pack(anchor="w")
94 self.buttons = bl = []
95 #
96 self.bcont = b = Button(bframe, text="Go", command=self.cont)
97 bl.append(b)
98 self.bstep = b = Button(bframe, text="Step", command=self.step)
99 bl.append(b)
100 self.bnext = b = Button(bframe, text="Over", command=self.next)
101 bl.append(b)
102 self.bret = b = Button(bframe, text="Out", command=self.ret)
103 bl.append(b)
104 self.bret = b = Button(bframe, text="Quit", command=self.quit)
105 bl.append(b)
106 #
107 for b in bl:
108 b.configure(state="disabled")
109 b.pack(side="left")
110 #
111 self.cframe = cframe = Frame(bframe)
112 self.cframe.pack(side="left")
113 #
114 if not self.vstack:
115 self.__class__.vstack = BooleanVar(top)
116 self.vstack.set(1)
117 self.bstack = Checkbutton(cframe,
118 text="Stack", command=self.show_stack, variable=self.vstack)
119 self.bstack.grid(row=0, column=0)
120 if not self.vsource:
121 self.__class__.vsource = BooleanVar(top)
122 ##self.vsource.set(1)
123 self.bsource = Checkbutton(cframe,
124 text="Source", command=self.show_source, variable=self.vsource)
125 self.bsource.grid(row=0, column=1)
126 if not self.vlocals:
127 self.__class__.vlocals = BooleanVar(top)
128 self.vlocals.set(1)
129 self.blocals = Checkbutton(cframe,
130 text="Locals", command=self.show_locals, variable=self.vlocals)
131 self.blocals.grid(row=1, column=0)
132 if not self.vglobals:
133 self.__class__.vglobals = BooleanVar(top)
134 ##self.vglobals.set(1)
135 self.bglobals = Checkbutton(cframe,
136 text="Globals", command=self.show_globals, variable=self.vglobals)
137 self.bglobals.grid(row=1, column=1)
138 #
139 self.status = Label(top, anchor="w")
140 self.status.pack(anchor="w")
141 self.error = Label(top, anchor="w")
142 self.error.pack(anchor="w", fill="x")
143 self.errorbg = self.error.cget("background")
144 #
145 self.fstack = Frame(top, height=1)
146 self.fstack.pack(expand=1, fill="both")
147 self.flocals = Frame(top)
148 self.flocals.pack(expand=1, fill="both")
149 self.fglobals = Frame(top, height=1)
150 self.fglobals.pack(expand=1, fill="both")
151 #
152 if self.vstack.get():
153 self.show_stack()
154 if self.vlocals.get():
155 self.show_locals()
156 if self.vglobals.get():
157 self.show_globals()
158
David Scherer7aced172000-08-15 01:13:23 +0000159
Chui Tey5d2af632002-05-26 13:36:41 +0000160 def interaction(self, message, frame, info=None):
David Scherer7aced172000-08-15 01:13:23 +0000161 self.frame = frame
David Scherer7aced172000-08-15 01:13:23 +0000162 self.status.configure(text=message)
163 #
164 if info:
165 type, value, tb = info
166 try:
167 m1 = type.__name__
168 except AttributeError:
169 m1 = "%s" % str(type)
170 if value is not None:
171 try:
172 m1 = "%s: %s" % (m1, str(value))
173 except:
174 pass
175 bg = "yellow"
176 else:
177 m1 = ""
178 tb = None
179 bg = self.errorbg
180 self.error.configure(text=m1, background=bg)
181 #
182 sv = self.stackviewer
183 if sv:
Chui Tey5d2af632002-05-26 13:36:41 +0000184 stack, i = self.idb.get_stack(self.frame, tb)
David Scherer7aced172000-08-15 01:13:23 +0000185 sv.load_stack(stack, i)
186 #
187 self.show_variables(1)
188 #
189 if self.vsource.get():
190 self.sync_source_line()
191 #
192 for b in self.buttons:
193 b.configure(state="normal")
194 #
195 self.top.tkraise()
196 self.root.mainloop()
197 #
198 for b in self.buttons:
199 b.configure(state="disabled")
200 self.status.configure(text="")
201 self.error.configure(text="", background=self.errorbg)
202 self.frame = None
203
204 def sync_source_line(self):
205 frame = self.frame
206 if not frame:
207 return
Chui Tey5d2af632002-05-26 13:36:41 +0000208 filename, lineno = self.__frame2fileline(frame)
209 if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
210 self.flist.gotofileline(filename, lineno)
211
212 def __frame2fileline(self, frame):
David Scherer7aced172000-08-15 01:13:23 +0000213 code = frame.f_code
Chui Tey5d2af632002-05-26 13:36:41 +0000214 filename = code.co_filename
David Scherer7aced172000-08-15 01:13:23 +0000215 lineno = frame.f_lineno
Chui Tey5d2af632002-05-26 13:36:41 +0000216 return filename, lineno
David Scherer7aced172000-08-15 01:13:23 +0000217
218 def cont(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000219 self.idb.set_continue()
David Scherer7aced172000-08-15 01:13:23 +0000220 self.root.quit()
221
222 def step(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000223 self.idb.set_step()
David Scherer7aced172000-08-15 01:13:23 +0000224 self.root.quit()
225
226 def next(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000227 self.idb.set_next(self.frame)
David Scherer7aced172000-08-15 01:13:23 +0000228 self.root.quit()
229
230 def ret(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000231 self.idb.set_return(self.frame)
David Scherer7aced172000-08-15 01:13:23 +0000232 self.root.quit()
233
234 def quit(self):
Chui Tey5d2af632002-05-26 13:36:41 +0000235 self.idb.set_quit()
David Scherer7aced172000-08-15 01:13:23 +0000236 self.root.quit()
237
238 stackviewer = None
239
240 def show_stack(self):
241 if not self.stackviewer and self.vstack.get():
242 self.stackviewer = sv = StackViewer.StackViewer(
243 self.fstack, self.flist, self)
244 if self.frame:
Chui Tey5d2af632002-05-26 13:36:41 +0000245 stack, i = self.idb.get_stack(self.frame, None)
David Scherer7aced172000-08-15 01:13:23 +0000246 sv.load_stack(stack, i)
247 else:
248 sv = self.stackviewer
249 if sv and not self.vstack.get():
250 self.stackviewer = None
251 sv.close()
252 self.fstack['height'] = 1
253
254 def show_source(self):
255 if self.vsource.get():
256 self.sync_source_line()
257
258 def show_frame(self, (frame, lineno)):
Chui Tey5d2af632002-05-26 13:36:41 +0000259 # Called from OldStackViewer
David Scherer7aced172000-08-15 01:13:23 +0000260 self.frame = frame
261 self.show_variables()
262
263 localsviewer = None
264 globalsviewer = None
265
266 def show_locals(self):
267 lv = self.localsviewer
268 if self.vlocals.get():
269 if not lv:
270 self.localsviewer = StackViewer.NamespaceViewer(
271 self.flocals, "Locals")
272 else:
273 if lv:
274 self.localsviewer = None
275 lv.close()
276 self.flocals['height'] = 1
277 self.show_variables()
278
279 def show_globals(self):
280 gv = self.globalsviewer
281 if self.vglobals.get():
282 if not gv:
283 self.globalsviewer = StackViewer.NamespaceViewer(
284 self.fglobals, "Globals")
285 else:
286 if gv:
287 self.globalsviewer = None
288 gv.close()
289 self.fglobals['height'] = 1
290 self.show_variables()
291
292 def show_variables(self, force=0):
293 lv = self.localsviewer
294 gv = self.globalsviewer
295 frame = self.frame
296 if not frame:
297 ldict = gdict = None
298 else:
299 ldict = frame.f_locals
300 gdict = frame.f_globals
301 if lv and gv and ldict is gdict:
302 ldict = None
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000303 # Calls OldStackviewer.NamespaceViewer.load_dict():
David Scherer7aced172000-08-15 01:13:23 +0000304 if lv:
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000305 lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000306 if gv:
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000307 gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
David Scherer7aced172000-08-15 01:13:23 +0000308
309 def set_breakpoint_here(self, edit):
310 text = edit.text
311 filename = edit.io.filename
312 if not filename:
313 text.bell()
314 return
315 lineno = int(float(text.index("insert")))
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000316 msg = self.idb.set_break(filename, lineno)
David Scherer7aced172000-08-15 01:13:23 +0000317 if msg:
318 text.bell()
319 return
320 text.tag_add("BREAK", "insert linestart", "insert lineend +1char")
321
Kurt B. Kaiser669f4c32002-06-20 04:01:47 +0000322 def clear_breakpoint_here(self, edit):
323 text = edit.text
324 filename = edit.io.filename
325 if not filename:
326 text.bell()
327 return
328 lineno = int(float(text.index("insert")))
329 msg = self.idb.clear_break(filename, lineno)
330 if msg:
331 text.bell()
332 return
333 text.tag_remove("BREAK", "insert linestart",\
334 "insert lineend +1char")
335
336