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