blob: 03da015eb1e01bbf5b5ba8386459a563a0d834ff [file] [log] [blame]
Jack Jansen4892ab71996-09-24 15:35:50 +00001# Window-interface-independent part of twit
2import sys
3import types
4import bdb
5import types
6
7SIMPLE_TYPES=(
8 types.NoneType,
9 types.IntType,
10 types.LongType,
11 types.FloatType,
12 types.ComplexType,
13 types.StringType
14)
15
Jack Jansen13bfbe71996-09-25 14:09:35 +000016# XXXX Mac-specific
17ICON_NORMAL=512
18ICON_RETURN=515
19ICON_CALL=516
20ICON_ZERO=517
21ICON_DEAD=518
22
Jack Jansen4892ab71996-09-24 15:35:50 +000023def Initialize():
24 pass
25
26class DebuggerStuff(bdb.Bdb):
27
28 def __init__(self, parent):
29 bdb.Bdb.__init__(self)
30 self.parent = parent
31 self.exception_info = (None, None)
32 self.reason = 'Not running'
Jack Jansen13bfbe71996-09-25 14:09:35 +000033 self.icon = ICON_NORMAL
Jack Jansen4892ab71996-09-24 15:35:50 +000034 self.reset()
35
36 def reset(self):
37 bdb.Bdb.reset(self)
38 self.forget()
39
40 def forget(self):
Jack Jansen13bfbe71996-09-25 14:09:35 +000041 print 'FORGET'
Jack Jansen4892ab71996-09-24 15:35:50 +000042 self.lineno = None
43 self.stack = []
44 self.curindex = 0
45 self.curframe = None
46
47 def setup(self, f, t):
48 self.forget()
Jack Jansen13bfbe71996-09-25 14:09:35 +000049 print 'SETUP', f, t
Jack Jansen4892ab71996-09-24 15:35:50 +000050 self.stack, self.curindex = self.get_stack(f, t)
51 self.curframe = self.stack[self.curindex][0]
52
53 def interaction(self, frame, traceback):
54 self.setup(frame, traceback)
55 self.parent.interact()
56 self.exception_info = (None, None)
57
58 def user_call(self, frame, argument_list):
Jack Jansen13bfbe71996-09-25 14:09:35 +000059 self.reason = 'Calling'
60 self.icon = ICON_CALL
Jack Jansen4892ab71996-09-24 15:35:50 +000061 self.interaction(frame, None)
62
63 def user_line(self, frame):
64 self.reason = 'Stopped'
Jack Jansen13bfbe71996-09-25 14:09:35 +000065 self.icon = ICON_NORMAL
Jack Jansen4892ab71996-09-24 15:35:50 +000066 self.interaction(frame, None)
67
68 def user_return(self, frame, return_value):
Jack Jansen13bfbe71996-09-25 14:09:35 +000069 self.reason = 'Returning'
70 self.icon = ICON_RETURN
Jack Jansen4892ab71996-09-24 15:35:50 +000071 self.interaction(frame, None)
72
73 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
74 self.reason = 'Exception occurred'
Jack Jansen13bfbe71996-09-25 14:09:35 +000075 self.icon = ICON_DEAD
Jack Jansen4892ab71996-09-24 15:35:50 +000076 self.exception_info = (exc_type, exc_value)
77 self.interaction(frame, exc_traceback)
78
79 def getexception(self):
80 tp, value = self.exception_info
81 if tp <> None and type(tp) <> type(''):
82 tp = tp.__name__
83 if value <> None and type(value) <> type(''):
84 value = `value`
85 return tp, value
86
87 def getstacktrace(self):
Jack Jansen13bfbe71996-09-25 14:09:35 +000088 print 'DBG GETSTACKTRACE', self.stack
Jack Jansen4892ab71996-09-24 15:35:50 +000089 names, locations = [], []
90 for frame, lineno in self.stack:
91 name = frame.f_code.co_name
92 if not name:
93 name = "<lambda>"
94 elif name == '?':
95 name = "<not a function>"
96 else:
97 name = name + '()'
98 names.append(name)
99
100 if lineno == -1:
101 lineno = getframelineno(frame)
102
103 modname = getframemodname(frame)
104 if not modname: modname = "<unknown>"
105
106 locations.append("%s:%d" % (modname, lineno))
Jack Jansen13bfbe71996-09-25 14:09:35 +0000107 print 'DBG RETURNS', names, locations
Jack Jansen4892ab71996-09-24 15:35:50 +0000108 return names, locations
109
110 def getframe(self, number):
111 if number < 0 or number >= len(self.stack):
112 return None
113 return self.stack[number][0]
114
115 def getframevars(self, number, show_complex=1, show_system=1):
116 frame = self.getframe(number)
117 if not frame:
118 return [], []
119 return getvarsfromdict(frame.f_locals, show_complex, show_system)
120
121 def getframevar(self, number, var):
122 frame = self.getframe(number)
123 return frame.f_locals[var]
124
125 def getframefilepos(self, frameno):
126 if frameno == None or frameno < 0 or frameno >= len(self.stack):
127 return None, None, None
128 frame, line = self.stack[frameno]
129 if line == -1:
130 line = getframelineno(frame)
131 modname = getframemodname(frame)
132 filename = frame.f_code.co_filename
133 return filename, modname, line
134
135 def getprogramstate(self):
136 return self.reason
137
138class Application:
139 """Base code for the application"""
140
141 def mi_init(self, run_args, pm_args):
142 self.dbg = DebuggerStuff(self)
143 self.run_dialog = self.new_stack_browser(self)
144 self.run_dialog.open()
145 self.module_dialog = None
146 self.initial_cmd = None
Jack Jansen13bfbe71996-09-25 14:09:35 +0000147 self.cur_string_name = None
Jack Jansen4892ab71996-09-24 15:35:50 +0000148 if pm_args:
149 while pm_args.tb_next <> None:
150 pm_args = pm_args.tb_next
151 self.dbg.setup(pm_args.tb_frame, pm_args)
152 self.run_dialog.setsession_pm()
Jack Jansen13bfbe71996-09-25 14:09:35 +0000153 self.run_dialog.update_views()
Jack Jansen4892ab71996-09-24 15:35:50 +0000154 elif run_args:
155 self.run_dialog.setsession_run()
156 self.initial_cmd = run_args
157 else:
158 self.run_dialog.setsession_none()
159
160 def breaks_changed(self, filename):
161 self.run_dialog.breaks_changed(filename)
162 if self.module_dialog:
163 self.module_dialog.breaks_changed(filename)
164
165 def to_debugger(self):
166 apply(self.dbg.run, self.initial_cmd)
167
168 def interact(self):
169 # Interact with user. First, display correct info
170 self.run_dialog.update_views()
171 if self.module_dialog:
172 self.module_dialog.update_views()
173
174 # Next, go into mainloop
175 self.one_mainloop()
176
177 # Finally (before we start the debuggee again) show state
178 self.run_dialog.show_it_running()
179
180 def quit_bdb(self):
181 self.dbg.set_quit()
182
183 def run(self):
184 cmd = AskString('Statement to execute:')
Jack Jansen13bfbe71996-09-25 14:09:35 +0000185 self.cur_string_name = '<string: "%s">'%cmd
186 try:
187 cmd = compile(cmd, self.cur_string_name, 'exec')
188 except SyntaxError, arg:
189 ShowMessage('Syntax error: %s'%`arg`)
190 return
Jack Jansen4892ab71996-09-24 15:35:50 +0000191 self.initial_cmd = (cmd, None, None)
192 self.run_dialog.setsession_run()
193 self.exit_mainloop()
194
195 def cont(self):
196 self.dbg.set_continue()
197 self.exit_mainloop()
198
199 def step(self, frame):
200 self.dbg.set_next(frame)
201 self.exit_mainloop()
202
203 def step_in(self):
204 self.dbg.set_step()
205 self.exit_mainloop()
206
207 def step_out(self, frame):
208 self.dbg.set_return(frame)
209 self.exit_mainloop()
210
211 def quit(self):
212 self.do_quit()
213
214 def browse(self, module):
215 if not self.module_dialog:
216 self.module_dialog = self.new_module_browser(self)
217 self.module_dialog.open(module)
218 else:
219 self.module_dialog.focus(module)
220
221 def browse_var(self, var):
222 b = self.new_var_browser(self, var)
223
224class StackBrowser:
225 """Base code for stack browser"""
226 def mi_open(self):
227 """Setup initial data structures"""
228 self.create_items()
229 self.cur_stackitem = None
230 self.cur_source = None
231 self.cur_modname = None
232 self.cur_line = None
233 self.show_complex = 1
234 self.show_system = 0
235 self.setup()
236
237 # create_items(self) should create self.modules, self.vars and self.source
238
239 def setup(self):
240 SetWatch()
241 """Fill the various widgets with values"""
242 name, value = self.parent.dbg.getexception()
243 self.setexception(name, value)
244 self.setprogramstate(self.parent.dbg.getprogramstate())
245
246 names, locations = self.parent.dbg.getstacktrace()
247 self.stack.setcontent(names, locations)
248 self.cur_stackitem = len(names)-1
249 self.stack.select(self.cur_stackitem)
250 self.setup_frame()
251
252 def setup_frame(self):
253 """Setup frame-dependent widget data"""
254 SetWatch()
255 self.cont_varnames, self.cont_varvalues = \
256 self.parent.dbg.getframevars(self.cur_stackitem,
257 self.show_complex, self.show_system)
258 self.vars.setcontent(self.cont_varnames, self.cont_varvalues)
259 self.set_var_buttons()
260
261 msg = ""
262 if self.cur_stackitem == None:
263 self.cur_source = None
264 self.cur_modname = None
265 self.cur_line = None
266 msg = "No stackframe selected"
267 else:
268 self.cur_source, self.cur_modname, optnextline = \
269 self.parent.dbg.getframefilepos(self.cur_stackitem)
270 if optnextline >= 0:
271 self.cur_line = optnextline
272 if self.cur_source == '<string>':
273 self.cur_source = None
Jack Jansen13bfbe71996-09-25 14:09:35 +0000274 msg = "Executing from unknown <string>"
275 elif type(self.cur_source) == types.StringType and \
276 self.cur_source[:8] == '<string:':
277 msg = "Executing from "+self.cur_source
278 self.cur_source = None
Jack Jansen4892ab71996-09-24 15:35:50 +0000279 print 'SOURCE', self.cur_source
280 print 'LINE', self.cur_line
281
282 self.setsource(msg)
Jack Jansen13bfbe71996-09-25 14:09:35 +0000283 if not self.cur_line:
284 self.source.setcurline(1, ICON_ZERO)
285 else:
286 self.source.setcurline(self.cur_line, self.parent.dbg.icon)
Jack Jansen4892ab71996-09-24 15:35:50 +0000287 self.breaks_changed(self.cur_source)
288
289
290 SetCursor()
291
292 # setsource(msg) should display cur_source+content, or msg if None
293
294 def show_it_running(self):
295 self.setprogramstate("Running")
296
297 def update_views(self):
298 self.setup()
299
300 def click_stack(self, number, *dummy):
301 if number == self.cur_stackitem: return
302 self.cur_stackitem = number
303 self.stack.select(self.cur_stackitem)
304 self.setup_frame()
305
306 def click_var(self, var, *dummy):
307 v = self.parent.dbg.getframevar(self.cur_stackitem, var)
308 self.parent.browse_var(v)
309
310 def click_source(self, lineno, inborder):
311 if not inborder:
312 self.source.select(lineno)
313 self.cur_line = lineno
314 if lineno == None or not self.cur_source or not inborder:
315 return
316 if self.parent.dbg.get_break(self.cur_source, lineno):
317 self.parent.dbg.clear_break(self.cur_source, lineno)
318 else:
319 self.parent.dbg.set_break(self.cur_source, lineno)
320 self.parent.breaks_changed(self.cur_source)
321
322 def breaks_changed(self, filename):
323 if filename == self.cur_source:
324 list = self.parent.dbg.get_file_breaks(filename)
325 self.source.setbreaks(list)
326
327 def click_quit(self):
328 self.parent.quit()
329
330 def click_run(self):
331 self.parent.run()
332
333 def click_continue(self):
334 self.parent.cont()
335
336 def click_step(self):
337 if self.cur_stackitem <> None:
338 frame = self.parent.dbg.getframe(self.cur_stackitem)
339 self.parent.step(frame)
340 else:
341 self.parent.step_in()
342
343 def click_step_in(self):
344 self.parent.step_in()
345
346 def click_step_out(self):
347 if self.cur_stackitem <> None:
348 frame = self.parent.dbg.getframe(self.cur_stackitem)
349 self.parent.step_out(frame)
350 else:
351 self.parent.step_in()
352
353 def click_browse(self):
354 self.parent.browse(self.cur_modname)
355
356 def click_edit(self):
357 lino = self.cur_line
358 if not lino:
359 lino = 1
360 if self.cur_source:
361 self.parent.edit(self.cur_source, lino)
362
363class ModuleBrowser:
364 """Base code for a module-browser"""
365
366 def mi_open(self, module):
367 """Setup initial data structures"""
368 self.create_items()
369 self.cur_module = module
370 self.cur_source = None
371 self.cur_line = None
372 self.cont_modules = []
373 self.value_windows = []
374 self.setup()
375
376 # create_items(self) should create self.modules, self.vars and self.source
377
378 def setup(self):
379 """Fill the various widgets with values"""
380 SetWatch()
381 modnames = getmodulenames()
382 if not self.cur_module in modnames:
383 self.cur_module = None
384 if modnames <> self.cont_modules:
385 self.modules.setcontent(modnames)
386 self.cont_modules = modnames
387 if self.cur_module:
388 self.modules.select(self.cont_modules.index(self.cur_module))
389 else:
390 self.modules.select(None)
391 self.setup_module()
392
393 def setup_module(self):
394 """Setup module-dependent widget data"""
395 SetWatch()
396 if not self.cur_module:
397 self.vars.setcontent([], [])
398 else:
399 self.cont_varnames, self.cont_varvalues = getmodulevars(self.cur_module)
400 self.vars.setcontent(self.cont_varnames, self.cont_varvalues)
401
402 msg = ""
403 if not self.cur_module:
404 self.cur_source = None
405 msg = "No module selected"
406 else:
407 m = sys.modules[self.cur_module]
408 try:
409 self.cur_source = m.__file__
410 except AttributeError:
411 self.cur_source = None
412 msg = "Not a python module"
413 self.cur_lineno = 0
414 self.setsource(msg)
415 self.source.select(self.cur_line)
416 self.breaks_changed(self.cur_source)
417
418 SetCursor()
419
420 # setsource(msg) should display cur_source+content, or msg if None
421
422 def update_views(self):
423 self.setup_module()
424
425 def click_module(self, module, *dummy):
426 if not module or module == self.cur_module: return
427 self.focus(module)
428
429 def focus(self, module):
430 self.cur_module = module
431 self.setup()
432
433 def click_var(self, var, *dummy):
434 if not var: return
435 m = sys.modules[self.cur_module]
436 dict = m.__dict__
437 self.parent.browse_var(dict[var])
438
439 def click_source(self, lineno, inborder):
440 if not inborder:
441 self.source.select(lineno)
442 self.cur_lineno = lineno
443 if lineno == None or not self.cur_source or not inborder:
444 return
445 if self.parent.dbg.get_break(self.cur_source, lineno):
446 self.parent.dbg.clear_break(self.cur_source, lineno)
447 else:
448 self.parent.dbg.set_break(self.cur_source, lineno)
449 self.parent.breaks_changed(self.cur_source)
450
451 def breaks_changed(self, filename):
452 if filename == self.cur_source:
453 list = self.parent.dbg.get_file_breaks(filename)
454 self.source.setbreaks(list)
455
456 def click_edit(self):
457 lino = self.cur_lineno
458 if not lino:
459 lino = 1
460 if self.cur_source:
461 self.parent.edit(self.cur_source, lino)
462
463
464def getmodulenames():
465 """Return a list of all current modules, sorted"""
466 list = sys.modules.keys()[:]
467 list.sort()
468 return list
469
470def getmodulevars(name):
471 """For given module return lists with names and values"""
472 m = sys.modules[name]
473 try:
474 dict = m.__dict__
475 except AttributeError:
476 dict = {}
477 return getvarsfromdict(dict)
478
479def getvarsfromdict(dict, show_complex=1, show_system=1):
480 allnames = dict.keys()[:]
481 allnames.sort()
482 names = []
483 for n in allnames:
484 if not show_complex:
485 if not type(dict[n]) in SIMPLE_TYPES:
486 continue
487 if not show_system:
488 if n[:2] == '__' and n[-2:] == '__':
489 continue
490 names.append(n)
491 values = []
492 for n in names:
493 v = pretty(dict[n])
494 values.append(v)
495 return names, values
496
497def pretty(var):
498 t = type(var)
499 if t == types.FunctionType: return '<function>'
500 if t == types.ClassType: return '<class>'
501 return `var`
502
503def getframelineno(frame):
504 """Given a frame return the line number"""
505 return getcodelineno(frame.f_code)
506
507def getfunclineno(func):
508 """Given a function return the line number"""
509 return getcodelineno(func.func_code)
510
511def getcodelineno(cobj):
512 """Given a code object return the line number"""
513 code = cobj.co_code
514 lineno = -1
515 if ord(code[0]) == 127: # SET_LINENO instruction
516 lineno = ord(code[1]) | (ord(code[2]) << 8)
517 return lineno
518
519def getframemodname(frame):
520 """Given a frame return the module name"""
521 globals = frame.f_globals
522 if globals.has_key('__name__'):
523 return globals['__name__']
524 return None