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