The Window Independent Tracer (which will probably move elsewhere once
it is truly window-independent:-)
diff --git a/Mac/Tools/twit/TwitCore.py b/Mac/Tools/twit/TwitCore.py
new file mode 100644
index 0000000..51f6485
--- /dev/null
+++ b/Mac/Tools/twit/TwitCore.py
@@ -0,0 +1,493 @@
+# Window-interface-independent part of twit
+import sys
+import types
+import bdb
+import types
+
+SIMPLE_TYPES=(
+ types.NoneType,
+ types.IntType,
+ types.LongType,
+ types.FloatType,
+ types.ComplexType,
+ types.StringType
+)
+
+def Initialize():
+ pass
+
+class DebuggerStuff(bdb.Bdb):
+
+ def __init__(self, parent):
+ bdb.Bdb.__init__(self)
+ self.parent = parent
+ self.exception_info = (None, None)
+ self.reason = 'Not running'
+ self.reset()
+
+ def reset(self):
+ bdb.Bdb.reset(self)
+ self.forget()
+
+ def forget(self):
+ self.lineno = None
+ self.stack = []
+ self.curindex = 0
+ self.curframe = None
+
+ def setup(self, f, t):
+ self.forget()
+ self.stack, self.curindex = self.get_stack(f, t)
+ self.curframe = self.stack[self.curindex][0]
+
+ def interaction(self, frame, traceback):
+ self.setup(frame, traceback)
+ self.parent.interact()
+ self.exception_info = (None, None)
+
+ def user_call(self, frame, argument_list):
+ self.reason = 'Calling function'
+ self.interaction(frame, None)
+
+ def user_line(self, frame):
+ self.reason = 'Stopped'
+ self.interaction(frame, None)
+
+ def user_return(self, frame, return_value):
+ self.reason = 'Returning from function'
+ self.interaction(frame, None)
+
+ def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
+ self.reason = 'Exception occurred'
+ self.exception_info = (exc_type, exc_value)
+ self.interaction(frame, exc_traceback)
+
+ def getexception(self):
+ tp, value = self.exception_info
+ if tp <> None and type(tp) <> type(''):
+ tp = tp.__name__
+ if value <> None and type(value) <> type(''):
+ value = `value`
+ return tp, value
+
+ def getstacktrace(self):
+ names, locations = [], []
+ for frame, lineno in self.stack:
+ name = frame.f_code.co_name
+ if not name:
+ name = "<lambda>"
+ elif name == '?':
+ name = "<not a function>"
+ else:
+ name = name + '()'
+ names.append(name)
+
+ if lineno == -1:
+ lineno = getframelineno(frame)
+
+ modname = getframemodname(frame)
+ if not modname: modname = "<unknown>"
+
+ locations.append("%s:%d" % (modname, lineno))
+ return names, locations
+
+ def getframe(self, number):
+ if number < 0 or number >= len(self.stack):
+ return None
+ return self.stack[number][0]
+
+ def getframevars(self, number, show_complex=1, show_system=1):
+ frame = self.getframe(number)
+ if not frame:
+ return [], []
+ return getvarsfromdict(frame.f_locals, show_complex, show_system)
+
+ def getframevar(self, number, var):
+ frame = self.getframe(number)
+ return frame.f_locals[var]
+
+ def getframefilepos(self, frameno):
+ if frameno == None or frameno < 0 or frameno >= len(self.stack):
+ return None, None, None
+ frame, line = self.stack[frameno]
+ if line == -1:
+ line = getframelineno(frame)
+ modname = getframemodname(frame)
+ filename = frame.f_code.co_filename
+ return filename, modname, line
+
+ def getprogramstate(self):
+ return self.reason
+
+class Application:
+ """Base code for the application"""
+
+ def mi_init(self, run_args, pm_args):
+ self.dbg = DebuggerStuff(self)
+ self.run_dialog = self.new_stack_browser(self)
+ self.run_dialog.open()
+ self.module_dialog = None
+ self.initial_cmd = None
+ if pm_args:
+ while pm_args.tb_next <> None:
+ pm_args = pm_args.tb_next
+ self.dbg.setup(pm_args.tb_frame, pm_args)
+ self.run_dialog.setsession_pm()
+ elif run_args:
+ self.run_dialog.setsession_run()
+ self.initial_cmd = run_args
+ else:
+ self.run_dialog.setsession_none()
+
+ def breaks_changed(self, filename):
+ self.run_dialog.breaks_changed(filename)
+ if self.module_dialog:
+ self.module_dialog.breaks_changed(filename)
+
+ def to_debugger(self):
+ apply(self.dbg.run, self.initial_cmd)
+
+ def interact(self):
+ # Interact with user. First, display correct info
+ self.run_dialog.update_views()
+ if self.module_dialog:
+ self.module_dialog.update_views()
+
+ # Next, go into mainloop
+ self.one_mainloop()
+
+ # Finally (before we start the debuggee again) show state
+ self.run_dialog.show_it_running()
+
+ def quit_bdb(self):
+ self.dbg.set_quit()
+
+ def run(self):
+ cmd = AskString('Statement to execute:')
+ self.initial_cmd = (cmd, None, None)
+ self.run_dialog.setsession_run()
+ self.exit_mainloop()
+
+ def cont(self):
+ self.dbg.set_continue()
+ self.exit_mainloop()
+
+ def step(self, frame):
+ self.dbg.set_next(frame)
+ self.exit_mainloop()
+
+ def step_in(self):
+ self.dbg.set_step()
+ self.exit_mainloop()
+
+ def step_out(self, frame):
+ self.dbg.set_return(frame)
+ self.exit_mainloop()
+
+ def quit(self):
+ self.do_quit()
+
+ def browse(self, module):
+ if not self.module_dialog:
+ self.module_dialog = self.new_module_browser(self)
+ self.module_dialog.open(module)
+ else:
+ self.module_dialog.focus(module)
+
+ def browse_var(self, var):
+ b = self.new_var_browser(self, var)
+
+class StackBrowser:
+ """Base code for stack browser"""
+ def mi_open(self):
+ """Setup initial data structures"""
+ self.create_items()
+ self.cur_stackitem = None
+ self.cur_source = None
+ self.cur_modname = None
+ self.cur_line = None
+ self.show_complex = 1
+ self.show_system = 0
+ self.setup()
+
+ # create_items(self) should create self.modules, self.vars and self.source
+
+ def setup(self):
+ SetWatch()
+ """Fill the various widgets with values"""
+ name, value = self.parent.dbg.getexception()
+ self.setexception(name, value)
+ self.setprogramstate(self.parent.dbg.getprogramstate())
+
+ names, locations = self.parent.dbg.getstacktrace()
+ self.stack.setcontent(names, locations)
+ self.cur_stackitem = len(names)-1
+ self.stack.select(self.cur_stackitem)
+ self.setup_frame()
+
+ def setup_frame(self):
+ """Setup frame-dependent widget data"""
+ SetWatch()
+ self.cont_varnames, self.cont_varvalues = \
+ self.parent.dbg.getframevars(self.cur_stackitem,
+ self.show_complex, self.show_system)
+ self.vars.setcontent(self.cont_varnames, self.cont_varvalues)
+ self.set_var_buttons()
+
+ msg = ""
+ if self.cur_stackitem == None:
+ self.cur_source = None
+ self.cur_modname = None
+ self.cur_line = None
+ msg = "No stackframe selected"
+ else:
+ self.cur_source, self.cur_modname, optnextline = \
+ self.parent.dbg.getframefilepos(self.cur_stackitem)
+ if optnextline >= 0:
+ self.cur_line = optnextline
+ if self.cur_source == '<string>':
+ self.cur_source = None
+ msg = "Executing from <string>"
+ print 'SOURCE', self.cur_source
+ print 'LINE', self.cur_line
+
+ self.setsource(msg)
+ self.source.setcurline(self.cur_line)
+ self.breaks_changed(self.cur_source)
+
+
+ SetCursor()
+
+ # setsource(msg) should display cur_source+content, or msg if None
+
+ def show_it_running(self):
+ self.setprogramstate("Running")
+
+ def update_views(self):
+ self.setup()
+
+ def click_stack(self, number, *dummy):
+ if number == self.cur_stackitem: return
+ self.cur_stackitem = number
+ self.stack.select(self.cur_stackitem)
+ self.setup_frame()
+
+ def click_var(self, var, *dummy):
+ v = self.parent.dbg.getframevar(self.cur_stackitem, var)
+ self.parent.browse_var(v)
+
+ def click_source(self, lineno, inborder):
+ if not inborder:
+ self.source.select(lineno)
+ self.cur_line = lineno
+ if lineno == None or not self.cur_source or not inborder:
+ return
+ if self.parent.dbg.get_break(self.cur_source, lineno):
+ self.parent.dbg.clear_break(self.cur_source, lineno)
+ else:
+ self.parent.dbg.set_break(self.cur_source, lineno)
+ self.parent.breaks_changed(self.cur_source)
+
+ def breaks_changed(self, filename):
+ if filename == self.cur_source:
+ list = self.parent.dbg.get_file_breaks(filename)
+ self.source.setbreaks(list)
+
+ def click_quit(self):
+ self.parent.quit()
+
+ def click_run(self):
+ self.parent.run()
+
+ def click_continue(self):
+ self.parent.cont()
+
+ def click_step(self):
+ if self.cur_stackitem <> None:
+ frame = self.parent.dbg.getframe(self.cur_stackitem)
+ self.parent.step(frame)
+ else:
+ self.parent.step_in()
+
+ def click_step_in(self):
+ self.parent.step_in()
+
+ def click_step_out(self):
+ if self.cur_stackitem <> None:
+ frame = self.parent.dbg.getframe(self.cur_stackitem)
+ self.parent.step_out(frame)
+ else:
+ self.parent.step_in()
+
+ def click_browse(self):
+ self.parent.browse(self.cur_modname)
+
+ def click_edit(self):
+ lino = self.cur_line
+ if not lino:
+ lino = 1
+ if self.cur_source:
+ self.parent.edit(self.cur_source, lino)
+
+class ModuleBrowser:
+ """Base code for a module-browser"""
+
+ def mi_open(self, module):
+ """Setup initial data structures"""
+ self.create_items()
+ self.cur_module = module
+ self.cur_source = None
+ self.cur_line = None
+ self.cont_modules = []
+ self.value_windows = []
+ self.setup()
+
+ # create_items(self) should create self.modules, self.vars and self.source
+
+ def setup(self):
+ """Fill the various widgets with values"""
+ SetWatch()
+ modnames = getmodulenames()
+ if not self.cur_module in modnames:
+ self.cur_module = None
+ if modnames <> self.cont_modules:
+ self.modules.setcontent(modnames)
+ self.cont_modules = modnames
+ if self.cur_module:
+ self.modules.select(self.cont_modules.index(self.cur_module))
+ else:
+ self.modules.select(None)
+ self.setup_module()
+
+ def setup_module(self):
+ """Setup module-dependent widget data"""
+ SetWatch()
+ if not self.cur_module:
+ self.vars.setcontent([], [])
+ else:
+ self.cont_varnames, self.cont_varvalues = getmodulevars(self.cur_module)
+ self.vars.setcontent(self.cont_varnames, self.cont_varvalues)
+
+ msg = ""
+ if not self.cur_module:
+ self.cur_source = None
+ msg = "No module selected"
+ else:
+ m = sys.modules[self.cur_module]
+ try:
+ self.cur_source = m.__file__
+ except AttributeError:
+ self.cur_source = None
+ msg = "Not a python module"
+ self.cur_lineno = 0
+ self.setsource(msg)
+ self.source.select(self.cur_line)
+ self.breaks_changed(self.cur_source)
+
+ SetCursor()
+
+ # setsource(msg) should display cur_source+content, or msg if None
+
+ def update_views(self):
+ self.setup_module()
+
+ def click_module(self, module, *dummy):
+ if not module or module == self.cur_module: return
+ self.focus(module)
+
+ def focus(self, module):
+ self.cur_module = module
+ self.setup()
+
+ def click_var(self, var, *dummy):
+ if not var: return
+ m = sys.modules[self.cur_module]
+ dict = m.__dict__
+ self.parent.browse_var(dict[var])
+
+ def click_source(self, lineno, inborder):
+ if not inborder:
+ self.source.select(lineno)
+ self.cur_lineno = lineno
+ if lineno == None or not self.cur_source or not inborder:
+ return
+ if self.parent.dbg.get_break(self.cur_source, lineno):
+ self.parent.dbg.clear_break(self.cur_source, lineno)
+ else:
+ self.parent.dbg.set_break(self.cur_source, lineno)
+ self.parent.breaks_changed(self.cur_source)
+
+ def breaks_changed(self, filename):
+ if filename == self.cur_source:
+ list = self.parent.dbg.get_file_breaks(filename)
+ self.source.setbreaks(list)
+
+ def click_edit(self):
+ lino = self.cur_lineno
+ if not lino:
+ lino = 1
+ if self.cur_source:
+ self.parent.edit(self.cur_source, lino)
+
+
+def getmodulenames():
+ """Return a list of all current modules, sorted"""
+ list = sys.modules.keys()[:]
+ list.sort()
+ return list
+
+def getmodulevars(name):
+ """For given module return lists with names and values"""
+ m = sys.modules[name]
+ try:
+ dict = m.__dict__
+ except AttributeError:
+ dict = {}
+ return getvarsfromdict(dict)
+
+def getvarsfromdict(dict, show_complex=1, show_system=1):
+ allnames = dict.keys()[:]
+ allnames.sort()
+ names = []
+ for n in allnames:
+ if not show_complex:
+ if not type(dict[n]) in SIMPLE_TYPES:
+ continue
+ if not show_system:
+ if n[:2] == '__' and n[-2:] == '__':
+ continue
+ names.append(n)
+ values = []
+ for n in names:
+ v = pretty(dict[n])
+ values.append(v)
+ return names, values
+
+def pretty(var):
+ t = type(var)
+ if t == types.FunctionType: return '<function>'
+ if t == types.ClassType: return '<class>'
+ return `var`
+
+def getframelineno(frame):
+ """Given a frame return the line number"""
+ return getcodelineno(frame.f_code)
+
+def getfunclineno(func):
+ """Given a function return the line number"""
+ return getcodelineno(func.func_code)
+
+def getcodelineno(cobj):
+ """Given a code object return the line number"""
+ code = cobj.co_code
+ lineno = -1
+ if ord(code[0]) == 127: # SET_LINENO instruction
+ lineno = ord(code[1]) | (ord(code[2]) << 8)
+ return lineno
+
+def getframemodname(frame):
+ """Given a frame return the module name"""
+ globals = frame.f_globals
+ if globals.has_key('__name__'):
+ return globals['__name__']
+ return None