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 |
---|