blob: a4831685d0af3d0755b1b12e7f5e8a35d6806f65 [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
55 interacting = 0
David Scherer7aced172000-08-15 01:13:23 +000056 vstack = vsource = vlocals = vglobals = None
57
Chui Tey5d2af632002-05-26 13:36:41 +000058 def __init__(self, pyshell, idb=None):
59 if idb is None:
60 idb = Idb(self)
David Scherer7aced172000-08-15 01:13:23 +000061 self.pyshell = pyshell
Chui Tey5d2af632002-05-26 13:36:41 +000062 self.idb = idb
David Scherer7aced172000-08-15 01:13:23 +000063 self.make_gui()
Kurt B. Kaiser5291d462001-07-13 00:07:42 +000064
Chui Tey5d2af632002-05-26 13:36:41 +000065 def run(self, *args):
66 try:
67 self.interacting = 1
68 return self.idb.run(*args)
69 finally:
70 self.interacting = 0
David Scherer7aced172000-08-15 01:13:23 +000071
72 def close(self, event=None):
73 if self.interacting:
74 self.top.bell()
75 return
76 if self.stackviewer:
77 self.stackviewer.close(); self.stackviewer = None
78 self.pyshell.close_debugger()
79 self.top.destroy()
80
David Scherer7aced172000-08-15 01:13:23 +000081 def make_gui(self):
82 pyshell = self.pyshell
83 self.flist = pyshell.flist
84 self.root = root = pyshell.root
85 self.top = top =ListedToplevel(root)
86 self.top.wm_title("Debug Control")
87 self.top.wm_iconname("Debug")
88 top.wm_protocol("WM_DELETE_WINDOW", self.close)
89 self.top.bind("<Escape>", self.close)
90 #
91 self.bframe = bframe = Frame(top)
92 self.bframe.pack(anchor="w")
93 self.buttons = bl = []
94 #
95 self.bcont = b = Button(bframe, text="Go", command=self.cont)
96 bl.append(b)
97 self.bstep = b = Button(bframe, text="Step", command=self.step)
98 bl.append(b)
99 self.bnext = b = Button(bframe, text="Over", command=self.next)
100 bl.append(b)
101 self.bret = b = Button(bframe, text="Out", command=self.ret)
102 bl.append(b)
103 self.bret = b = Button(bframe, text="Quit", command=self.quit)
104 bl.append(b)
105 #
106 for b in bl:
107 b.configure(state="disabled")
108 b.pack(side="left")
109 #
110 self.cframe = cframe = Frame(bframe)
111 self.cframe.pack(side="left")
112 #
113 if not self.vstack:
114 self.__class__.vstack = BooleanVar(top)
115 self.vstack.set(1)
116 self.bstack = Checkbutton(cframe,
117 text="Stack", command=self.show_stack, variable=self.vstack)
118 self.bstack.grid(row=0, column=0)
119 if not self.vsource:
120 self.__class__.vsource = BooleanVar(top)
121 ##self.vsource.set(1)
122 self.bsource = Checkbutton(cframe,
123 text="Source", command=self.show_source, variable=self.vsource)
124 self.bsource.grid(row=0, column=1)
125 if not self.vlocals:
126 self.__class__.vlocals = BooleanVar(top)
127 self.vlocals.set(1)
128 self.blocals = Checkbutton(cframe,
129 text="Locals", command=self.show_locals, variable=self.vlocals)
130 self.blocals.grid(row=1, column=0)
131 if not self.vglobals:
132 self.__class__.vglobals = BooleanVar(top)
133 ##self.vglobals.set(1)
134 self.bglobals = Checkbutton(cframe,
135 text="Globals", command=self.show_globals, variable=self.vglobals)
136 self.bglobals.grid(row=1, column=1)
137 #
138 self.status = Label(top, anchor="w")
139 self.status.pack(anchor="w")
140 self.error = Label(top, anchor="w")
141 self.error.pack(anchor="w", fill="x")
142 self.errorbg = self.error.cget("background")
143 #
144 self.fstack = Frame(top, height=1)
145 self.fstack.pack(expand=1, fill="both")
146 self.flocals = Frame(top)
147 self.flocals.pack(expand=1, fill="both")
148 self.fglobals = Frame(top, height=1)
149 self.fglobals.pack(expand=1, fill="both")
150 #
151 if self.vstack.get():
152 self.show_stack()
153 if self.vlocals.get():
154 self.show_locals()
155 if self.vglobals.get():
156 self.show_globals()
157
158 frame = None
159
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
303 if lv:
304 lv.load_dict(ldict, force)
305 if gv:
306 gv.load_dict(gdict, force)
307
308 def set_breakpoint_here(self, edit):
309 text = edit.text
310 filename = edit.io.filename
311 if not filename:
312 text.bell()
313 return
314 lineno = int(float(text.index("insert")))
315 msg = self.set_break(filename, lineno)
316 if msg:
317 text.bell()
318 return
319 text.tag_add("BREAK", "insert linestart", "insert lineend +1char")
320
321 # A literal copy of Bdb.set_break() without the print statement at the end
Chui Tey5d2af632002-05-26 13:36:41 +0000322 #def set_break(self, filename, lineno, temporary=0, cond = None):
323 # import linecache # Import as late as possible
324 # filename = self.canonic(filename)
325 # line = linecache.getline(filename, lineno)
326 # if not line:
327 # return 'That line does not exist!'
328 # if not self.breaks.has_key(filename):
329 # self.breaks[filename] = []
330 # list = self.breaks[filename]
331 # if not lineno in list:
332 # list.append(lineno)
333 # bp = bdb.Breakpoint(filename, lineno, temporary, cond)