1from cStringIO import StringIO 2import traceback 3import threading 4import pdb 5import sys 6 7exec_lock = threading.Lock() 8 9class EvalContext(object): 10 11 """ 12 Class that represents a interactive interface. It has its own 13 namespace. Use eval_context.exec_expr(expr) to run commands; the 14 output of those commands is returned, as are print statements. 15 16 This is essentially what doctest does, and is taken directly from 17 doctest. 18 """ 19 20 def __init__(self, namespace, globs): 21 self.namespace = namespace 22 self.globs = globs 23 24 def exec_expr(self, s): 25 out = StringIO() 26 exec_lock.acquire() 27 save_stdout = sys.stdout 28 try: 29 debugger = _OutputRedirectingPdb(save_stdout) 30 debugger.reset() 31 pdb.set_trace = debugger.set_trace 32 sys.stdout = out 33 try: 34 code = compile(s, '<web>', "single", 0, 1) 35 exec code in self.namespace, self.globs 36 debugger.set_continue() 37 except KeyboardInterrupt: 38 raise 39 except: 40 traceback.print_exc(file=out) 41 debugger.set_continue() 42 finally: 43 sys.stdout = save_stdout 44 exec_lock.release() 45 return out.getvalue() 46 47# From doctest 48class _OutputRedirectingPdb(pdb.Pdb): 49 """ 50 A specialized version of the python debugger that redirects stdout 51 to a given stream when interacting with the user. Stdout is *not* 52 redirected when traced code is executed. 53 """ 54 def __init__(self, out): 55 self.__out = out 56 pdb.Pdb.__init__(self) 57 58 def trace_dispatch(self, *args): 59 # Redirect stdout to the given stream. 60 save_stdout = sys.stdout 61 sys.stdout = self.__out 62 # Call Pdb's trace dispatch method. 63 try: 64 return pdb.Pdb.trace_dispatch(self, *args) 65 finally: 66 sys.stdout = save_stdout 67