##// END OF EJS Templates
Make the OS-level stdout/stderr capture work in the frontends.
Gael Varoquaux -
Show More
@@ -1,158 +1,149 b''
1 1 """
2 2 Frontend class that uses IPython0 to prefilter the inputs.
3 3
4 4 Using the IPython0 mechanism gives us access to the magics.
5 5 """
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2008 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18 import sys
19 19
20 20 from linefrontendbase import LineFrontEndBase, common_prefix
21 21
22 22 from IPython.ipmaker import make_IPython
23 23 from IPython.ipapi import IPApi
24 from IPython.kernel.core.file_like import FileLike
25 from IPython.kernel.core.output_trap import OutputTrap
24 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
26 25
27 26 from IPython.genutils import Term
28 27 import pydoc
29 28
30 29 #-------------------------------------------------------------------------------
31 30 # Utility functions (temporary, should be moved out of here)
32 31 #-------------------------------------------------------------------------------
33 32 import os
34 33 def xterm_system(command):
35 34 """ Run a command in a separate console window.
36 35 """
37 36 os.system(("""xterm -title "%s" -e \'/bin/sh -c "%s ; """
38 37 """echo; echo press enter to close ; """
39 38 # """echo \\"\x1b]0;%s (finished -- press enter to close)\x07\\" ;
40 39 """read foo;"\' """) % (command, command) )
41 40
42 41 #-------------------------------------------------------------------------------
43 42 # Frontend class using ipython0 to do the prefiltering.
44 43 #-------------------------------------------------------------------------------
45 44 class PrefilterFrontEnd(LineFrontEndBase):
46 45
47 46 def __init__(self, *args, **kwargs):
48 47 LineFrontEndBase.__init__(self, *args, **kwargs)
49 48 # Instanciate an IPython0 interpreter to be able to use the
50 49 # prefiltering.
51 50 self.ipython0 = make_IPython()
52 51 # Set the pager:
53 52 self.ipython0.set_hook('show_in_pager',
54 53 lambda s, string: self.write("\n"+string))
55 54 self.ipython0.write = self.write
56 55 self._ip = _ip = IPApi(self.ipython0)
57 56 # XXX: Hack: mix the two namespaces
58 57 self.shell.user_ns = self.ipython0.user_ns
59 58 self.shell.user_global_ns = self.ipython0.user_global_ns
60 59 # Make sure the raw system call doesn't get called, as we don't
61 60 # have a stdin accessible.
62 61 self._ip.system = xterm_system
63 # Redefine a serie of magics to avoid os.system:
64 # FIXME: I am redefining way too much magics.
65 for alias_name, (_, alias_value) in \
66 _ip.IP.shell.alias_table.iteritems():
67 magic = lambda s : _ip.magic('sx %s %s' % (alias_value, s))
68 setattr(_ip.IP, 'magic_%s' % alias_name, magic)
69 # FIXME: I should create a real file-like object dedicated to this
70 # terminal
71 self.shell.output_trap = OutputTrap(
72 out=FileLike(write_callback=self.write),
73 err=FileLike(write_callback=self.write),
62 self.shell.output_trap = RedirectorOutputTrap(
63 out_callback=self.write,
64 err_callback=self.write,
74 65 )
75 66 # Capture and release the outputs, to make sure all the
76 67 # shadow variables are set
77 68 self.capture_output()
78 69 self.release_output()
79 70
80 71
81 72 def prefilter_input(self, input_string):
82 73 """ Using IPython0 to prefilter the commands.
83 74 """
84 75 input_string = LineFrontEndBase.prefilter_input(self, input_string)
85 76 filtered_lines = []
86 77 # The IPython0 prefilters sometime produce output. We need to
87 78 # capture it.
88 79 self.capture_output()
89 80 self.last_result = dict(number=self.prompt_number)
90 81 try:
91 82 for line in input_string.split('\n'):
92 83 filtered_lines.append(self.ipython0.prefilter(line, False))
93 84 except:
94 85 # XXX: probably not the right thing to do.
95 86 self.ipython0.showsyntaxerror()
96 87 self.after_execute()
97 88 finally:
98 89 self.release_output()
99 90
100 91 filtered_string = '\n'.join(filtered_lines)
101 92 return filtered_string
102 93
103 94
104 95 def show_traceback(self):
105 96 self.capture_output()
106 97 self.ipython0.showtraceback()
107 98 self.release_output()
108 99
109 100
110 101 def execute(self, python_string, raw_string=None):
111 102 self.capture_output()
112 103 LineFrontEndBase.execute(self, python_string,
113 104 raw_string=raw_string)
114 105 self.release_output()
115 106
116 107
117 108 def capture_output(self):
118 109 """ Capture all the output mechanisms we can think of.
119 110 """
120 111 self.__old_cout_write = Term.cout.write
121 112 self.__old_err_write = Term.cerr.write
122 113 Term.cout.write = self.write
123 114 Term.cerr.write = self.write
124 115 self.__old_stdout = sys.stdout
125 116 self.__old_stderr= sys.stderr
126 117 sys.stdout = Term.cout
127 118 sys.stderr = Term.cerr
128 119 self.__old_help_output = pydoc.help.output
129 120 pydoc.help.output = self.shell.output_trap.out
130 121
131 122
132 123 def release_output(self):
133 124 """ Release all the different captures we have made.
134 125 """
135 126 Term.cout.write = self.__old_cout_write
136 127 Term.cerr.write = self.__old_err_write
137 128 sys.stdout = self.__old_stdout
138 129 sys.stderr = self.__old_stderr
139 130 pydoc.help.output = self.__old_help_output
140 131
141 132
142 133 def complete(self, line):
143 134 word = line.split('\n')[-1].split(' ')[-1]
144 135 completions = self.ipython0.complete(word)
145 136 # FIXME: The proper sort should be done in the complete method.
146 137 key = lambda x: x.replace('_', '')
147 138 completions.sort(key=key)
148 139 if completions:
149 140 prefix = common_prefix(completions)
150 141 line = line[:-len(word)] + prefix
151 142 return line, completions
152 143
153 144
154 145 def do_exit(self):
155 146 """ Exit the shell, cleanup and save the history.
156 147 """
157 148 self.ipython0.atexit_operations()
158 149
@@ -1,79 +1,93 b''
1 1 # encoding: utf-8
2 2
3 3 """
4 4 Trap stdout/stderr, including at the OS level. Calls a callback with
5 5 the output each time Python tries to write to the stdout or stderr.
6 6 """
7 7
8 8 __docformat__ = "restructuredtext en"
9 9
10 10 #-------------------------------------------------------------------------------
11 11 # Copyright (C) 2008 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-------------------------------------------------------------------------------
16 16
17 17 #-------------------------------------------------------------------------------
18 18 # Imports
19 19 #-------------------------------------------------------------------------------
20 20
21 21 from fd_redirector import FDRedirector, STDOUT, STDERR
22 22
23 23 from IPython.kernel.core.file_like import FileLike
24 24 from IPython.kernel.core.output_trap import OutputTrap
25 25
26 26 class RedirectorOutputTrap(OutputTrap):
27 27 """ Object which can trap text sent to stdout and stderr.
28 28 """
29 29
30 30 #------------------------------------------------------------------------
31 31 # OutputTrap interface.
32 32 #------------------------------------------------------------------------
33 33 def __init__(self, out_callback, err_callback):
34 34 # Callback invoked on write to stdout and stderr
35 35 self.out_callback = out_callback
36 36 self.err_callback = err_callback
37 37
38 38 # File descriptor redirectors, to capture non-Python
39 39 # output.
40 40 self.out_redirector = FDRedirector(STDOUT)
41 41 self.err_redirector = FDRedirector(STDERR)
42 42
43 43 # Call the base class with file like objects that will trigger
44 44 # our callbacks
45 45 OutputTrap.__init__(self, out=FileLike(self.on_out_write),
46 46 err=FileLike(self.on_err_write), )
47 47
48 48
49 49 def set(self):
50 50 """ Set the hooks: set the redirectors and call the base class.
51 51 """
52 52 self.out_redirector.start()
53 53 #self.err_redirector.start()
54 54 OutputTrap.set(self)
55 55
56 56
57 57 def unset(self):
58 58 """ Remove the hooks: call the base class and stop the
59 59 redirectors.
60 60 """
61 61 OutputTrap.unset(self)
62 # Flush the redirectors before stopping them
63 self.on_out_write('')
62 64 self.err_redirector.stop()
65 self.on_err_write('')
63 66 self.out_redirector.stop()
64 67
65 68
66 69 #------------------------------------------------------------------------
67 70 # Callbacks for synchronous output
68 71 #------------------------------------------------------------------------
69 72 def on_out_write(self, string):
70 73 """ Callback called when there is some Python output on stdout.
71 74 """
75 try:
72 76 self.out_callback(self.out_redirector.getvalue() + string)
77 except:
78 # If tracebacks are happening and we can't see them, it is
79 # quasy impossible to debug
80 self.unset()
81 raise
73 82
74 83 def on_err_write(self, string):
75 84 """ Callback called when there is some Python output on stderr.
76 85 """
86 try:
77 87 self.err_callback(self.err_redirector.getvalue() + string)
78
88 except:
89 # If tracebacks are happening and we can't see them, it is
90 # quasy impossible to debug
91 self.unset()
92 raise
79 93
General Comments 0
You need to be logged in to leave comments. Login now