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