##// END OF EJS Templates
Synchronous stdout/stderr output.
Gael Varoquaux -
Show More
@@ -0,0 +1,67 b''
1 # encoding: utf-8
2
3 """ Redirects stdout/stderr to given write methods."""
4
5 __docformat__ = "restructuredtext en"
6
7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
13
14 #-------------------------------------------------------------------------------
15 # Imports
16 #-------------------------------------------------------------------------------
17
18 import sys
19 from IPython.kernel.core.output_trap import OutputTrap
20
21 class FileLike(object):
22 """ FileLike object that redirects all write to a callback.
23
24 Only the write-related methods are implemented, as well as those
25 required to read a StringIO.
26 """
27 closed = False
28
29 def __init__(self, write):
30 self.write = write
31
32 def flush(self):
33 pass
34
35 def close(self):
36 pass
37
38 def writelines(self, lines):
39 for line in lines:
40 self.write(line)
41
42 def isatty(self):
43 return False
44
45 def getvalue(self):
46 return ''
47
48
49 class SyncOutputTrap(OutputTrap):
50 """ Object which redirect text sent to stdout and stderr to write
51 callbacks.
52 """
53
54 def __init__(self, write_out, write_err):
55 # Store callbacks
56 self.out = FileLike(write_out)
57 self.err = FileLike(write_err)
58
59 # Boolean to check if the stdout/stderr hook is set.
60 self.out_set = False
61 self.err_set = False
62
63 def clear(self):
64 """ Clear out the buffers.
65 """
66 pass
67
@@ -1,418 +1,420 b''
1 1 # encoding: utf-8
2 2 """
3 3 A Wx widget to act as a console and input commands.
4 4
5 5 This widget deals with prompts and provides an edit buffer
6 6 restricted to after the last prompt.
7 7 """
8 8
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-------------------------------------------------------------------------------
12 12 # Copyright (C) 2008 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is
15 15 # in the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21
22 22 import wx
23 23 import wx.stc as stc
24 24
25 25 from wx.py import editwindow
26 26
27 27 import re
28 28
29 29 # FIXME: Need to provide an API for non user-generated display on the
30 30 # screen: this should not be editable by the user.
31 31
32 32 if wx.Platform == '__WXMSW__':
33 33 _DEFAULT_SIZE = 80
34 34 else:
35 35 _DEFAULT_SIZE = 10
36 36
37 37 _DEFAULT_STYLE = {
38 38 'stdout' : 'fore:#0000FF',
39 39 'stderr' : 'fore:#007f00',
40 40 'trace' : 'fore:#FF0000',
41 41
42 42 'default' : 'size:%d' % _DEFAULT_SIZE,
43 43 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
44 44 'bracebad' : 'fore:#000000,back:#FF0000,bold',
45 45
46 46 # properties for the various Python lexer styles
47 47 'comment' : 'fore:#007F00',
48 48 'number' : 'fore:#007F7F',
49 49 'string' : 'fore:#7F007F,italic',
50 50 'char' : 'fore:#7F007F,italic',
51 51 'keyword' : 'fore:#00007F,bold',
52 52 'triple' : 'fore:#7F0000',
53 53 'tripledouble' : 'fore:#7F0000',
54 54 'class' : 'fore:#0000FF,bold,underline',
55 55 'def' : 'fore:#007F7F,bold',
56 56 'operator' : 'bold'
57 57 }
58 58
59 59 # new style numbers
60 60 _STDOUT_STYLE = 15
61 61 _STDERR_STYLE = 16
62 62 _TRACE_STYLE = 17
63 63
64 64
65 65 # system colors
66 66 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
67 67
68 68 #-------------------------------------------------------------------------------
69 69 # The console widget class
70 70 #-------------------------------------------------------------------------------
71 71 class ConsoleWidget(editwindow.EditWindow):
72 72 """ Specialized styled text control view for console-like workflow.
73 73
74 74 This widget is mainly interested in dealing with the prompt and
75 75 keeping the cursor inside the editing line.
76 76 """
77 77
78 78 title = 'Console'
79 79
80 80 style = _DEFAULT_STYLE.copy()
81 81
82 82 # Translation table from ANSI escape sequences to color. Override
83 83 # this to specify your colors.
84 84 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
85 85 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
86 86 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
87 87 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
88 88 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
89 89 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
90 90 '1;34': [12, 'LIGHT BLUE'], '1;35':
91 91 [13, 'MEDIUM VIOLET RED'],
92 92 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
93 93
94 94 # The color of the carret (call _apply_style() after setting)
95 95 carret_color = 'BLACK'
96 96
97 97
98 98 #--------------------------------------------------------------------------
99 99 # Public API
100 100 #--------------------------------------------------------------------------
101 101
102 102 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
103 103 size=wx.DefaultSize, style=0, ):
104 104 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
105 105 self.configure_scintilla()
106 106
107 107 # FIXME: we need to retrieve this from the interpreter.
108 108 self.prompt = \
109 109 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
110 110 self.new_prompt(self.prompt % 1)
111 111
112 112 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
113 113 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
114 114
115 115
116 116 def configure_scintilla(self):
117 117 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
118 118 # the widget
119 119 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
120 120 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
121 121 # Also allow Ctrl Shift "=" for poor non US keyboard users.
122 122 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
123 123 stc.STC_CMD_ZOOMIN)
124 124
125 125 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
126 126 # stc.STC_CMD_PAGEUP)
127 127
128 128 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
129 129 # stc.STC_CMD_PAGEDOWN)
130 130
131 131 # Keys: we need to clear some of the keys the that don't play
132 132 # well with a console.
133 133 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
134 134 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
135 135 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
136 136
137 137
138 138 self.SetEOLMode(stc.STC_EOL_CRLF)
139 139 self.SetWrapMode(stc.STC_WRAP_CHAR)
140 140 self.SetWrapMode(stc.STC_WRAP_WORD)
141 141 self.SetBufferedDraw(True)
142 142 self.SetUseAntiAliasing(True)
143 143 self.SetLayoutCache(stc.STC_CACHE_PAGE)
144 144 self.SetUndoCollection(False)
145 145 self.SetUseTabs(True)
146 146 self.SetIndent(4)
147 147 self.SetTabWidth(4)
148 148
149 149 self.EnsureCaretVisible()
150 150 # we don't want scintilla's autocompletion to choose
151 151 # automaticaly out of a single choice list, as we pop it up
152 152 # automaticaly
153 153 self.AutoCompSetChooseSingle(False)
154 154 self.AutoCompSetMaxHeight(10)
155 155
156 156 self.SetMargins(3, 3) #text is moved away from border with 3px
157 157 # Suppressing Scintilla margins
158 158 self.SetMarginWidth(0, 0)
159 159 self.SetMarginWidth(1, 0)
160 160 self.SetMarginWidth(2, 0)
161 161
162 162 self._apply_style()
163 163
164 164 # Xterm escape sequences
165 165 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
166 166 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
167 167
168 168 #self.SetEdgeMode(stc.STC_EDGE_LINE)
169 169 #self.SetEdgeColumn(80)
170 170
171 171 # styles
172 172 p = self.style
173 173 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
174 174 self.StyleClearAll()
175 175 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
176 176 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
177 177 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
178 178
179 179 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
180 180 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
181 181 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
182 182 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
183 183 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
184 184 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
185 185 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
186 186 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
187 187 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
188 188 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
189 189 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
190 190 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
191 191 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
192 192 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
193 193
194 194
195 195 def write(self, text):
196 196 """ Write given text to buffer, while translating the ansi escape
197 197 sequences.
198 198 """
199 199 title = self.title_pat.split(text)
200 200 if len(title)>0:
201 201 self.title = title[-1]
202 202
203 203 text = self.title_pat.sub('', text)
204 204 segments = self.color_pat.split(text)
205 205 segment = segments.pop(0)
206 206 self.StartStyling(self.GetLength(), 0xFF)
207 207 self.AppendText(segment)
208 208
209 209 if segments:
210 210 ansi_tags = self.color_pat.findall(text)
211 211
212 212 for tag in ansi_tags:
213 213 i = segments.index(tag)
214 214 self.StartStyling(self.GetLength(), 0xFF)
215 215 self.AppendText(segments[i+1])
216 216
217 217 if tag != '0':
218 218 self.SetStyling(len(segments[i+1]),
219 219 self.ANSI_STYLES[tag][0])
220 220
221 221 segments.pop(i)
222 222
223 223 self.GotoPos(self.GetLength())
224 wx.Yield()
224 225
225 226
226 227 def new_prompt(self, prompt):
227 228 """ Prints a prompt at start of line, and move the start of the
228 229 current block there.
229 230
230 231 The prompt can be give with ascii escape sequences.
231 232 """
232 233 self.write(prompt)
233 234 # now we update our cursor giving end of prompt
234 235 self.current_prompt_pos = self.GetLength()
235 236 self.current_prompt_line = self.GetCurrentLine()
236 237 wx.Yield()
237 238 self.EnsureCaretVisible()
238 239
239 240
240 241 def replace_current_edit_buffer(self, text):
241 242 """ Replace currently entered command line with given text.
242 243 """
243 244 self.SetSelection(self.current_prompt_pos, self.GetLength())
244 245 self.ReplaceSelection(text)
245 246 self.GotoPos(self.GetLength())
246 247
247 248
248 249 def get_current_edit_buffer(self):
249 250 """ Returns the text in current edit buffer.
250 251 """
251 252 return self.GetTextRange(self.current_prompt_pos,
252 253 self.GetLength())
253 254
254 255
255 256 #--------------------------------------------------------------------------
256 257 # Private API
257 258 #--------------------------------------------------------------------------
258 259
259 260 def _apply_style(self):
260 261 """ Applies the colors for the different text elements and the
261 262 carret.
262 263 """
263 264 self.SetCaretForeground(self.carret_color)
264 265
265 266 #self.StyleClearAll()
266 267 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
267 268 "fore:#FF0000,back:#0000FF,bold")
268 269 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
269 270 "fore:#000000,back:#FF0000,bold")
270 271
271 272 for style in self.ANSI_STYLES.values():
272 273 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
273 274
274 275
275 276 def write_completion(self, possibilities):
276 277 # FIXME: This is non Wx specific and needs to be moved into
277 278 # the base class.
278 279 current_buffer = self.get_current_edit_buffer()
279 280
280 281 self.write('\n')
281 282 max_len = len(max(possibilities, key=len)) + 1
282 283
283 284 #now we check how much symbol we can put on a line...
284 285 chars_per_line = self.GetSize()[0]/self.GetCharWidth()
285 286 symbols_per_line = max(1, chars_per_line/max_len)
286 287
287 288 pos = 1
288 289 buf = []
289 290 for symbol in possibilities:
290 291 if pos < symbols_per_line:
291 292 buf.append(symbol.ljust(max_len))
292 293 pos += 1
293 294 else:
294 295 buf.append(symbol.rstrip() +'\n')
295 296 pos = 1
296 297 self.write(''.join(buf))
297 298 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
298 299 self.replace_current_edit_buffer(current_buffer)
299 300
300 301
301 302 def pop_completion(self, possibilities, offset=0):
302 303 """ Pops up an autocompletion menu. Offset is the offset
303 304 in characters of the position at which the menu should
304 305 appear, relativ to the cursor.
305 306 """
306 307 self.AutoCompSetIgnoreCase(False)
307 308 self.AutoCompSetAutoHide(False)
308 309 self.AutoCompSetMaxHeight(len(possibilities))
309 310 self.AutoCompShow(offset, " ".join(possibilities))
310 311
311 312
312 313 def scroll_to_bottom(self):
313 314 maxrange = self.GetScrollRange(wx.VERTICAL)
314 315 self.ScrollLines(maxrange)
315 316
316 317
317 318 def _on_enter(self):
318 319 """ Called when the return key is hit.
319 320 """
320 321 pass
321 322
322 323
323 324 def _on_key_down(self, event, skip=True):
324 325 """ Key press callback used for correcting behavior for
325 326 console-like interfaces: the cursor is constraint to be after
326 327 the last prompt.
327 328
328 329 Return True if event as been catched.
329 330 """
330 331 catched = True
331 332 # Intercept some specific keys.
332 333 if event.KeyCode == ord('L') and event.ControlDown() :
333 334 self.scroll_to_bottom()
334 335 elif event.KeyCode == ord('K') and event.ControlDown() :
335 336 self.replace_current_edit_buffer('')
336 337 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
337 338 self.ScrollPages(-1)
338 339 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
339 340 self.ScrollPages(1)
340 341 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
341 342 self.ScrollLines(-1)
342 343 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
343 344 self.ScrollLinees(1)
344 345 else:
345 346 catched = False
346 347
347 348 if self.AutoCompActive():
348 349 event.Skip()
349 350 else:
350 351 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
351 352 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
352 353 catched = True
354 self.CallTipCancel()
353 355 self.write('\n')
354 356 self._on_enter()
355 357
356 358 elif event.KeyCode == wx.WXK_HOME:
357 359 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
358 360 self.GotoPos(self.current_prompt_pos)
359 361 catched = True
360 362
361 363 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
362 364 # FIXME: This behavior is not ideal: if the selection
363 365 # is already started, it will jump.
364 366 self.SetSelectionStart(self.current_prompt_pos)
365 367 self.SetSelectionEnd(self.GetCurrentPos())
366 368 catched = True
367 369
368 370 elif event.KeyCode == wx.WXK_UP:
369 371 if self.GetCurrentLine() > self.current_prompt_line:
370 372 if self.GetCurrentLine() == self.current_prompt_line + 1 \
371 373 and self.GetColumn(self.GetCurrentPos()) < \
372 374 self.GetColumn(self.current_prompt_pos):
373 375 self.GotoPos(self.current_prompt_pos)
374 376 else:
375 377 event.Skip()
376 378 catched = True
377 379
378 380 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
379 381 if self.GetCurrentPos() > self.current_prompt_pos:
380 382 event.Skip()
381 383 catched = True
382 384
383 385 if skip and not catched:
384 386 event.Skip()
385 387
386 388 return catched
387 389
388 390
389 391 def _on_key_up(self, event, skip=True):
390 392 """ If cursor is outside the editing region, put it back.
391 393 """
392 394 event.Skip()
393 395 if self.GetCurrentPos() < self.current_prompt_pos:
394 396 self.GotoPos(self.current_prompt_pos)
395 397
396 398
397 399
398 400
399 401 if __name__ == '__main__':
400 402 # Some simple code to test the console widget.
401 403 class MainWindow(wx.Frame):
402 404 def __init__(self, parent, id, title):
403 405 wx.Frame.__init__(self, parent, id, title, size=(300,250))
404 406 self._sizer = wx.BoxSizer(wx.VERTICAL)
405 407 self.console_widget = ConsoleWidget(self)
406 408 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
407 409 self.SetSizer(self._sizer)
408 410 self.SetAutoLayout(1)
409 411 self.Show(True)
410 412
411 413 app = wx.PySimpleApp()
412 414 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
413 415 w.SetSize((780, 460))
414 416 w.Show()
415 417
416 418 app.MainLoop()
417 419
418 420
@@ -1,218 +1,218 b''
1 1 # encoding: utf-8 -*- test-case-name:
2 2 # FIXME: Need to add tests.
3 3 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
4 4
5 5 """Classes to provide a Wx frontend to the
6 6 IPython.kernel.core.interpreter.
7 7
8 8 """
9 9
10 10 __docformat__ = "restructuredtext en"
11 11
12 12 #-------------------------------------------------------------------------------
13 13 # Copyright (C) 2008 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-------------------------------------------------------------------------------
18 18
19 19 #-------------------------------------------------------------------------------
20 20 # Imports
21 21 #-------------------------------------------------------------------------------
22 22
23 23
24 24 import wx
25 25 import re
26 26 from wx import stc
27 27 from console_widget import ConsoleWidget
28 28 import __builtin__
29 29
30 30 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
31 31
32 32 #_COMMAND_BG = '#FAFAF1' # Nice green
33 33 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
34 34
35 35 _RUNNING_BUFFER_MARKER = 31
36 36
37 37
38 38 #-------------------------------------------------------------------------------
39 39 # Classes to implement the Wx frontend
40 40 #-------------------------------------------------------------------------------
41 41 class IPythonWxController(PrefilterFrontEnd, ConsoleWidget):
42 42
43 43 output_prompt = \
44 '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
44 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
45 45
46 46 #--------------------------------------------------------------------------
47 47 # Public API
48 48 #--------------------------------------------------------------------------
49 49
50 50 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
51 51 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
52 52 *args, **kwds):
53 53 """ Create Shell instance.
54 54 """
55 55 ConsoleWidget.__init__(self, parent, id, pos, size, style)
56 56 PrefilterFrontEnd.__init__(self)
57 57
58 58 # Capture Character keys
59 59 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
60 60
61 61 # Marker for running buffer.
62 62 self.MarkerDefine(_RUNNING_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
63 63 background=_RUNNING_BUFFER_BG)
64 64
65 65
66 66
67 67 def do_completion(self):
68 68 """ Do code completion.
69 69 """
70 70 line = self.get_current_edit_buffer()
71 71 new_line, completions = self.complete(line)
72 72 if len(completions)>1:
73 73 self.write_completion(completions)
74 74 self.replace_current_edit_buffer(new_line)
75 75
76 76
77 77 def do_calltip(self):
78 78 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
79 79 symbol = self.get_current_edit_buffer()
80 80 symbol_string = separators.split(symbol)[-1]
81 81 base_symbol_string = symbol_string.split('.')[0]
82 82 if base_symbol_string in self.shell.user_ns:
83 83 symbol = self.shell.user_ns[base_symbol_string]
84 84 elif base_symbol_string in self.shell.user_global_ns:
85 85 symbol = self.shell.user_global_ns[base_symbol_string]
86 86 elif base_symbol_string in __builtin__.__dict__:
87 87 symbol = __builtin__.__dict__[base_symbol_string]
88 88 else:
89 89 return False
90 90 for name in symbol_string.split('.')[1:] + ['__doc__']:
91 91 symbol = getattr(symbol, name)
92 92 try:
93 93 self.AutoCompCancel()
94 94 wx.Yield()
95 95 self.CallTipShow(self.GetCurrentPos(), symbol)
96 96 except:
97 97 # The retrieve symbol couldn't be converted to a string
98 98 pass
99 99
100 100
101 101 def popup_completion(self, create=False):
102 102 """ Updates the popup completion menu if it exists. If create is
103 103 true, open the menu.
104 104 """
105 105 line = self.get_current_edit_buffer()
106 106 if (self.AutoCompActive() and not line[-1] == '.') \
107 107 or create==True:
108 108 suggestion, completions = self.complete(line)
109 109 offset=0
110 110 if completions:
111 111 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
112 112 residual = complete_sep.split(line)[-1]
113 113 offset = len(residual)
114 114 self.pop_completion(completions, offset=offset)
115 115
116 116
117 117 def execute(self, python_string, raw_string=None):
118 118 self.CallTipCancel()
119 119 self._cursor = wx.BusyCursor()
120 120 if raw_string is None:
121 121 raw_string = python_string
122 122 end_line = self.current_prompt_line \
123 123 + max(1, len(raw_string.split('\n'))-1)
124 124 for i in range(self.current_prompt_line, end_line):
125 125 self.MarkerAdd(i, 31)
126 126 # Update the display:
127 127 wx.Yield()
128 # Remove the trailing "\n" for cleaner display
129 self.SetSelection(self.GetLength()-1, self.GetLength())
130 self.ReplaceSelection('')
128 ## Remove the trailing "\n" for cleaner display
129 #self.SetSelection(self.GetLength()-1, self.GetLength())
130 #self.ReplaceSelection('')
131 131 self.GotoPos(self.GetLength())
132 132 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
133 133
134 134
135 135 def after_execute(self):
136 136 PrefilterFrontEnd.after_execute(self)
137 137 if hasattr(self, '_cursor'):
138 138 del self._cursor
139 139
140 140 #--------------------------------------------------------------------------
141 141 # Private API
142 142 #--------------------------------------------------------------------------
143 143
144 144
145 145 def _on_key_down(self, event, skip=True):
146 146 """ Capture the character events, let the parent
147 147 widget handle them, and put our logic afterward.
148 148 """
149 149 current_line_number = self.GetCurrentLine()
150 150 if event.KeyCode == ord('('):
151 151 event.Skip()
152 152 self.do_calltip()
153 153 elif self.AutoCompActive():
154 154 event.Skip()
155 155 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
156 156 wx.CallAfter(self.popup_completion, create=True)
157 157 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
158 158 wx.WXK_RIGHT):
159 159 wx.CallAfter(self.popup_completion)
160 160 else:
161 161 # Up history
162 162 if event.KeyCode == wx.WXK_UP and (
163 163 ( current_line_number == self.current_prompt_line and
164 164 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
165 165 or event.ControlDown() ):
166 166 new_buffer = self.get_history_previous(
167 167 self.get_current_edit_buffer())
168 168 if new_buffer is not None:
169 169 self.replace_current_edit_buffer(new_buffer)
170 170 if self.GetCurrentLine() > self.current_prompt_line:
171 171 # Go to first line, for seemless history up.
172 172 self.GotoPos(self.current_prompt_pos)
173 173 # Down history
174 174 elif event.KeyCode == wx.WXK_DOWN and (
175 175 ( current_line_number == self.LineCount -1 and
176 176 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
177 177 or event.ControlDown() ):
178 178 new_buffer = self.get_history_next()
179 179 if new_buffer is not None:
180 180 self.replace_current_edit_buffer(new_buffer)
181 181 elif event.KeyCode == ord('\t'):
182 182 last_line = self.get_current_edit_buffer().split('\n')[-1]
183 183 if not re.match(r'^\s*$', last_line):
184 184 self.do_completion()
185 185 else:
186 186 event.Skip()
187 187 else:
188 188 ConsoleWidget._on_key_down(self, event, skip=skip)
189 189
190 190
191 191 def _on_key_up(self, event, skip=True):
192 192 if event.KeyCode == 59:
193 193 # Intercepting '.'
194 194 event.Skip()
195 195 self.popup_completion(create=True)
196 196 else:
197 197 ConsoleWidget._on_key_up(self, event, skip=skip)
198 198
199 199
200 200 if __name__ == '__main__':
201 201 class MainWindow(wx.Frame):
202 202 def __init__(self, parent, id, title):
203 203 wx.Frame.__init__(self, parent, id, title, size=(300,250))
204 204 self._sizer = wx.BoxSizer(wx.VERTICAL)
205 205 self.shell = IPythonWxController(self)
206 206 self._sizer.Add(self.shell, 1, wx.EXPAND)
207 207 self.SetSizer(self._sizer)
208 208 self.SetAutoLayout(1)
209 209 self.Show(True)
210 210
211 211 app = wx.PySimpleApp()
212 212 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
213 213 frame.shell.SetFocus()
214 214 frame.SetSize((680, 460))
215 215 self = frame.shell
216 216
217 217 app.MainLoop()
218 218
@@ -1,749 +1,747 b''
1 1 # encoding: utf-8
2 2
3 3 """Central interpreter object for an IPython engine.
4 4
5 5 The interpreter is the object whose job is to process lines of user input and
6 6 actually execute them in the user's namespace.
7 7 """
8 8
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-------------------------------------------------------------------------------
12 12 # Copyright (C) 2008 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21
22 22 # Standard library imports.
23 from compiler.ast import Discard
24 23 from types import FunctionType
25 24
26 25 import __builtin__
27 26 import codeop
28 27 import compiler
29 import pprint
30 28 import sys
31 29 import traceback
32 30
33 31 # Local imports.
34 32 from IPython.kernel.core import ultraTB
35 33 from IPython.kernel.core.display_trap import DisplayTrap
36 34 from IPython.kernel.core.macro import Macro
37 35 from IPython.kernel.core.prompts import CachedOutput
38 36 from IPython.kernel.core.traceback_trap import TracebackTrap
39 37 from IPython.kernel.core.util import Bunch, system_shell
40 38 from IPython.external.Itpl import ItplNS
41 39
42 40 # Global constants
43 41 COMPILER_ERROR = 'error'
44 42 INCOMPLETE_INPUT = 'incomplete'
45 43 COMPLETE_INPUT = 'complete'
46 44
47 45 ##############################################################################
48 46 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
49 47 # not
50 48
51 49 rc = Bunch()
52 50 rc.cache_size = 100
53 51 rc.pprint = True
54 52 rc.separate_in = '\n'
55 53 rc.separate_out = '\n'
56 54 rc.separate_out2 = ''
57 55 rc.prompt_in1 = r'In [\#]: '
58 56 rc.prompt_in2 = r' .\\D.: '
59 57 rc.prompt_out = ''
60 58 rc.prompts_pad_left = False
61 59
62 60 ##############################################################################
63 61
64 62 # Top-level utilities
65 63 def default_display_formatters():
66 64 """ Return a list of default display formatters.
67 65 """
68 66
69 67 from display_formatter import PPrintDisplayFormatter, ReprDisplayFormatter
70 68 return [PPrintDisplayFormatter(), ReprDisplayFormatter()]
71 69
72 70 def default_traceback_formatters():
73 71 """ Return a list of default traceback formatters.
74 72 """
75 73
76 74 from traceback_formatter import PlainTracebackFormatter
77 75 return [PlainTracebackFormatter()]
78 76
79 77 # Top-level classes
80 78 class NotDefined(object): pass
81 79
82 80 class Interpreter(object):
83 81 """ An interpreter object.
84 82
85 83 fixme: needs to negotiate available formatters with frontends.
86 84
87 85 Important: the interpeter should be built so that it exposes a method
88 86 for each attribute/method of its sub-object. This way it can be
89 87 replaced by a network adapter.
90 88 """
91 89
92 90 def __init__(self, user_ns=None, global_ns=None,translator=None,
93 91 magic=None, display_formatters=None,
94 92 traceback_formatters=None, output_trap=None, history=None,
95 93 message_cache=None, filename='<string>', config=None):
96 94
97 95 # The local/global namespaces for code execution
98 96 local_ns = user_ns # compatibility name
99 97 if local_ns is None:
100 98 local_ns = {}
101 99 self.user_ns = local_ns
102 100 # The local namespace
103 101 if global_ns is None:
104 102 global_ns = {}
105 103 self.user_global_ns = global_ns
106 104
107 105 # An object that will translate commands into executable Python.
108 106 # The current translator does not work properly so for now we are going
109 107 # without!
110 108 # if translator is None:
111 109 # from IPython.kernel.core.translator import IPythonTranslator
112 110 # translator = IPythonTranslator()
113 111 self.translator = translator
114 112
115 113 # An object that maintains magic commands.
116 114 if magic is None:
117 115 from IPython.kernel.core.magic import Magic
118 116 magic = Magic(self)
119 117 self.magic = magic
120 118
121 119 # A list of formatters for the displayhook.
122 120 if display_formatters is None:
123 121 display_formatters = default_display_formatters()
124 122 self.display_formatters = display_formatters
125 123
126 124 # A list of formatters for tracebacks.
127 125 if traceback_formatters is None:
128 126 traceback_formatters = default_traceback_formatters()
129 127 self.traceback_formatters = traceback_formatters
130 128
131 129 # The object trapping stdout/stderr.
132 130 if output_trap is None:
133 131 from IPython.kernel.core.output_trap import OutputTrap
134 132 output_trap = OutputTrap()
135 133 self.output_trap = output_trap
136 134
137 135 # An object that manages the history.
138 136 if history is None:
139 137 from IPython.kernel.core.history import InterpreterHistory
140 138 history = InterpreterHistory()
141 139 self.history = history
142 140 self.get_history_item = history.get_history_item
143 141 self.get_history_input_cache = history.get_input_cache
144 142 self.get_history_input_after = history.get_input_after
145 143
146 144 # An object that caches all of the return messages.
147 145 if message_cache is None:
148 146 from IPython.kernel.core.message_cache import SimpleMessageCache
149 147 message_cache = SimpleMessageCache()
150 148 self.message_cache = message_cache
151 149
152 150 # The "filename" of the code that is executed in this interpreter.
153 151 self.filename = filename
154 152
155 153 # An object that contains much configuration information.
156 154 if config is None:
157 155 # fixme: Move this constant elsewhere!
158 156 config = Bunch(ESC_MAGIC='%')
159 157 self.config = config
160 158
161 159 # Hook managers.
162 160 # fixme: make the display callbacks configurable. In the meantime,
163 161 # enable macros.
164 162 self.display_trap = DisplayTrap(
165 163 formatters=self.display_formatters,
166 164 callbacks=[self._possible_macro],
167 165 )
168 166 self.traceback_trap = TracebackTrap(
169 167 formatters=self.traceback_formatters)
170 168
171 169 # This is used temporarily for reformating exceptions in certain
172 170 # cases. It will go away once the ultraTB stuff is ported
173 171 # to ipython1
174 172 self.tbHandler = ultraTB.FormattedTB(color_scheme='NoColor',
175 173 mode='Context',
176 174 tb_offset=2)
177 175
178 176 # An object that can compile commands and remember __future__
179 177 # statements.
180 178 self.command_compiler = codeop.CommandCompiler()
181 179
182 180 # A replacement for the raw_input() and input() builtins. Change these
183 181 # attributes later to configure them.
184 182 self.raw_input_builtin = raw_input
185 183 self.input_builtin = input
186 184
187 185 # The number of the current cell.
188 186 self.current_cell_number = 1
189 187
190 188 # Initialize cache, set in/out prompts and printing system
191 189 self.outputcache = CachedOutput(self,
192 190 rc.cache_size,
193 191 rc.pprint,
194 192 input_sep = rc.separate_in,
195 193 output_sep = rc.separate_out,
196 194 output_sep2 = rc.separate_out2,
197 195 ps1 = rc.prompt_in1,
198 196 ps2 = rc.prompt_in2,
199 197 ps_out = rc.prompt_out,
200 198 pad_left = rc.prompts_pad_left)
201 199
202 200 # Need to decide later if this is the right approach, but clients
203 201 # commonly use sys.ps1/2, so it may be best to just set them here
204 202 sys.ps1 = self.outputcache.prompt1.p_str
205 203 sys.ps2 = self.outputcache.prompt2.p_str
206 204
207 205 # This is the message dictionary assigned temporarily when running the
208 206 # code.
209 207 self.message = None
210 208
211 209 self.setup_namespace()
212 210
213 211
214 212 #### Public 'Interpreter' interface ########################################
215 213
216 214 def formatTraceback(self, et, ev, tb, message=''):
217 215 """Put a formatted version of the traceback into value and reraise.
218 216
219 217 When exceptions have to be sent over the network, the traceback
220 218 needs to be put into the value of the exception in a nicely
221 219 formatted way. The method takes the type, value and tb of an
222 220 exception and puts a string representation of the tb into the
223 221 value of the exception and reraises it.
224 222
225 223 Currently this method uses the ultraTb formatter from IPython trunk.
226 224 Eventually it should simply use the traceback formatters in core
227 225 that are loaded into self.tracback_trap.formatters.
228 226 """
229 227 tbinfo = self.tbHandler.text(et,ev,tb)
230 228 ev._ipython_traceback_text = tbinfo
231 229 return et, ev, tb
232 230
233 231 def execute(self, commands, raiseException=True):
234 232 """ Execute some IPython commands.
235 233
236 234 1. Translate them into Python.
237 235 2. Run them.
238 236 3. Trap stdout/stderr.
239 237 4. Trap sys.displayhook().
240 238 5. Trap exceptions.
241 239 6. Return a message object.
242 240
243 241 Parameters
244 242 ----------
245 243 commands : str
246 244 The raw commands that the user typed into the prompt.
247 245
248 246 Returns
249 247 -------
250 248 message : dict
251 249 The dictionary of responses. See the README.txt in this directory
252 250 for an explanation of the format.
253 251 """
254 252
255 253 # Create a message dictionary with all of the information we will be
256 254 # returning to the frontend and other listeners.
257 255 message = self.setup_message()
258 256
259 257 # Massage the input and store the raw and translated commands into
260 258 # a dict.
261 259 user_input = dict(raw=commands)
262 260 if self.translator is not None:
263 261 python = self.translator(commands, message)
264 262 if python is None:
265 263 # Something went wrong with the translation. The translator
266 264 # should have added an appropriate entry to the message object.
267 265 return message
268 266 else:
269 267 python = commands
270 268 user_input['translated'] = python
271 269 message['input'] = user_input
272 270
273 271 # Set the message object so that any magics executed in the code have
274 272 # access.
275 273 self.message = message
276 274
277 275 # Set all of the output/exception traps.
278 276 self.set_traps()
279 277
280 278 # Actually execute the Python code.
281 279 status = self.execute_python(python)
282 280
283 281 # Unset all of the traps.
284 282 self.unset_traps()
285 283
286 284 # Unset the message object.
287 285 self.message = None
288 286
289 287 # Update the history variables in the namespace.
290 288 # E.g. In, Out, _, __, ___
291 289 if self.history is not None:
292 290 self.history.update_history(self, python)
293 291
294 292 # Let all of the traps contribute to the message and then clear their
295 293 # stored information.
296 294 self.output_trap.add_to_message(message)
297 295 self.output_trap.clear()
298 296 self.display_trap.add_to_message(message)
299 297 self.display_trap.clear()
300 298 self.traceback_trap.add_to_message(message)
301 299 # Pull out the type, value and tb of the current exception
302 300 # before clearing it.
303 301 einfo = self.traceback_trap.args
304 302 self.traceback_trap.clear()
305 303
306 304 # Cache the message.
307 305 self.message_cache.add_message(self.current_cell_number, message)
308 306
309 307 # Bump the number.
310 308 self.current_cell_number += 1
311 309
312 310 # This conditional lets the execute method either raise any
313 311 # exception that has occured in user code OR return the message
314 312 # dict containing the traceback and other useful info.
315 313 if raiseException and einfo:
316 314 raise einfo[0],einfo[1],einfo[2]
317 315 else:
318 316 return message
319 317
320 318 def generate_prompt(self, is_continuation):
321 319 """Calculate and return a string with the prompt to display.
322 320
323 321 :Parameters:
324 322 is_continuation : bool
325 323 Whether the input line is continuing multiline input or not, so
326 324 that a proper continuation prompt can be computed."""
327 325
328 326 if is_continuation:
329 327 return str(self.outputcache.prompt2)
330 328 else:
331 329 return str(self.outputcache.prompt1)
332 330
333 331 def execute_python(self, python):
334 332 """ Actually run the Python code in the namespace.
335 333
336 334 :Parameters:
337 335
338 336 python : str
339 337 Pure, exec'able Python code. Special IPython commands should have
340 338 already been translated into pure Python.
341 339 """
342 340
343 341 # We use a CommandCompiler instance to compile the code so as to keep
344 342 # track of __future__ imports.
345 343 try:
346 344 commands = self.split_commands(python)
347 345 except (SyntaxError, IndentationError), e:
348 346 # Save the exc_info so compilation related exceptions can be
349 347 # reraised
350 348 self.traceback_trap.args = sys.exc_info()
351 349 self.pack_exception(self.message,e)
352 350 return None
353 351
354 352 for cmd in commands:
355 353 try:
356 354 code = self.command_compiler(cmd, self.filename, 'single')
357 355 except (SyntaxError, OverflowError, ValueError), e:
358 356 self.traceback_trap.args = sys.exc_info()
359 357 self.pack_exception(self.message,e)
360 358 # No point in continuing if one block raised
361 359 return None
362 360 else:
363 361 self.execute_block(code)
364 362
365 363 def execute_block(self,code):
366 364 """Execute a single block of code in the user namespace.
367 365
368 366 Return value: a flag indicating whether the code to be run completed
369 367 successfully:
370 368
371 369 - 0: successful execution.
372 370 - 1: an error occurred.
373 371 """
374 372
375 373 outflag = 1 # start by assuming error, success will reset it
376 374 try:
377 375 exec code in self.user_ns
378 376 outflag = 0
379 377 except SystemExit:
380 378 self.resetbuffer()
381 379 self.traceback_trap.args = sys.exc_info()
382 380 except:
383 381 self.traceback_trap.args = sys.exc_info()
384 382
385 383 return outflag
386 384
387 385 def execute_macro(self, macro):
388 386 """ Execute the value of a macro.
389 387
390 388 Parameters
391 389 ----------
392 390 macro : Macro
393 391 """
394 392
395 393 python = macro.value
396 394 if self.translator is not None:
397 395 python = self.translator(python)
398 396 self.execute_python(python)
399 397
400 398 def getCommand(self, i=None):
401 399 """Gets the ith message in the message_cache.
402 400
403 401 This is implemented here for compatibility with the old ipython1 shell
404 402 I am not sure we need this though. I even seem to remember that we
405 403 were going to get rid of it.
406 404 """
407 405 return self.message_cache.get_message(i)
408 406
409 407 def reset(self):
410 408 """Reset the interpreter.
411 409
412 410 Currently this only resets the users variables in the namespace.
413 411 In the future we might want to also reset the other stateful
414 412 things like that the Interpreter has, like In, Out, etc.
415 413 """
416 414 self.user_ns.clear()
417 415 self.setup_namespace()
418 416
419 417 def complete(self,line,text=None, pos=None):
420 418 """Complete the given text.
421 419
422 420 :Parameters:
423 421
424 422 text : str
425 423 Text fragment to be completed on. Typically this is
426 424 """
427 425 # fixme: implement
428 426 raise NotImplementedError
429 427
430 428 def push(self, ns):
431 429 """ Put value into the namespace with name key.
432 430
433 431 Parameters
434 432 ----------
435 433 **kwds
436 434 """
437 435
438 436 self.user_ns.update(ns)
439 437
440 438 def push_function(self, ns):
441 439 # First set the func_globals for all functions to self.user_ns
442 440 new_kwds = {}
443 441 for k, v in ns.iteritems():
444 442 if not isinstance(v, FunctionType):
445 443 raise TypeError("function object expected")
446 444 new_kwds[k] = FunctionType(v.func_code, self.user_ns)
447 445 self.user_ns.update(new_kwds)
448 446
449 447 def pack_exception(self,message,exc):
450 448 message['exception'] = exc.__class__
451 449 message['exception_value'] = \
452 450 traceback.format_exception_only(exc.__class__, exc)
453 451
454 452 def feed_block(self, source, filename='<input>', symbol='single'):
455 453 """Compile some source in the interpreter.
456 454
457 455 One several things can happen:
458 456
459 457 1) The input is incorrect; compile_command() raised an
460 458 exception (SyntaxError or OverflowError).
461 459
462 460 2) The input is incomplete, and more input is required;
463 461 compile_command() returned None. Nothing happens.
464 462
465 463 3) The input is complete; compile_command() returned a code
466 464 object. The code is executed by calling self.runcode() (which
467 465 also handles run-time exceptions, except for SystemExit).
468 466
469 467 The return value is:
470 468
471 469 - True in case 2
472 470
473 471 - False in the other cases, unless an exception is raised, where
474 472 None is returned instead. This can be used by external callers to
475 473 know whether to continue feeding input or not.
476 474
477 475 The return value can be used to decide whether to use sys.ps1 or
478 476 sys.ps2 to prompt the next line."""
479 477
480 478 self.message = self.setup_message()
481 479
482 480 try:
483 481 code = self.command_compiler(source,filename,symbol)
484 482 except (OverflowError, SyntaxError, IndentationError, ValueError ), e:
485 483 # Case 1
486 484 self.traceback_trap.args = sys.exc_info()
487 485 self.pack_exception(self.message,e)
488 486 return COMPILER_ERROR,False
489 487
490 488 if code is None:
491 489 # Case 2: incomplete input. This means that the input can span
492 490 # multiple lines. But we still need to decide when to actually
493 491 # stop taking user input. Later we'll add auto-indentation support
494 492 # somehow. In the meantime, we'll just stop if there are two lines
495 493 # of pure whitespace at the end.
496 494 last_two = source.rsplit('\n',2)[-2:]
497 495 print 'last two:',last_two # dbg
498 496 if len(last_two)==2 and all(s.isspace() for s in last_two):
499 497 return COMPLETE_INPUT,False
500 498 else:
501 499 return INCOMPLETE_INPUT, True
502 500 else:
503 501 # Case 3
504 502 return COMPLETE_INPUT, False
505 503
506 504 def pull(self, keys):
507 505 """ Get an item out of the namespace by key.
508 506
509 507 Parameters
510 508 ----------
511 509 key : str
512 510
513 511 Returns
514 512 -------
515 513 value : object
516 514
517 515 Raises
518 516 ------
519 517 TypeError if the key is not a string.
520 518 NameError if the object doesn't exist.
521 519 """
522 520
523 521 if isinstance(keys, str):
524 522 result = self.user_ns.get(keys, NotDefined())
525 523 if isinstance(result, NotDefined):
526 524 raise NameError('name %s is not defined' % keys)
527 525 elif isinstance(keys, (list, tuple)):
528 526 result = []
529 527 for key in keys:
530 528 if not isinstance(key, str):
531 529 raise TypeError("objects must be keyed by strings.")
532 530 else:
533 531 r = self.user_ns.get(key, NotDefined())
534 532 if isinstance(r, NotDefined):
535 533 raise NameError('name %s is not defined' % key)
536 534 else:
537 535 result.append(r)
538 536 if len(keys)==1:
539 537 result = result[0]
540 538 else:
541 539 raise TypeError("keys must be a strong or a list/tuple of strings")
542 540 return result
543 541
544 542 def pull_function(self, keys):
545 543 return self.pull(keys)
546 544
547 545 #### Interactive user API ##################################################
548 546
549 547 def ipsystem(self, command):
550 548 """ Execute a command in a system shell while expanding variables in the
551 549 current namespace.
552 550
553 551 Parameters
554 552 ----------
555 553 command : str
556 554 """
557 555
558 556 # Expand $variables.
559 557 command = self.var_expand(command)
560 558
561 559 system_shell(command,
562 560 header='IPython system call: ',
563 561 verbose=self.rc.system_verbose,
564 562 )
565 563
566 564 def ipmagic(self, arg_string):
567 565 """ Call a magic function by name.
568 566
569 567 ipmagic('name -opt foo bar') is equivalent to typing at the ipython
570 568 prompt:
571 569
572 570 In[1]: %name -opt foo bar
573 571
574 572 To call a magic without arguments, simply use ipmagic('name').
575 573
576 574 This provides a proper Python function to call IPython's magics in any
577 575 valid Python code you can type at the interpreter, including loops and
578 576 compound statements. It is added by IPython to the Python builtin
579 577 namespace upon initialization.
580 578
581 579 Parameters
582 580 ----------
583 581 arg_string : str
584 582 A string containing the name of the magic function to call and any
585 583 additional arguments to be passed to the magic.
586 584
587 585 Returns
588 586 -------
589 587 something : object
590 588 The return value of the actual object.
591 589 """
592 590
593 591 # Taken from IPython.
594 592 raise NotImplementedError('Not ported yet')
595 593
596 594 args = arg_string.split(' ', 1)
597 595 magic_name = args[0]
598 596 magic_name = magic_name.lstrip(self.config.ESC_MAGIC)
599 597
600 598 try:
601 599 magic_args = args[1]
602 600 except IndexError:
603 601 magic_args = ''
604 602 fn = getattr(self.magic, 'magic_'+magic_name, None)
605 603 if fn is None:
606 604 self.error("Magic function `%s` not found." % magic_name)
607 605 else:
608 606 magic_args = self.var_expand(magic_args)
609 607 return fn(magic_args)
610 608
611 609
612 610 #### Private 'Interpreter' interface #######################################
613 611
614 612 def setup_message(self):
615 613 """Return a message object.
616 614
617 615 This method prepares and returns a message dictionary. This dict
618 616 contains the various fields that are used to transfer information about
619 617 execution, results, tracebacks, etc, to clients (either in or out of
620 618 process ones). Because of the need to work with possibly out of
621 619 process clients, this dict MUST contain strictly pickle-safe values.
622 620 """
623 621
624 622 return dict(number=self.current_cell_number)
625 623
626 624 def setup_namespace(self):
627 625 """ Add things to the namespace.
628 626 """
629 627
630 628 self.user_ns.setdefault('__name__', '__main__')
631 629 self.user_ns.setdefault('__builtins__', __builtin__)
632 630 self.user_ns['__IP'] = self
633 631 if self.raw_input_builtin is not None:
634 632 self.user_ns['raw_input'] = self.raw_input_builtin
635 633 if self.input_builtin is not None:
636 634 self.user_ns['input'] = self.input_builtin
637 635
638 636 builtin_additions = dict(
639 637 ipmagic=self.ipmagic,
640 638 )
641 639 __builtin__.__dict__.update(builtin_additions)
642 640
643 641 if self.history is not None:
644 642 self.history.setup_namespace(self.user_ns)
645 643
646 644 def set_traps(self):
647 645 """ Set all of the output, display, and traceback traps.
648 646 """
649 647
650 648 self.output_trap.set()
651 649 self.display_trap.set()
652 650 self.traceback_trap.set()
653 651
654 652 def unset_traps(self):
655 653 """ Unset all of the output, display, and traceback traps.
656 654 """
657 655
658 656 self.output_trap.unset()
659 657 self.display_trap.unset()
660 658 self.traceback_trap.unset()
661 659
662 660 def split_commands(self, python):
663 661 """ Split multiple lines of code into discrete commands that can be
664 662 executed singly.
665 663
666 664 Parameters
667 665 ----------
668 666 python : str
669 667 Pure, exec'able Python code.
670 668
671 669 Returns
672 670 -------
673 671 commands : list of str
674 672 Separate commands that can be exec'ed independently.
675 673 """
676 674
677 675 # compiler.parse treats trailing spaces after a newline as a
678 676 # SyntaxError. This is different than codeop.CommandCompiler, which
679 677 # will compile the trailng spaces just fine. We simply strip any
680 678 # trailing whitespace off. Passing a string with trailing whitespace
681 679 # to exec will fail however. There seems to be some inconsistency in
682 680 # how trailing whitespace is handled, but this seems to work.
683 681 python = python.strip()
684 682
685 683 # The compiler module will parse the code into an abstract syntax tree.
686 684 ast = compiler.parse(python)
687 685
688 686 # Uncomment to help debug the ast tree
689 687 # for n in ast.node:
690 688 # print n.lineno,'->',n
691 689
692 690 # Each separate command is available by iterating over ast.node. The
693 691 # lineno attribute is the line number (1-indexed) beginning the commands
694 692 # suite.
695 693 # lines ending with ";" yield a Discard Node that doesn't have a lineno
696 694 # attribute. These nodes can and should be discarded. But there are
697 695 # other situations that cause Discard nodes that shouldn't be discarded.
698 696 # We might eventually discover other cases where lineno is None and have
699 697 # to put in a more sophisticated test.
700 698 linenos = [x.lineno-1 for x in ast.node if x.lineno is not None]
701 699
702 700 # When we finally get the slices, we will need to slice all the way to
703 701 # the end even though we don't have a line number for it. Fortunately,
704 702 # None does the job nicely.
705 703 linenos.append(None)
706 704 lines = python.splitlines()
707 705
708 706 # Create a list of atomic commands.
709 707 cmds = []
710 708 for i, j in zip(linenos[:-1], linenos[1:]):
711 709 cmd = lines[i:j]
712 710 if cmd:
713 711 cmds.append('\n'.join(cmd)+'\n')
714 712
715 713 return cmds
716 714
717 715 def error(self, text):
718 716 """ Pass an error message back to the shell.
719 717
720 718 Preconditions
721 719 -------------
722 720 This should only be called when self.message is set. In other words,
723 721 when code is being executed.
724 722
725 723 Parameters
726 724 ----------
727 725 text : str
728 726 """
729 727
730 728 errors = self.message.get('IPYTHON_ERROR', [])
731 729 errors.append(text)
732 730
733 731 def var_expand(self, template):
734 732 """ Expand $variables in the current namespace using Itpl.
735 733
736 734 Parameters
737 735 ----------
738 736 template : str
739 737 """
740 738
741 739 return str(ItplNS(template, self.user_ns))
742 740
743 741 def _possible_macro(self, obj):
744 742 """ If the object is a macro, execute it.
745 743 """
746 744
747 745 if isinstance(obj, Macro):
748 746 self.execute_macro(obj)
749 747
General Comments 0
You need to be logged in to leave comments. Login now