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