# # support code for the trace object space # import autopath import sys class Stack(list): push = list.append def pop(self): return super(Stack, self).pop(-1) def top(self): try: return self[-1] except IndexError: return None class ResultPrinter(object): def __init__(self, indentor = ' ', repr_type_simple = True, show_bytecode = True, output_filename = None, tree_pos_indicator = "|-", show_hidden_applevel = False, recursive_operations = False, show_wrapped_consts_bytecode = True, **kwds ): if output_filename is None: self.out = sys.stdout else: self.out = open(output_filename, "w") # Configurable stuff self.indentor = indentor self.tree_pos_indicator = tree_pos_indicator self.show_bytecode = show_bytecode self.show_hidden_applevel = show_hidden_applevel self.recursive_operations = recursive_operations self.show_wrapped_consts_bytecode = show_wrapped_consts_bytecode if repr_type_simple: self.repr_value = simple_repr else: self.repr_value = repr_value # Keeps a stack of current state to handle # showing of applevel and recursive operations self.indent_state = Stack() # Some printing state self.last_line_was_new = True def reset(self): self.indent_state = Stack() def valid_state(self): state = self.indent_state.top() if state is not None and not state[0]: return False return True def print_line(self, line, new_line = True): if self.last_line_was_new: indent_count = len([c for c, t, f in self.indent_state if c]) if indent_count: indent = indent_count - 1 assert (indent >= 0) line = (self.indentor * indent) + self.tree_pos_indicator + line if new_line: self.last_line_was_new = True print >>self.out, line else: print >>self.out, line, self.last_line_was_new = False def print_frame(self, print_type, frame): if not self.valid_state(): return # Force new line if not the case if not self.last_line_was_new: print >>self.out, "" self.last_line_was_new = True code = getattr(frame, 'pycode', None) filename = getattr(code, 'co_filename', "") filename = filename.replace("\n", "\\n") lineno = getattr(code, 'co_firstlineno', "") s = " <<<< %s %s @ %s >>>>" % (print_type, filename, lineno) self.print_line(s) def print_bytecode(self, index, bytecode, space): if not self.valid_state(): return if self.show_bytecode: if self.show_wrapped_consts_bytecode: bytecode_str = repr(bytecode) else: bytecode_str = bytecode.repr_with_space(space) s = "%2d%s%s" % (index, (self.indentor * 2), bytecode_str) self.print_line(s) def print_op_enter(self, space, name, args): if not self.valid_state(): return s = " " * 4 s += "%s" % name s += "(" + ", ".join([self.repr_value(space, ii) for ii in args]) + ")" self.print_line(s, new_line=False) def print_op_leave(self, space, name, res): if not self.valid_state(): return if self.last_line_was_new: s = " " * 4 else: s = " " s += "-> %s" % self.repr_value(space, res) self.print_line(s) def print_op_exc(self, name, exc, space): if not self.valid_state(): return if self.last_line_was_new: s = " " * 4 else: s = " " s += "-> (%s)" % self.repr_value(space, exc) self.print_line(s) def print_event(self, space, event_result, event): from pypy.objspace import trace if isinstance(event, trace.EnterFrame): frame = event.frame if self.show_hidden_applevel or not frame.pycode.hidden_applevel: show = True else: show = False self.indent_state.push((show, trace.EnterFrame, frame)) self.print_frame("enter", frame) elif isinstance(event, trace.LeaveFrame): lastframe = self.indent_state.top()[2] assert lastframe is not None self.print_frame("leave", lastframe) self.indent_state.pop() elif isinstance(event, trace.ExecBytecode): frame = event.frame assert (frame == self.get_last_frame()) # Get bytecode from frame disresult = event_result.getdisresult(frame) bytecode = disresult.getbytecode(event.index) self.print_bytecode(event.index, bytecode, space) elif isinstance(event, trace.CallBegin): lastframe = self.get_last_frame() info = event.callinfo show = True # Check if we are in applevel? if not self.show_hidden_applevel: if lastframe is None or lastframe.pycode.hidden_applevel: show = False # Check if recursive operations? prev_indent_state = self.indent_state.top() if not self.recursive_operations and prev_indent_state is not None: if prev_indent_state[1] == trace.CallBegin: show = False self.indent_state.push((show, trace.CallBegin, None)) self.print_op_enter(space, info.name, info.args) elif isinstance(event, trace.CallFinished): info = event.callinfo self.print_op_leave(space, info.name, event.res) self.indent_state.pop() elif isinstance(event, trace.CallException): info = event.callinfo self.print_op_exc(info.name, event.ex, space) self.indent_state.pop() def get_last_frame(self): for c, t, f in self.indent_state[::-1]: if f is not None: return f class ResultPrinterVerbose(ResultPrinter): """ Puts result on same line """ def print_op_enter(self, space, name, args): if not self.valid_state(): return s = " " * 4 s += "%s" % name s += "(" + ", ".join([self.repr_value(space, ii) for ii in args]) + ")" self.print_line(s) def print_op_exc(self, name, exc, space): if not self.valid_state(): return if self.last_line_was_new: s = " " * 4 else: s = " " s += "x-> %s" % self.repr_value(space, exc) self.print_line(s) def simple_repr(space, obj): res = repr(obj) if len(res) > 80: res = res[:76] + "..." return res def repr_value_complex(space, obj): """ representations - very slow """ from pypy.interpreter.argument import Arguments from pypy.interpreter.error import OperationError # Special case true and false (from space.is_true()) - we use a # different representation from a wrapped object reprs method. if obj is True: return "TRUE" elif obj is False: return "FALSE" if hasattr(obj, "__iter__"): return ", ".join([repr_value(space, ii) for ii in obj]) # Special case - arguments if isinstance(obj, Arguments): args = [repr_value(space, ii) for ii in obj.arguments_w] if obj.kwds_w: args += ["%s = %s" % (k, repr_value(space, v)) for k, v in obj.kwds_w.items()] if not obj.w_stararg is None: args.append("*" + repr_value_complex(space, obj.w_stararg)) if not obj.w_starstararg is None: args.append("**" + repr_value_complex(space, obj.w_starstararg)) return "Args(%s)" % (", ".join(args)) # Special case - operation error if isinstance(obj, OperationError): return "OpError(%s, %s)" % (repr_value(space, obj.w_type), repr_value(space, obj.get_w_value(space))) # Try object repr try: return space.str_w(space.repr(obj)) except: # Give up return repr(obj) def repr_value(space, obj): return repr_value_complex(space, obj)[:120] # __________________________________________________________________________ def perform_trace(tspace, app_func, *args_w): from pypy.interpreter.gateway import app2interp from pypy.interpreter.argument import Arguments # Create our function func_gw = app2interp(app_func) w_func = func_gw.get_function(tspace) # Run the func in the trace space and return results tspace.settrace() w_result = tspace.call_function(w_func, *args_w) trace_result = tspace.getresult() tspace.settrace() return w_result, trace_result if __name__ == '__main__': from pypy.objspace import std, trace # Wrap up std space, with a trace space tspace = trace.create_trace_space(std.Space()) def func(x): count = 0 for ii in range(x): count += ii return count # Note includes lazy loading of builtins res = perform_trace(tspace, func, tspace.wrap(5)) print "Result:", res