##// END OF EJS Templates
BUG: Fix minor frontend bugs
Gael Varoquaux -
Show More
@@ -1,251 +1,257 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 This is a transitory class, used here to do the transition between
7 7 ipython0 and ipython1. This class is meant to be short-lived as more
8 8 functionnality is abstracted out of ipython0 in reusable functions and
9 9 is added on the interpreter. This class can be a used to guide this
10 10 refactoring.
11 11 """
12 12 __docformat__ = "restructuredtext en"
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Copyright (C) 2008 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-------------------------------------------------------------------------------
20 20
21 21 #-------------------------------------------------------------------------------
22 22 # Imports
23 23 #-------------------------------------------------------------------------------
24 24 import sys
25
26 from linefrontendbase import LineFrontEndBase, common_prefix
27 from frontendbase import FrontEndBase
25 import pydoc
26 import os
27 import __builtin__
28 28
29 29 from IPython.ipmaker import make_IPython
30 30 from IPython.ipapi import IPApi
31 31 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
32 32
33 33 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
34 34
35 35 from IPython.genutils import Term
36 import pydoc
37 import os
38 import sys
36
37 from linefrontendbase import LineFrontEndBase, common_prefix
39 38
40 39
41 40 def mk_system_call(system_call_function, command):
42 41 """ given a os.system replacement, and a leading string command,
43 42 returns a function that will execute the command with the given
44 43 argument string.
45 44 """
46 45 def my_system_call(args):
47 46 system_call_function("%s %s" % (command, args))
48 47
49 48 my_system_call.__doc__ = "Calls %s" % command
50 49 return my_system_call
51 50
52 51 #-------------------------------------------------------------------------------
53 52 # Frontend class using ipython0 to do the prefiltering.
54 53 #-------------------------------------------------------------------------------
55 54 class PrefilterFrontEnd(LineFrontEndBase):
56 55 """ Class that uses ipython0 to do prefilter the input, do the
57 56 completion and the magics.
58 57
59 58 The core trick is to use an ipython0 instance to prefilter the
60 59 input, and share the namespace between the interpreter instance used
61 60 to execute the statements and the ipython0 used for code
62 61 completion...
63 62 """
64 63
65 64 debug = False
66 65
67 66 def __init__(self, ipython0=None, *args, **kwargs):
68 67 """ Parameters:
69 68 -----------
70 69
71 70 ipython0: an optional ipython0 instance to use for command
72 71 prefiltering and completion.
73 72 """
74 73 LineFrontEndBase.__init__(self, *args, **kwargs)
75 74 self.shell.output_trap = RedirectorOutputTrap(
76 75 out_callback=self.write,
77 76 err_callback=self.write,
78 77 )
79 78 self.shell.traceback_trap = SyncTracebackTrap(
80 79 formatters=self.shell.traceback_trap.formatters,
81 80 )
82 81
83 82 # Start the ipython0 instance:
84 83 self.save_output_hooks()
85 84 if ipython0 is None:
86 85 # Instanciate an IPython0 interpreter to be able to use the
87 86 # prefiltering.
87 # Suppress all key input, to avoid waiting
88 def my_rawinput(x=None):
89 return '\n'
90 old_rawinput = __builtin__.raw_input
91 __builtin__.raw_input = my_rawinput
88 92 # XXX: argv=[] is a bit bold.
89 93 ipython0 = make_IPython(argv=[],
90 94 user_ns=self.shell.user_ns,
91 95 user_global_ns=self.shell.user_global_ns)
96 __builtin__.raw_input = old_rawinput
92 97 self.ipython0 = ipython0
93 98 # Set the pager:
94 99 self.ipython0.set_hook('show_in_pager',
95 100 lambda s, string: self.write("\n" + string))
96 101 self.ipython0.write = self.write
97 102 self._ip = _ip = IPApi(self.ipython0)
98 103 # Make sure the raw system call doesn't get called, as we don't
99 104 # have a stdin accessible.
100 105 self._ip.system = self.system_call
101 106 # XXX: Muck around with magics so that they work better
102 107 # in our environment
103 self.ipython0.magic_ls = mk_system_call(self.system_call,
104 'ls -CF')
108 if not sys.platform.startswith('win'):
109 self.ipython0.magic_ls = mk_system_call(self.system_call,
110 'ls -CF')
105 111 # And now clean up the mess created by ipython0
106 112 self.release_output()
107 113
108 114
109 115 if not 'banner' in kwargs and self.banner is None:
110 116 self.banner = self.ipython0.BANNER + """
111 117 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
112 118
113 119 self.start()
114 120
115 121 #--------------------------------------------------------------------------
116 122 # FrontEndBase interface
117 123 #--------------------------------------------------------------------------
118 124
119 125 def show_traceback(self):
120 126 """ Use ipython0 to capture the last traceback and display it.
121 127 """
122 128 # Don't do the capture; the except_hook has already done some
123 129 # modifications to the IO streams, if we store them, we'll be
124 130 # storing the wrong ones.
125 131 #self.capture_output()
126 132 self.ipython0.showtraceback(tb_offset=-1)
127 133 self.release_output()
128 134
129 135
130 136 def execute(self, python_string, raw_string=None):
131 137 if self.debug:
132 138 print 'Executing Python code:', repr(python_string)
133 139 self.capture_output()
134 140 LineFrontEndBase.execute(self, python_string,
135 141 raw_string=raw_string)
136 142 self.release_output()
137 143
138 144
139 145 def save_output_hooks(self):
140 146 """ Store all the output hooks we can think of, to be able to
141 147 restore them.
142 148
143 149 We need to do this early, as starting the ipython0 instance will
144 150 screw ouput hooks.
145 151 """
146 152 self.__old_cout_write = Term.cout.write
147 153 self.__old_cerr_write = Term.cerr.write
148 154 self.__old_stdout = sys.stdout
149 155 self.__old_stderr= sys.stderr
150 156 self.__old_help_output = pydoc.help.output
151 157 self.__old_display_hook = sys.displayhook
152 158
153 159
154 160 def capture_output(self):
155 161 """ Capture all the output mechanisms we can think of.
156 162 """
157 163 self.save_output_hooks()
158 164 Term.cout.write = self.write
159 165 Term.cerr.write = self.write
160 166 sys.stdout = Term.cout
161 167 sys.stderr = Term.cerr
162 168 pydoc.help.output = self.shell.output_trap.out
163 169
164 170
165 171 def release_output(self):
166 172 """ Release all the different captures we have made.
167 173 """
168 174 Term.cout.write = self.__old_cout_write
169 175 Term.cerr.write = self.__old_cerr_write
170 176 sys.stdout = self.__old_stdout
171 177 sys.stderr = self.__old_stderr
172 178 pydoc.help.output = self.__old_help_output
173 179 sys.displayhook = self.__old_display_hook
174 180
175 181
176 182 def complete(self, line):
177 183 # FIXME: This should be factored out in the linefrontendbase
178 184 # method.
179 185 word = line.split('\n')[-1].split(' ')[-1]
180 186 completions = self.ipython0.complete(word)
181 187 # FIXME: The proper sort should be done in the complete method.
182 188 key = lambda x: x.replace('_', '')
183 189 completions.sort(key=key)
184 190 if completions:
185 191 prefix = common_prefix(completions)
186 192 line = line[:-len(word)] + prefix
187 193 return line, completions
188 194
189 195
190 196 #--------------------------------------------------------------------------
191 197 # LineFrontEndBase interface
192 198 #--------------------------------------------------------------------------
193 199
194 200 def prefilter_input(self, input_string):
195 201 """ Using IPython0 to prefilter the commands to turn them
196 202 in executable statements that are valid Python strings.
197 203 """
198 204 input_string = LineFrontEndBase.prefilter_input(self, input_string)
199 205 filtered_lines = []
200 206 # The IPython0 prefilters sometime produce output. We need to
201 207 # capture it.
202 208 self.capture_output()
203 209 self.last_result = dict(number=self.prompt_number)
204 210
205 211 ## try:
206 212 ## for line in input_string.split('\n'):
207 213 ## filtered_lines.append(
208 214 ## self.ipython0.prefilter(line, False).rstrip())
209 215 ## except:
210 216 ## # XXX: probably not the right thing to do.
211 217 ## self.ipython0.showsyntaxerror()
212 218 ## self.after_execute()
213 219 ## finally:
214 220 ## self.release_output()
215 221
216 222
217 223 try:
218 224 try:
219 225 for line in input_string.split('\n'):
220 226 filtered_lines.append(
221 227 self.ipython0.prefilter(line, False).rstrip())
222 228 except:
223 229 # XXX: probably not the right thing to do.
224 230 self.ipython0.showsyntaxerror()
225 231 self.after_execute()
226 232 finally:
227 233 self.release_output()
228 234
229 235
230 236
231 237 # Clean up the trailing whitespace, to avoid indentation errors
232 238 filtered_string = '\n'.join(filtered_lines)
233 239 return filtered_string
234 240
235 241
236 242 #--------------------------------------------------------------------------
237 243 # PrefilterFrontEnd interface
238 244 #--------------------------------------------------------------------------
239 245
240 246 def system_call(self, command_string):
241 247 """ Allows for frontend to define their own system call, to be
242 248 able capture output and redirect input.
243 249 """
244 250 return os.system(command_string)
245 251
246 252
247 253 def do_exit(self):
248 254 """ Exit the shell, cleanup and save the history.
249 255 """
250 256 self.ipython0.atexit_operations()
251 257
General Comments 0
You need to be logged in to leave comments. Login now