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