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