[3] | 1 | from cStringIO import StringIO |
---|
| 2 | import traceback |
---|
| 3 | import threading |
---|
| 4 | import pdb |
---|
| 5 | import sys |
---|
| 6 | |
---|
| 7 | exec_lock = threading.Lock() |
---|
| 8 | |
---|
| 9 | class 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 |
---|
| 48 | class _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 |
---|