blob: 8cd8c0e428a5d360fa5aab6794833390c7abc5f7 [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
Jack Jansena1560cf1996-09-26 16:26:05 +00006import os
Jack Jansen4892ab71996-09-24 15:35:50 +00007
8SIMPLE_TYPES=(
9 types.NoneType,
10 types.IntType,
11 types.LongType,
12 types.FloatType,
13 types.ComplexType,
14 types.StringType
15)
16
Jack Jansen13bfbe71996-09-25 14:09:35 +000017# XXXX Mac-specific
Jack Jansenb280e2b1996-12-23 17:11:00 +000018ICON_NORMAL=500
19ICON_RETURN=503
20ICON_CALL=504
21ICON_ZERO=505
22ICON_DEAD=506
Jack Jansen13bfbe71996-09-25 14:09:35 +000023
Jack Jansen4892ab71996-09-24 15:35:50 +000024class DebuggerStuff(bdb.Bdb):
25
26 def __init__(self, parent):
27 bdb.Bdb.__init__(self)
28 self.parent = parent
29 self.exception_info = (None, None)
30 self.reason = 'Not running'
Jack Jansen13bfbe71996-09-25 14:09:35 +000031 self.icon = ICON_NORMAL
Jack Jansen4892ab71996-09-24 15:35:50 +000032 self.reset()
33
34 def reset(self):
35 bdb.Bdb.reset(self)
36 self.forget()
37
38 def forget(self):
39 self.lineno = None
40 self.stack = []
41 self.curindex = 0
42 self.curframe = None
Jack Jansena1560cf1996-09-26 16:26:05 +000043
44 def run(self, cmd, locals, globals):
45 self.reason = 'Running'
46 bdb.Bdb.run(self, cmd, locals, globals)
47 print 'RETURN from run'
48 self.reason = 'Not running'
Jack Jansen4892ab71996-09-24 15:35:50 +000049
50 def setup(self, f, t):
51 self.forget()
52 self.stack, self.curindex = self.get_stack(f, t)
53 self.curframe = self.stack[self.curindex][0]
54
55 def interaction(self, frame, traceback):
56 self.setup(frame, traceback)
57 self.parent.interact()
58 self.exception_info = (None, None)
59
Jack Jansena1560cf1996-09-26 16:26:05 +000060# def user_call(self, frame, argument_list):
61# self.reason = 'Calling'
62# self.icon = ICON_CALL
63# self.interaction(frame, None)
Jack Jansen4892ab71996-09-24 15:35:50 +000064
65 def user_line(self, frame):
66 self.reason = 'Stopped'
Jack Jansen13bfbe71996-09-25 14:09:35 +000067 self.icon = ICON_NORMAL
Jack Jansen4892ab71996-09-24 15:35:50 +000068 self.interaction(frame, None)
69
70 def user_return(self, frame, return_value):
Jack Jansen13bfbe71996-09-25 14:09:35 +000071 self.reason = 'Returning'
72 self.icon = ICON_RETURN
Jack Jansen4892ab71996-09-24 15:35:50 +000073 self.interaction(frame, None)
74
75 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
76 self.reason = 'Exception occurred'
Jack Jansen13bfbe71996-09-25 14:09:35 +000077 self.icon = ICON_DEAD
Jack Jansena1560cf1996-09-26 16:26:05 +000078 self.parent.setstate('tb')
Jack Jansen4892ab71996-09-24 15:35:50 +000079 self.exception_info = (exc_type, exc_value)
80 self.interaction(frame, exc_traceback)
81
82 def getexception(self):
83 tp, value = self.exception_info
84 if tp <> None and type(tp) <> type(''):
85 tp = tp.__name__
86 if value <> None and type(value) <> type(''):
87 value = `value`
88 return tp, value
89
90 def getstacktrace(self):
91 names, locations = [], []
92 for frame, lineno in self.stack:
93 name = frame.f_code.co_name
94 if not name:
95 name = "<lambda>"
96 elif name == '?':
97 name = "<not a function>"
98 else:
99 name = name + '()'
100 names.append(name)
101
102 if lineno == -1:
103 lineno = getframelineno(frame)
104
105 modname = getframemodname(frame)
106 if not modname: modname = "<unknown>"
107
108 locations.append("%s:%d" % (modname, lineno))
109 return names, locations
110
111 def getframe(self, number):
112 if number < 0 or number >= len(self.stack):
113 return None
114 return self.stack[number][0]
115
116 def getframevars(self, number, show_complex=1, show_system=1):
117 frame = self.getframe(number)
118 if not frame:
119 return [], []
120 return getvarsfromdict(frame.f_locals, show_complex, show_system)
121
122 def getframevar(self, number, var):
123 frame = self.getframe(number)
124 return frame.f_locals[var]
125
126 def getframefilepos(self, frameno):
127 if frameno == None or frameno < 0 or frameno >= len(self.stack):
128 return None, None, None
129 frame, line = self.stack[frameno]
130 if line == -1:
131 line = getframelineno(frame)
132 modname = getframemodname(frame)
133 filename = frame.f_code.co_filename
134 return filename, modname, line
135
136 def getprogramstate(self):
137 return self.reason
138
139class Application:
140 """Base code for the application"""
141
Jack Jansena1560cf1996-09-26 16:26:05 +0000142 def mi_init(self, sessiontype, arg):
Jack Jansen4892ab71996-09-24 15:35:50 +0000143 self.dbg = DebuggerStuff(self)
144 self.run_dialog = self.new_stack_browser(self)
145 self.run_dialog.open()
146 self.module_dialog = None
147 self.initial_cmd = None
Jack Jansen13bfbe71996-09-25 14:09:35 +0000148 self.cur_string_name = None
Jack Jansena1560cf1996-09-26 16:26:05 +0000149 if sessiontype == 'tb':
150 while arg.tb_next <> None:
151 arg = arg.tb_next
152 self.dbg.setup(arg.tb_frame, arg)
153 self.run_dialog.setup()
154 elif sessiontype == 'run':
155 self.initial_cmd = arg
156
Jack Jansen4892ab71996-09-24 15:35:50 +0000157 def breaks_changed(self, filename):
158 self.run_dialog.breaks_changed(filename)
159 if self.module_dialog:
160 self.module_dialog.breaks_changed(filename)
161
162 def to_debugger(self):
Jack Jansena1560cf1996-09-26 16:26:05 +0000163 cmd = self.initial_cmd
164 self.initial_cmd = None
165 self.setstate('run')
166 self.switch_to_app()
167 apply(self.dbg.run, cmd)
168 self.setstate('none')
169 self.switch_to_dbg()
170 self.run_dialog.update_views()
171 if self.module_dialog:
172 self.module_dialog.update_views()
Jack Jansen4892ab71996-09-24 15:35:50 +0000173
174 def interact(self):
175 # Interact with user. First, display correct info
Jack Jansena1560cf1996-09-26 16:26:05 +0000176 self.switch_to_dbg()
Jack Jansen4892ab71996-09-24 15:35:50 +0000177 self.run_dialog.update_views()
178 if self.module_dialog:
179 self.module_dialog.update_views()
180
181 # Next, go into mainloop
182 self.one_mainloop()
183
184 # Finally (before we start the debuggee again) show state
Jack Jansena1560cf1996-09-26 16:26:05 +0000185 self.switch_to_app()
Jack Jansen4892ab71996-09-24 15:35:50 +0000186 self.run_dialog.show_it_running()
187
188 def quit_bdb(self):
189 self.dbg.set_quit()
190
191 def run(self):
Jack Jansena1560cf1996-09-26 16:26:05 +0000192 cmd = self.AskString('Statement to execute:')
193 self.runstring(cmd)
194
195 def runfile(self, path):
196 dir, file = os.path.split(path)
197 try:
198 os.chdir(dir)
199 except os.error, arg:
200 self.Message("%s: %s"%(dir, arg))
201 return
202 ns = {'__name__':'__main__', '__file__':path}
203 cmd = "execfile('%s')"%file
204 self.runstring(cmd, ns, ns)
205
206 def runstring(self, cmd, globals={}, locals={}):
Jack Jansen13bfbe71996-09-25 14:09:35 +0000207 self.cur_string_name = '<string: "%s">'%cmd
208 try:
209 cmd = compile(cmd, self.cur_string_name, 'exec')
210 except SyntaxError, arg:
Jack Jansena1560cf1996-09-26 16:26:05 +0000211 self.Message('Syntax error: %s'%`arg`)
Jack Jansen13bfbe71996-09-25 14:09:35 +0000212 return
Jack Jansena1560cf1996-09-26 16:26:05 +0000213 self.initial_cmd = (cmd, globals, locals)
Jack Jansen4892ab71996-09-24 15:35:50 +0000214 self.exit_mainloop()
215
216 def cont(self):
217 self.dbg.set_continue()
218 self.exit_mainloop()
219
220 def step(self, frame):
221 self.dbg.set_next(frame)
222 self.exit_mainloop()
223
224 def step_in(self):
225 self.dbg.set_step()
226 self.exit_mainloop()
227
228 def step_out(self, frame):
229 self.dbg.set_return(frame)
230 self.exit_mainloop()
231
Jack Jansena1560cf1996-09-26 16:26:05 +0000232 def kill(self):
233 self.dbg.set_quit()
234 self.exit_mainloop()
235
Jack Jansen4892ab71996-09-24 15:35:50 +0000236 def quit(self):
237 self.do_quit()
238
239 def browse(self, module):
240 if not self.module_dialog:
241 self.module_dialog = self.new_module_browser(self)
242 self.module_dialog.open(module)
243 else:
244 self.module_dialog.focus(module)
245
246 def browse_var(self, var):
247 b = self.new_var_browser(self, var)
248
249class StackBrowser:
250 """Base code for stack browser"""
251 def mi_open(self):
252 """Setup initial data structures"""
Jack Jansen4892ab71996-09-24 15:35:50 +0000253 self.cur_stackitem = None
254 self.cur_source = None
255 self.cur_modname = None
256 self.cur_line = None
257 self.show_complex = 1
258 self.show_system = 0
259 self.setup()
260
261 # create_items(self) should create self.modules, self.vars and self.source
262
263 def setup(self):
Jack Jansena1560cf1996-09-26 16:26:05 +0000264 self.parent.SetWatch()
Jack Jansen4892ab71996-09-24 15:35:50 +0000265 """Fill the various widgets with values"""
266 name, value = self.parent.dbg.getexception()
267 self.setexception(name, value)
268 self.setprogramstate(self.parent.dbg.getprogramstate())
269
270 names, locations = self.parent.dbg.getstacktrace()
Jack Jansen0eb88371996-10-09 09:38:46 +0000271 self.stack_setcontent(names, locations)
Jack Jansen4892ab71996-09-24 15:35:50 +0000272 self.cur_stackitem = len(names)-1
Jack Jansen0eb88371996-10-09 09:38:46 +0000273 self.stack_select(self.cur_stackitem)
Jack Jansen4892ab71996-09-24 15:35:50 +0000274 self.setup_frame()
275
276 def setup_frame(self):
277 """Setup frame-dependent widget data"""
Jack Jansena1560cf1996-09-26 16:26:05 +0000278 self.parent.SetWatch()
Jack Jansen4892ab71996-09-24 15:35:50 +0000279 self.cont_varnames, self.cont_varvalues = \
280 self.parent.dbg.getframevars(self.cur_stackitem,
281 self.show_complex, self.show_system)
Jack Jansen0eb88371996-10-09 09:38:46 +0000282 self.setvars()
Jack Jansen4892ab71996-09-24 15:35:50 +0000283 self.set_var_buttons()
284
285 msg = ""
286 if self.cur_stackitem == None:
287 self.cur_source = None
288 self.cur_modname = None
289 self.cur_line = None
290 msg = "No stackframe selected"
291 else:
292 self.cur_source, self.cur_modname, optnextline = \
293 self.parent.dbg.getframefilepos(self.cur_stackitem)
294 if optnextline >= 0:
295 self.cur_line = optnextline
296 if self.cur_source == '<string>':
297 self.cur_source = None
Jack Jansen13bfbe71996-09-25 14:09:35 +0000298 msg = "Executing from unknown <string>"
299 elif type(self.cur_source) == types.StringType and \
300 self.cur_source[:8] == '<string:':
301 msg = "Executing from "+self.cur_source
302 self.cur_source = None
Jack Jansen4892ab71996-09-24 15:35:50 +0000303
304 self.setsource(msg)
Jack Jansen13bfbe71996-09-25 14:09:35 +0000305 if not self.cur_line:
Jack Jansen0eb88371996-10-09 09:38:46 +0000306 self.source_setline(1, ICON_ZERO)
Jack Jansen13bfbe71996-09-25 14:09:35 +0000307 else:
Jack Jansen0eb88371996-10-09 09:38:46 +0000308 self.source_setline(self.cur_line, self.parent.dbg.icon)
Jack Jansen4892ab71996-09-24 15:35:50 +0000309 self.breaks_changed(self.cur_source)
310
311
Jack Jansena1560cf1996-09-26 16:26:05 +0000312 self.parent.SetCursor()
Jack Jansen4892ab71996-09-24 15:35:50 +0000313
314 # setsource(msg) should display cur_source+content, or msg if None
315
316 def show_it_running(self):
317 self.setprogramstate("Running")
318
319 def update_views(self):
320 self.setup()
321
322 def click_stack(self, number, *dummy):
323 if number == self.cur_stackitem: return
324 self.cur_stackitem = number
Jack Jansen0eb88371996-10-09 09:38:46 +0000325 self.stack_select(self.cur_stackitem)
Jack Jansen4892ab71996-09-24 15:35:50 +0000326 self.setup_frame()
327
328 def click_var(self, var, *dummy):
329 v = self.parent.dbg.getframevar(self.cur_stackitem, var)
330 self.parent.browse_var(v)
331
332 def click_source(self, lineno, inborder):
333 if not inborder:
Jack Jansen0eb88371996-10-09 09:38:46 +0000334 self.source_select(lineno)
Jack Jansen4892ab71996-09-24 15:35:50 +0000335 self.cur_line = lineno
336 if lineno == None or not self.cur_source or not inborder:
337 return
338 if self.parent.dbg.get_break(self.cur_source, lineno):
339 self.parent.dbg.clear_break(self.cur_source, lineno)
340 else:
341 self.parent.dbg.set_break(self.cur_source, lineno)
342 self.parent.breaks_changed(self.cur_source)
343
344 def breaks_changed(self, filename):
345 if filename == self.cur_source:
346 list = self.parent.dbg.get_file_breaks(filename)
Jack Jansen0eb88371996-10-09 09:38:46 +0000347 self.source_setbreaks(list)
Jack Jansen4892ab71996-09-24 15:35:50 +0000348
349 def click_quit(self):
350 self.parent.quit()
351
352 def click_run(self):
353 self.parent.run()
354
355 def click_continue(self):
356 self.parent.cont()
357
358 def click_step(self):
359 if self.cur_stackitem <> None:
360 frame = self.parent.dbg.getframe(self.cur_stackitem)
361 self.parent.step(frame)
362 else:
363 self.parent.step_in()
364
365 def click_step_in(self):
366 self.parent.step_in()
367
368 def click_step_out(self):
369 if self.cur_stackitem <> None:
370 frame = self.parent.dbg.getframe(self.cur_stackitem)
371 self.parent.step_out(frame)
372 else:
373 self.parent.step_in()
Jack Jansena1560cf1996-09-26 16:26:05 +0000374
375 def click_kill(self):
376 self.parent.kill()
Jack Jansen4892ab71996-09-24 15:35:50 +0000377
378 def click_browse(self):
379 self.parent.browse(self.cur_modname)
380
381 def click_edit(self):
382 lino = self.cur_line
383 if not lino:
384 lino = 1
385 if self.cur_source:
386 self.parent.edit(self.cur_source, lino)
387
388class ModuleBrowser:
389 """Base code for a module-browser"""
390
391 def mi_open(self, module):
392 """Setup initial data structures"""
Jack Jansen4892ab71996-09-24 15:35:50 +0000393 self.cur_module = module
394 self.cur_source = None
395 self.cur_line = None
396 self.cont_modules = []
397 self.value_windows = []
398 self.setup()
399
400 # create_items(self) should create self.modules, self.vars and self.source
401
402 def setup(self):
403 """Fill the various widgets with values"""
Jack Jansena1560cf1996-09-26 16:26:05 +0000404 self.parent.SetWatch()
Jack Jansen4892ab71996-09-24 15:35:50 +0000405 modnames = getmodulenames()
406 if not self.cur_module in modnames:
407 self.cur_module = None
408 if modnames <> self.cont_modules:
Jack Jansen4892ab71996-09-24 15:35:50 +0000409 self.cont_modules = modnames
Jack Jansen0eb88371996-10-09 09:38:46 +0000410 self.setmodulenames()
Jack Jansen4892ab71996-09-24 15:35:50 +0000411 if self.cur_module:
Jack Jansen0eb88371996-10-09 09:38:46 +0000412 self.module_select(self.cont_modules.index(self.cur_module))
Jack Jansen4892ab71996-09-24 15:35:50 +0000413 else:
Jack Jansen0eb88371996-10-09 09:38:46 +0000414 self.module_select(None)
Jack Jansen4892ab71996-09-24 15:35:50 +0000415 self.setup_module()
416
417 def setup_module(self):
418 """Setup module-dependent widget data"""
Jack Jansena1560cf1996-09-26 16:26:05 +0000419 self.parent.SetWatch()
Jack Jansen4892ab71996-09-24 15:35:50 +0000420 if not self.cur_module:
Jack Jansen0eb88371996-10-09 09:38:46 +0000421 self.cont_varnames = []
422 self.cont_varvalues = []
Jack Jansen4892ab71996-09-24 15:35:50 +0000423 else:
424 self.cont_varnames, self.cont_varvalues = getmodulevars(self.cur_module)
Jack Jansen0eb88371996-10-09 09:38:46 +0000425 self.setvars()
Jack Jansen4892ab71996-09-24 15:35:50 +0000426
427 msg = ""
428 if not self.cur_module:
429 self.cur_source = None
430 msg = "No module selected"
431 else:
432 m = sys.modules[self.cur_module]
433 try:
434 self.cur_source = m.__file__
435 except AttributeError:
436 self.cur_source = None
437 msg = "Not a python module"
438 self.cur_lineno = 0
439 self.setsource(msg)
Jack Jansen0eb88371996-10-09 09:38:46 +0000440 self.source_select(self.cur_line)
Jack Jansen4892ab71996-09-24 15:35:50 +0000441 self.breaks_changed(self.cur_source)
442
Jack Jansena1560cf1996-09-26 16:26:05 +0000443 self.parent.SetCursor()
Jack Jansen4892ab71996-09-24 15:35:50 +0000444
445 # setsource(msg) should display cur_source+content, or msg if None
446
447 def update_views(self):
448 self.setup_module()
449
450 def click_module(self, module, *dummy):
451 if not module or module == self.cur_module: return
452 self.focus(module)
453
454 def focus(self, module):
455 self.cur_module = module
456 self.setup()
457
458 def click_var(self, var, *dummy):
459 if not var: return
460 m = sys.modules[self.cur_module]
461 dict = m.__dict__
462 self.parent.browse_var(dict[var])
463
464 def click_source(self, lineno, inborder):
465 if not inborder:
Jack Jansen0eb88371996-10-09 09:38:46 +0000466 self.source_select(lineno)
Jack Jansen4892ab71996-09-24 15:35:50 +0000467 self.cur_lineno = lineno
468 if lineno == None or not self.cur_source or not inborder:
469 return
470 if self.parent.dbg.get_break(self.cur_source, lineno):
471 self.parent.dbg.clear_break(self.cur_source, lineno)
472 else:
473 self.parent.dbg.set_break(self.cur_source, lineno)
474 self.parent.breaks_changed(self.cur_source)
475
476 def breaks_changed(self, filename):
477 if filename == self.cur_source:
478 list = self.parent.dbg.get_file_breaks(filename)
Jack Jansen0eb88371996-10-09 09:38:46 +0000479 self.source_setbreaks(list)
Jack Jansen4892ab71996-09-24 15:35:50 +0000480
481 def click_edit(self):
482 lino = self.cur_lineno
483 if not lino:
484 lino = 1
485 if self.cur_source:
486 self.parent.edit(self.cur_source, lino)
487
488
489def getmodulenames():
490 """Return a list of all current modules, sorted"""
491 list = sys.modules.keys()[:]
492 list.sort()
493 return list
494
495def getmodulevars(name):
496 """For given module return lists with names and values"""
497 m = sys.modules[name]
498 try:
499 dict = m.__dict__
500 except AttributeError:
501 dict = {}
502 return getvarsfromdict(dict)
503
504def getvarsfromdict(dict, show_complex=1, show_system=1):
505 allnames = dict.keys()[:]
506 allnames.sort()
507 names = []
508 for n in allnames:
509 if not show_complex:
510 if not type(dict[n]) in SIMPLE_TYPES:
511 continue
512 if not show_system:
513 if n[:2] == '__' and n[-2:] == '__':
514 continue
515 names.append(n)
516 values = []
517 for n in names:
518 v = pretty(dict[n])
519 values.append(v)
520 return names, values
521
522def pretty(var):
523 t = type(var)
524 if t == types.FunctionType: return '<function>'
525 if t == types.ClassType: return '<class>'
526 return `var`
527
528def getframelineno(frame):
529 """Given a frame return the line number"""
530 return getcodelineno(frame.f_code)
531
532def getfunclineno(func):
533 """Given a function return the line number"""
534 return getcodelineno(func.func_code)
535
536def getcodelineno(cobj):
537 """Given a code object return the line number"""
538 code = cobj.co_code
539 lineno = -1
540 if ord(code[0]) == 127: # SET_LINENO instruction
541 lineno = ord(code[1]) | (ord(code[2]) << 8)
542 return lineno
543
544def getframemodname(frame):
545 """Given a frame return the module name"""
546 globals = frame.f_globals
547 if globals.has_key('__name__'):
548 return globals['__name__']
549 return None