##// END OF EJS Templates
Add set_next_input method to ZMQInteractiveShell, so that %recall can put code at the next prompt.
Thomas Kluyver -
Show More
@@ -1,496 +1,496 b''
1 """ A FrontendWidget that emulates the interface of the console IPython and
1 """ A FrontendWidget that emulates the interface of the console IPython and
2 supports the additional functionality provided by the IPython kernel.
2 supports the additional functionality provided by the IPython kernel.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Imports
6 # Imports
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 # Standard library imports
9 # Standard library imports
10 from collections import namedtuple
10 from collections import namedtuple
11 import os.path
11 import os.path
12 import re
12 import re
13 from subprocess import Popen
13 from subprocess import Popen
14 import sys
14 import sys
15 from textwrap import dedent
15 from textwrap import dedent
16
16
17 # System library imports
17 # System library imports
18 from IPython.external.qt import QtCore, QtGui
18 from IPython.external.qt import QtCore, QtGui
19
19
20 # Local imports
20 # Local imports
21 from IPython.core.inputsplitter import IPythonInputSplitter, \
21 from IPython.core.inputsplitter import IPythonInputSplitter, \
22 transform_ipy_prompt
22 transform_ipy_prompt
23 from IPython.core.usage import default_gui_banner
23 from IPython.core.usage import default_gui_banner
24 from IPython.utils.traitlets import Bool, Str, Unicode
24 from IPython.utils.traitlets import Bool, Str, Unicode
25 from frontend_widget import FrontendWidget
25 from frontend_widget import FrontendWidget
26 from styles import (default_light_style_sheet, default_light_syntax_style,
26 from styles import (default_light_style_sheet, default_light_syntax_style,
27 default_dark_style_sheet, default_dark_syntax_style,
27 default_dark_style_sheet, default_dark_syntax_style,
28 default_bw_style_sheet, default_bw_syntax_style)
28 default_bw_style_sheet, default_bw_syntax_style)
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Constants
31 # Constants
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 # Default strings to build and display input and output prompts (and separators
34 # Default strings to build and display input and output prompts (and separators
35 # in between)
35 # in between)
36 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
36 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
37 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
37 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
38 default_input_sep = '\n'
38 default_input_sep = '\n'
39 default_output_sep = ''
39 default_output_sep = ''
40 default_output_sep2 = ''
40 default_output_sep2 = ''
41
41
42 # Base path for most payload sources.
42 # Base path for most payload sources.
43 zmq_shell_source = 'IPython.zmq.zmqshell.ZMQInteractiveShell'
43 zmq_shell_source = 'IPython.zmq.zmqshell.ZMQInteractiveShell'
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # IPythonWidget class
46 # IPythonWidget class
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 class IPythonWidget(FrontendWidget):
49 class IPythonWidget(FrontendWidget):
50 """ A FrontendWidget for an IPython kernel.
50 """ A FrontendWidget for an IPython kernel.
51 """
51 """
52
52
53 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
53 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
54 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
54 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
55 # settings.
55 # settings.
56 custom_edit = Bool(False)
56 custom_edit = Bool(False)
57 custom_edit_requested = QtCore.Signal(object, object)
57 custom_edit_requested = QtCore.Signal(object, object)
58
58
59 # A command for invoking a system text editor. If the string contains a
59 # A command for invoking a system text editor. If the string contains a
60 # {filename} format specifier, it will be used. Otherwise, the filename will
60 # {filename} format specifier, it will be used. Otherwise, the filename will
61 # be appended to the end the command.
61 # be appended to the end the command.
62 editor = Unicode('default', config=True)
62 editor = Unicode('default', config=True)
63
63
64 # The editor command to use when a specific line number is requested. The
64 # The editor command to use when a specific line number is requested. The
65 # string should contain two format specifiers: {line} and {filename}. If
65 # string should contain two format specifiers: {line} and {filename}. If
66 # this parameter is not specified, the line number option to the %edit magic
66 # this parameter is not specified, the line number option to the %edit magic
67 # will be ignored.
67 # will be ignored.
68 editor_line = Unicode(config=True)
68 editor_line = Unicode(config=True)
69
69
70 # A CSS stylesheet. The stylesheet can contain classes for:
70 # A CSS stylesheet. The stylesheet can contain classes for:
71 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
71 # 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
72 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
72 # 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter)
73 # 3. IPython: .error, .in-prompt, .out-prompt, etc
73 # 3. IPython: .error, .in-prompt, .out-prompt, etc
74 style_sheet = Unicode(config=True)
74 style_sheet = Unicode(config=True)
75
75
76 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
76 # If not empty, use this Pygments style for syntax highlighting. Otherwise,
77 # the style sheet is queried for Pygments style information.
77 # the style sheet is queried for Pygments style information.
78 syntax_style = Str(config=True)
78 syntax_style = Str(config=True)
79
79
80 # Prompts.
80 # Prompts.
81 in_prompt = Str(default_in_prompt, config=True)
81 in_prompt = Str(default_in_prompt, config=True)
82 out_prompt = Str(default_out_prompt, config=True)
82 out_prompt = Str(default_out_prompt, config=True)
83 input_sep = Str(default_input_sep, config=True)
83 input_sep = Str(default_input_sep, config=True)
84 output_sep = Str(default_output_sep, config=True)
84 output_sep = Str(default_output_sep, config=True)
85 output_sep2 = Str(default_output_sep2, config=True)
85 output_sep2 = Str(default_output_sep2, config=True)
86
86
87 # FrontendWidget protected class variables.
87 # FrontendWidget protected class variables.
88 _input_splitter_class = IPythonInputSplitter
88 _input_splitter_class = IPythonInputSplitter
89
89
90 # IPythonWidget protected class variables.
90 # IPythonWidget protected class variables.
91 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
91 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
92 _payload_source_edit = zmq_shell_source + '.edit_magic'
92 _payload_source_edit = zmq_shell_source + '.edit_magic'
93 _payload_source_exit = zmq_shell_source + '.ask_exit'
93 _payload_source_exit = zmq_shell_source + '.ask_exit'
94 _payload_source_loadpy = zmq_shell_source + '.magic_loadpy'
94 _payload_source_next_input = zmq_shell_source + '.set_next_input'
95 _payload_source_page = 'IPython.zmq.page.page'
95 _payload_source_page = 'IPython.zmq.page.page'
96
96
97 #---------------------------------------------------------------------------
97 #---------------------------------------------------------------------------
98 # 'object' interface
98 # 'object' interface
99 #---------------------------------------------------------------------------
99 #---------------------------------------------------------------------------
100
100
101 def __init__(self, *args, **kw):
101 def __init__(self, *args, **kw):
102 super(IPythonWidget, self).__init__(*args, **kw)
102 super(IPythonWidget, self).__init__(*args, **kw)
103
103
104 # IPythonWidget protected variables.
104 # IPythonWidget protected variables.
105 self._code_to_load = None
105 self._code_to_load = None
106 self._payload_handlers = {
106 self._payload_handlers = {
107 self._payload_source_edit : self._handle_payload_edit,
107 self._payload_source_edit : self._handle_payload_edit,
108 self._payload_source_exit : self._handle_payload_exit,
108 self._payload_source_exit : self._handle_payload_exit,
109 self._payload_source_page : self._handle_payload_page,
109 self._payload_source_page : self._handle_payload_page,
110 self._payload_source_loadpy : self._handle_payload_loadpy }
110 self._payload_source_next_input : self._handle_payload_next_input }
111 self._previous_prompt_obj = None
111 self._previous_prompt_obj = None
112 self._keep_kernel_on_exit = None
112 self._keep_kernel_on_exit = None
113
113
114 # Initialize widget styling.
114 # Initialize widget styling.
115 if self.style_sheet:
115 if self.style_sheet:
116 self._style_sheet_changed()
116 self._style_sheet_changed()
117 self._syntax_style_changed()
117 self._syntax_style_changed()
118 else:
118 else:
119 self.set_default_style()
119 self.set_default_style()
120
120
121 #---------------------------------------------------------------------------
121 #---------------------------------------------------------------------------
122 # 'BaseFrontendMixin' abstract interface
122 # 'BaseFrontendMixin' abstract interface
123 #---------------------------------------------------------------------------
123 #---------------------------------------------------------------------------
124
124
125 def _handle_complete_reply(self, rep):
125 def _handle_complete_reply(self, rep):
126 """ Reimplemented to support IPython's improved completion machinery.
126 """ Reimplemented to support IPython's improved completion machinery.
127 """
127 """
128 cursor = self._get_cursor()
128 cursor = self._get_cursor()
129 info = self._request_info.get('complete')
129 info = self._request_info.get('complete')
130 if info and info.id == rep['parent_header']['msg_id'] and \
130 if info and info.id == rep['parent_header']['msg_id'] and \
131 info.pos == cursor.position():
131 info.pos == cursor.position():
132 matches = rep['content']['matches']
132 matches = rep['content']['matches']
133 text = rep['content']['matched_text']
133 text = rep['content']['matched_text']
134 offset = len(text)
134 offset = len(text)
135
135
136 # Clean up matches with period and path separators if the matched
136 # Clean up matches with period and path separators if the matched
137 # text has not been transformed. This is done by truncating all
137 # text has not been transformed. This is done by truncating all
138 # but the last component and then suitably decreasing the offset
138 # but the last component and then suitably decreasing the offset
139 # between the current cursor position and the start of completion.
139 # between the current cursor position and the start of completion.
140 if len(matches) > 1 and matches[0][:offset] == text:
140 if len(matches) > 1 and matches[0][:offset] == text:
141 parts = re.split(r'[./\\]', text)
141 parts = re.split(r'[./\\]', text)
142 sep_count = len(parts) - 1
142 sep_count = len(parts) - 1
143 if sep_count:
143 if sep_count:
144 chop_length = sum(map(len, parts[:sep_count])) + sep_count
144 chop_length = sum(map(len, parts[:sep_count])) + sep_count
145 matches = [ match[chop_length:] for match in matches ]
145 matches = [ match[chop_length:] for match in matches ]
146 offset -= chop_length
146 offset -= chop_length
147
147
148 # Move the cursor to the start of the match and complete.
148 # Move the cursor to the start of the match and complete.
149 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
149 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
150 self._complete_with_items(cursor, matches)
150 self._complete_with_items(cursor, matches)
151
151
152 def _handle_execute_reply(self, msg):
152 def _handle_execute_reply(self, msg):
153 """ Reimplemented to support prompt requests.
153 """ Reimplemented to support prompt requests.
154 """
154 """
155 info = self._request_info.get('execute')
155 info = self._request_info.get('execute')
156 if info and info.id == msg['parent_header']['msg_id']:
156 if info and info.id == msg['parent_header']['msg_id']:
157 if info.kind == 'prompt':
157 if info.kind == 'prompt':
158 number = msg['content']['execution_count'] + 1
158 number = msg['content']['execution_count'] + 1
159 self._show_interpreter_prompt(number)
159 self._show_interpreter_prompt(number)
160 else:
160 else:
161 super(IPythonWidget, self)._handle_execute_reply(msg)
161 super(IPythonWidget, self)._handle_execute_reply(msg)
162
162
163 def _handle_history_reply(self, msg):
163 def _handle_history_reply(self, msg):
164 """ Implemented to handle history tail replies, which are only supported
164 """ Implemented to handle history tail replies, which are only supported
165 by the IPython kernel.
165 by the IPython kernel.
166 """
166 """
167 history_items = msg['content']['history']
167 history_items = msg['content']['history']
168 items = [ line.rstrip() for _, _, line in history_items ]
168 items = [ line.rstrip() for _, _, line in history_items ]
169 self._set_history(items)
169 self._set_history(items)
170
170
171 def _handle_pyout(self, msg):
171 def _handle_pyout(self, msg):
172 """ Reimplemented for IPython-style "display hook".
172 """ Reimplemented for IPython-style "display hook".
173 """
173 """
174 if not self._hidden and self._is_from_this_session(msg):
174 if not self._hidden and self._is_from_this_session(msg):
175 content = msg['content']
175 content = msg['content']
176 prompt_number = content['execution_count']
176 prompt_number = content['execution_count']
177 data = content['data']
177 data = content['data']
178 if data.has_key('text/html'):
178 if data.has_key('text/html'):
179 self._append_plain_text(self.output_sep)
179 self._append_plain_text(self.output_sep)
180 self._append_html(self._make_out_prompt(prompt_number))
180 self._append_html(self._make_out_prompt(prompt_number))
181 html = data['text/html']
181 html = data['text/html']
182 self._append_plain_text('\n')
182 self._append_plain_text('\n')
183 self._append_html(html + self.output_sep2)
183 self._append_html(html + self.output_sep2)
184 elif data.has_key('text/plain'):
184 elif data.has_key('text/plain'):
185 self._append_plain_text(self.output_sep)
185 self._append_plain_text(self.output_sep)
186 self._append_html(self._make_out_prompt(prompt_number))
186 self._append_html(self._make_out_prompt(prompt_number))
187 text = data['text/plain']
187 text = data['text/plain']
188 self._append_plain_text(text + self.output_sep2)
188 self._append_plain_text(text + self.output_sep2)
189
189
190 def _handle_display_data(self, msg):
190 def _handle_display_data(self, msg):
191 """ The base handler for the ``display_data`` message.
191 """ The base handler for the ``display_data`` message.
192 """
192 """
193 # For now, we don't display data from other frontends, but we
193 # For now, we don't display data from other frontends, but we
194 # eventually will as this allows all frontends to monitor the display
194 # eventually will as this allows all frontends to monitor the display
195 # data. But we need to figure out how to handle this in the GUI.
195 # data. But we need to figure out how to handle this in the GUI.
196 if not self._hidden and self._is_from_this_session(msg):
196 if not self._hidden and self._is_from_this_session(msg):
197 source = msg['content']['source']
197 source = msg['content']['source']
198 data = msg['content']['data']
198 data = msg['content']['data']
199 metadata = msg['content']['metadata']
199 metadata = msg['content']['metadata']
200 # In the regular IPythonWidget, we simply print the plain text
200 # In the regular IPythonWidget, we simply print the plain text
201 # representation.
201 # representation.
202 if data.has_key('text/html'):
202 if data.has_key('text/html'):
203 html = data['text/html']
203 html = data['text/html']
204 self._append_html(html)
204 self._append_html(html)
205 elif data.has_key('text/plain'):
205 elif data.has_key('text/plain'):
206 text = data['text/plain']
206 text = data['text/plain']
207 self._append_plain_text(text)
207 self._append_plain_text(text)
208 # This newline seems to be needed for text and html output.
208 # This newline seems to be needed for text and html output.
209 self._append_plain_text(u'\n')
209 self._append_plain_text(u'\n')
210
210
211 def _started_channels(self):
211 def _started_channels(self):
212 """ Reimplemented to make a history request.
212 """ Reimplemented to make a history request.
213 """
213 """
214 super(IPythonWidget, self)._started_channels()
214 super(IPythonWidget, self)._started_channels()
215 self.kernel_manager.xreq_channel.history(hist_access_type='tail', n=1000)
215 self.kernel_manager.xreq_channel.history(hist_access_type='tail', n=1000)
216
216
217 #---------------------------------------------------------------------------
217 #---------------------------------------------------------------------------
218 # 'ConsoleWidget' public interface
218 # 'ConsoleWidget' public interface
219 #---------------------------------------------------------------------------
219 #---------------------------------------------------------------------------
220
220
221 def copy(self):
221 def copy(self):
222 """ Copy the currently selected text to the clipboard, removing prompts
222 """ Copy the currently selected text to the clipboard, removing prompts
223 if possible.
223 if possible.
224 """
224 """
225 text = self._control.textCursor().selection().toPlainText()
225 text = self._control.textCursor().selection().toPlainText()
226 if text:
226 if text:
227 lines = map(transform_ipy_prompt, text.splitlines())
227 lines = map(transform_ipy_prompt, text.splitlines())
228 text = '\n'.join(lines)
228 text = '\n'.join(lines)
229 QtGui.QApplication.clipboard().setText(text)
229 QtGui.QApplication.clipboard().setText(text)
230
230
231 #---------------------------------------------------------------------------
231 #---------------------------------------------------------------------------
232 # 'FrontendWidget' public interface
232 # 'FrontendWidget' public interface
233 #---------------------------------------------------------------------------
233 #---------------------------------------------------------------------------
234
234
235 def execute_file(self, path, hidden=False):
235 def execute_file(self, path, hidden=False):
236 """ Reimplemented to use the 'run' magic.
236 """ Reimplemented to use the 'run' magic.
237 """
237 """
238 # Use forward slashes on Windows to avoid escaping each separator.
238 # Use forward slashes on Windows to avoid escaping each separator.
239 if sys.platform == 'win32':
239 if sys.platform == 'win32':
240 path = os.path.normpath(path).replace('\\', '/')
240 path = os.path.normpath(path).replace('\\', '/')
241
241
242 self.execute('%%run %s' % path, hidden=hidden)
242 self.execute('%%run %s' % path, hidden=hidden)
243
243
244 #---------------------------------------------------------------------------
244 #---------------------------------------------------------------------------
245 # 'FrontendWidget' protected interface
245 # 'FrontendWidget' protected interface
246 #---------------------------------------------------------------------------
246 #---------------------------------------------------------------------------
247
247
248 def _complete(self):
248 def _complete(self):
249 """ Reimplemented to support IPython's improved completion machinery.
249 """ Reimplemented to support IPython's improved completion machinery.
250 """
250 """
251 # We let the kernel split the input line, so we *always* send an empty
251 # We let the kernel split the input line, so we *always* send an empty
252 # text field. Readline-based frontends do get a real text field which
252 # text field. Readline-based frontends do get a real text field which
253 # they can use.
253 # they can use.
254 text = ''
254 text = ''
255
255
256 # Send the completion request to the kernel
256 # Send the completion request to the kernel
257 msg_id = self.kernel_manager.xreq_channel.complete(
257 msg_id = self.kernel_manager.xreq_channel.complete(
258 text, # text
258 text, # text
259 self._get_input_buffer_cursor_line(), # line
259 self._get_input_buffer_cursor_line(), # line
260 self._get_input_buffer_cursor_column(), # cursor_pos
260 self._get_input_buffer_cursor_column(), # cursor_pos
261 self.input_buffer) # block
261 self.input_buffer) # block
262 pos = self._get_cursor().position()
262 pos = self._get_cursor().position()
263 info = self._CompletionRequest(msg_id, pos)
263 info = self._CompletionRequest(msg_id, pos)
264 self._request_info['complete'] = info
264 self._request_info['complete'] = info
265
265
266 def _get_banner(self):
266 def _get_banner(self):
267 """ Reimplemented to return IPython's default banner.
267 """ Reimplemented to return IPython's default banner.
268 """
268 """
269 return default_gui_banner
269 return default_gui_banner
270
270
271 def _process_execute_error(self, msg):
271 def _process_execute_error(self, msg):
272 """ Reimplemented for IPython-style traceback formatting.
272 """ Reimplemented for IPython-style traceback formatting.
273 """
273 """
274 content = msg['content']
274 content = msg['content']
275 traceback = '\n'.join(content['traceback']) + '\n'
275 traceback = '\n'.join(content['traceback']) + '\n'
276 if False:
276 if False:
277 # FIXME: For now, tracebacks come as plain text, so we can't use
277 # FIXME: For now, tracebacks come as plain text, so we can't use
278 # the html renderer yet. Once we refactor ultratb to produce
278 # the html renderer yet. Once we refactor ultratb to produce
279 # properly styled tracebacks, this branch should be the default
279 # properly styled tracebacks, this branch should be the default
280 traceback = traceback.replace(' ', '&nbsp;')
280 traceback = traceback.replace(' ', '&nbsp;')
281 traceback = traceback.replace('\n', '<br/>')
281 traceback = traceback.replace('\n', '<br/>')
282
282
283 ename = content['ename']
283 ename = content['ename']
284 ename_styled = '<span class="error">%s</span>' % ename
284 ename_styled = '<span class="error">%s</span>' % ename
285 traceback = traceback.replace(ename, ename_styled)
285 traceback = traceback.replace(ename, ename_styled)
286
286
287 self._append_html(traceback)
287 self._append_html(traceback)
288 else:
288 else:
289 # This is the fallback for now, using plain text with ansi escapes
289 # This is the fallback for now, using plain text with ansi escapes
290 self._append_plain_text(traceback)
290 self._append_plain_text(traceback)
291
291
292 def _process_execute_payload(self, item):
292 def _process_execute_payload(self, item):
293 """ Reimplemented to dispatch payloads to handler methods.
293 """ Reimplemented to dispatch payloads to handler methods.
294 """
294 """
295 handler = self._payload_handlers.get(item['source'])
295 handler = self._payload_handlers.get(item['source'])
296 if handler is None:
296 if handler is None:
297 # We have no handler for this type of payload, simply ignore it
297 # We have no handler for this type of payload, simply ignore it
298 return False
298 return False
299 else:
299 else:
300 handler(item)
300 handler(item)
301 return True
301 return True
302
302
303 def _show_interpreter_prompt(self, number=None):
303 def _show_interpreter_prompt(self, number=None):
304 """ Reimplemented for IPython-style prompts.
304 """ Reimplemented for IPython-style prompts.
305 """
305 """
306 # If a number was not specified, make a prompt number request.
306 # If a number was not specified, make a prompt number request.
307 if number is None:
307 if number is None:
308 msg_id = self.kernel_manager.xreq_channel.execute('', silent=True)
308 msg_id = self.kernel_manager.xreq_channel.execute('', silent=True)
309 info = self._ExecutionRequest(msg_id, 'prompt')
309 info = self._ExecutionRequest(msg_id, 'prompt')
310 self._request_info['execute'] = info
310 self._request_info['execute'] = info
311 return
311 return
312
312
313 # Show a new prompt and save information about it so that it can be
313 # Show a new prompt and save information about it so that it can be
314 # updated later if the prompt number turns out to be wrong.
314 # updated later if the prompt number turns out to be wrong.
315 self._prompt_sep = self.input_sep
315 self._prompt_sep = self.input_sep
316 self._show_prompt(self._make_in_prompt(number), html=True)
316 self._show_prompt(self._make_in_prompt(number), html=True)
317 block = self._control.document().lastBlock()
317 block = self._control.document().lastBlock()
318 length = len(self._prompt)
318 length = len(self._prompt)
319 self._previous_prompt_obj = self._PromptBlock(block, length, number)
319 self._previous_prompt_obj = self._PromptBlock(block, length, number)
320
320
321 # Update continuation prompt to reflect (possibly) new prompt length.
321 # Update continuation prompt to reflect (possibly) new prompt length.
322 self._set_continuation_prompt(
322 self._set_continuation_prompt(
323 self._make_continuation_prompt(self._prompt), html=True)
323 self._make_continuation_prompt(self._prompt), html=True)
324
324
325 # Load code from the %loadpy magic, if necessary.
325 # Load code from the %loadpy magic, if necessary.
326 if self._code_to_load is not None:
326 if self._code_to_load is not None:
327 self.input_buffer = dedent(self._code_to_load.rstrip())
327 self.input_buffer = dedent(self._code_to_load.rstrip())
328 self._code_to_load = None
328 self._code_to_load = None
329
329
330 def _show_interpreter_prompt_for_reply(self, msg):
330 def _show_interpreter_prompt_for_reply(self, msg):
331 """ Reimplemented for IPython-style prompts.
331 """ Reimplemented for IPython-style prompts.
332 """
332 """
333 # Update the old prompt number if necessary.
333 # Update the old prompt number if necessary.
334 content = msg['content']
334 content = msg['content']
335 previous_prompt_number = content['execution_count']
335 previous_prompt_number = content['execution_count']
336 if self._previous_prompt_obj and \
336 if self._previous_prompt_obj and \
337 self._previous_prompt_obj.number != previous_prompt_number:
337 self._previous_prompt_obj.number != previous_prompt_number:
338 block = self._previous_prompt_obj.block
338 block = self._previous_prompt_obj.block
339
339
340 # Make sure the prompt block has not been erased.
340 # Make sure the prompt block has not been erased.
341 if block.isValid() and block.text():
341 if block.isValid() and block.text():
342
342
343 # Remove the old prompt and insert a new prompt.
343 # Remove the old prompt and insert a new prompt.
344 cursor = QtGui.QTextCursor(block)
344 cursor = QtGui.QTextCursor(block)
345 cursor.movePosition(QtGui.QTextCursor.Right,
345 cursor.movePosition(QtGui.QTextCursor.Right,
346 QtGui.QTextCursor.KeepAnchor,
346 QtGui.QTextCursor.KeepAnchor,
347 self._previous_prompt_obj.length)
347 self._previous_prompt_obj.length)
348 prompt = self._make_in_prompt(previous_prompt_number)
348 prompt = self._make_in_prompt(previous_prompt_number)
349 self._prompt = self._insert_html_fetching_plain_text(
349 self._prompt = self._insert_html_fetching_plain_text(
350 cursor, prompt)
350 cursor, prompt)
351
351
352 # When the HTML is inserted, Qt blows away the syntax
352 # When the HTML is inserted, Qt blows away the syntax
353 # highlighting for the line, so we need to rehighlight it.
353 # highlighting for the line, so we need to rehighlight it.
354 self._highlighter.rehighlightBlock(cursor.block())
354 self._highlighter.rehighlightBlock(cursor.block())
355
355
356 self._previous_prompt_obj = None
356 self._previous_prompt_obj = None
357
357
358 # Show a new prompt with the kernel's estimated prompt number.
358 # Show a new prompt with the kernel's estimated prompt number.
359 self._show_interpreter_prompt(previous_prompt_number + 1)
359 self._show_interpreter_prompt(previous_prompt_number + 1)
360
360
361 #---------------------------------------------------------------------------
361 #---------------------------------------------------------------------------
362 # 'IPythonWidget' interface
362 # 'IPythonWidget' interface
363 #---------------------------------------------------------------------------
363 #---------------------------------------------------------------------------
364
364
365 def set_default_style(self, colors='lightbg'):
365 def set_default_style(self, colors='lightbg'):
366 """ Sets the widget style to the class defaults.
366 """ Sets the widget style to the class defaults.
367
367
368 Parameters:
368 Parameters:
369 -----------
369 -----------
370 colors : str, optional (default lightbg)
370 colors : str, optional (default lightbg)
371 Whether to use the default IPython light background or dark
371 Whether to use the default IPython light background or dark
372 background or B&W style.
372 background or B&W style.
373 """
373 """
374 colors = colors.lower()
374 colors = colors.lower()
375 if colors=='lightbg':
375 if colors=='lightbg':
376 self.style_sheet = default_light_style_sheet
376 self.style_sheet = default_light_style_sheet
377 self.syntax_style = default_light_syntax_style
377 self.syntax_style = default_light_syntax_style
378 elif colors=='linux':
378 elif colors=='linux':
379 self.style_sheet = default_dark_style_sheet
379 self.style_sheet = default_dark_style_sheet
380 self.syntax_style = default_dark_syntax_style
380 self.syntax_style = default_dark_syntax_style
381 elif colors=='nocolor':
381 elif colors=='nocolor':
382 self.style_sheet = default_bw_style_sheet
382 self.style_sheet = default_bw_style_sheet
383 self.syntax_style = default_bw_syntax_style
383 self.syntax_style = default_bw_syntax_style
384 else:
384 else:
385 raise KeyError("No such color scheme: %s"%colors)
385 raise KeyError("No such color scheme: %s"%colors)
386
386
387 #---------------------------------------------------------------------------
387 #---------------------------------------------------------------------------
388 # 'IPythonWidget' protected interface
388 # 'IPythonWidget' protected interface
389 #---------------------------------------------------------------------------
389 #---------------------------------------------------------------------------
390
390
391 def _edit(self, filename, line=None):
391 def _edit(self, filename, line=None):
392 """ Opens a Python script for editing.
392 """ Opens a Python script for editing.
393
393
394 Parameters:
394 Parameters:
395 -----------
395 -----------
396 filename : str
396 filename : str
397 A path to a local system file.
397 A path to a local system file.
398
398
399 line : int, optional
399 line : int, optional
400 A line of interest in the file.
400 A line of interest in the file.
401 """
401 """
402 if self.custom_edit:
402 if self.custom_edit:
403 self.custom_edit_requested.emit(filename, line)
403 self.custom_edit_requested.emit(filename, line)
404 elif self.editor == 'default':
404 elif self.editor == 'default':
405 self._append_plain_text('No default editor available.\n')
405 self._append_plain_text('No default editor available.\n')
406 else:
406 else:
407 try:
407 try:
408 filename = '"%s"' % filename
408 filename = '"%s"' % filename
409 if line and self.editor_line:
409 if line and self.editor_line:
410 command = self.editor_line.format(filename=filename,
410 command = self.editor_line.format(filename=filename,
411 line=line)
411 line=line)
412 else:
412 else:
413 try:
413 try:
414 command = self.editor.format()
414 command = self.editor.format()
415 except KeyError:
415 except KeyError:
416 command = self.editor.format(filename=filename)
416 command = self.editor.format(filename=filename)
417 else:
417 else:
418 command += ' ' + filename
418 command += ' ' + filename
419 except KeyError:
419 except KeyError:
420 self._append_plain_text('Invalid editor command.\n')
420 self._append_plain_text('Invalid editor command.\n')
421 else:
421 else:
422 try:
422 try:
423 Popen(command, shell=True)
423 Popen(command, shell=True)
424 except OSError:
424 except OSError:
425 msg = 'Opening editor with command "%s" failed.\n'
425 msg = 'Opening editor with command "%s" failed.\n'
426 self._append_plain_text(msg % command)
426 self._append_plain_text(msg % command)
427
427
428 def _make_in_prompt(self, number):
428 def _make_in_prompt(self, number):
429 """ Given a prompt number, returns an HTML In prompt.
429 """ Given a prompt number, returns an HTML In prompt.
430 """
430 """
431 body = self.in_prompt % number
431 body = self.in_prompt % number
432 return '<span class="in-prompt">%s</span>' % body
432 return '<span class="in-prompt">%s</span>' % body
433
433
434 def _make_continuation_prompt(self, prompt):
434 def _make_continuation_prompt(self, prompt):
435 """ Given a plain text version of an In prompt, returns an HTML
435 """ Given a plain text version of an In prompt, returns an HTML
436 continuation prompt.
436 continuation prompt.
437 """
437 """
438 end_chars = '...: '
438 end_chars = '...: '
439 space_count = len(prompt.lstrip('\n')) - len(end_chars)
439 space_count = len(prompt.lstrip('\n')) - len(end_chars)
440 body = '&nbsp;' * space_count + end_chars
440 body = '&nbsp;' * space_count + end_chars
441 return '<span class="in-prompt">%s</span>' % body
441 return '<span class="in-prompt">%s</span>' % body
442
442
443 def _make_out_prompt(self, number):
443 def _make_out_prompt(self, number):
444 """ Given a prompt number, returns an HTML Out prompt.
444 """ Given a prompt number, returns an HTML Out prompt.
445 """
445 """
446 body = self.out_prompt % number
446 body = self.out_prompt % number
447 return '<span class="out-prompt">%s</span>' % body
447 return '<span class="out-prompt">%s</span>' % body
448
448
449 #------ Payload handlers --------------------------------------------------
449 #------ Payload handlers --------------------------------------------------
450
450
451 # Payload handlers with a generic interface: each takes the opaque payload
451 # Payload handlers with a generic interface: each takes the opaque payload
452 # dict, unpacks it and calls the underlying functions with the necessary
452 # dict, unpacks it and calls the underlying functions with the necessary
453 # arguments.
453 # arguments.
454
454
455 def _handle_payload_edit(self, item):
455 def _handle_payload_edit(self, item):
456 self._edit(item['filename'], item['line_number'])
456 self._edit(item['filename'], item['line_number'])
457
457
458 def _handle_payload_exit(self, item):
458 def _handle_payload_exit(self, item):
459 self._keep_kernel_on_exit = item['keepkernel']
459 self._keep_kernel_on_exit = item['keepkernel']
460 self.exit_requested.emit()
460 self.exit_requested.emit()
461
461
462 def _handle_payload_loadpy(self, item):
462 def _handle_payload_next_input(self, item):
463 # Simple save the text of the .py file for later. The text is written
463 # Simply store the text for now. It is written to the buffer when
464 # to the buffer when _prompt_started_hook is called.
464 # _show_interpreter_prompt is called.
465 self._code_to_load = item['text']
465 self._code_to_load = item['text']
466
466
467 def _handle_payload_page(self, item):
467 def _handle_payload_page(self, item):
468 # Since the plain text widget supports only a very small subset of HTML
468 # Since the plain text widget supports only a very small subset of HTML
469 # and we have no control over the HTML source, we only page HTML
469 # and we have no control over the HTML source, we only page HTML
470 # payloads in the rich text widget.
470 # payloads in the rich text widget.
471 if item['html'] and self.kind == 'rich':
471 if item['html'] and self.kind == 'rich':
472 self._page(item['html'], html=True)
472 self._page(item['html'], html=True)
473 else:
473 else:
474 self._page(item['text'], html=False)
474 self._page(item['text'], html=False)
475
475
476 #------ Trait change handlers --------------------------------------------
476 #------ Trait change handlers --------------------------------------------
477
477
478 def _style_sheet_changed(self):
478 def _style_sheet_changed(self):
479 """ Set the style sheets of the underlying widgets.
479 """ Set the style sheets of the underlying widgets.
480 """
480 """
481 self.setStyleSheet(self.style_sheet)
481 self.setStyleSheet(self.style_sheet)
482 self._control.document().setDefaultStyleSheet(self.style_sheet)
482 self._control.document().setDefaultStyleSheet(self.style_sheet)
483 if self._page_control:
483 if self._page_control:
484 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
484 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
485
485
486 bg_color = self._control.palette().window().color()
486 bg_color = self._control.palette().window().color()
487 self._ansi_processor.set_background_color(bg_color)
487 self._ansi_processor.set_background_color(bg_color)
488
488
489 def _syntax_style_changed(self):
489 def _syntax_style_changed(self):
490 """ Set the style for the syntax highlighter.
490 """ Set the style for the syntax highlighter.
491 """
491 """
492 if self.syntax_style:
492 if self.syntax_style:
493 self._highlighter.set_style(self.syntax_style)
493 self._highlighter.set_style(self.syntax_style)
494 else:
494 else:
495 self._highlighter.set_style_sheet(self.style_sheet)
495 self._highlighter.set_style_sheet(self.style_sheet)
496
496
@@ -1,601 +1,606 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
12 """
12 """
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import inspect
19 import inspect
20 import os
20 import os
21
21
22 # Our own
22 # Our own
23 from IPython.core.interactiveshell import (
23 from IPython.core.interactiveshell import (
24 InteractiveShell, InteractiveShellABC
24 InteractiveShell, InteractiveShellABC
25 )
25 )
26 from IPython.core import page
26 from IPython.core import page
27 from IPython.core.autocall import ZMQExitAutocall
27 from IPython.core.autocall import ZMQExitAutocall
28 from IPython.core.displayhook import DisplayHook
28 from IPython.core.displayhook import DisplayHook
29 from IPython.core.displaypub import DisplayPublisher
29 from IPython.core.displaypub import DisplayPublisher
30 from IPython.core.macro import Macro
30 from IPython.core.macro import Macro
31 from IPython.core.payloadpage import install_payload_page
31 from IPython.core.payloadpage import install_payload_page
32 from IPython.utils import io
32 from IPython.utils import io
33 from IPython.utils.path import get_py_filename
33 from IPython.utils.path import get_py_filename
34 from IPython.utils.traitlets import Instance, Type, Dict
34 from IPython.utils.traitlets import Instance, Type, Dict
35 from IPython.utils.warn import warn
35 from IPython.utils.warn import warn
36 from IPython.zmq.session import extract_header
36 from IPython.zmq.session import extract_header
37 from session import Session
37 from session import Session
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Globals and side-effects
40 # Globals and side-effects
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 # Install the payload version of page.
43 # Install the payload version of page.
44 install_payload_page()
44 install_payload_page()
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Functions and classes
47 # Functions and classes
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50 class ZMQDisplayHook(DisplayHook):
50 class ZMQDisplayHook(DisplayHook):
51 """A displayhook subclass that publishes data using ZeroMQ."""
51 """A displayhook subclass that publishes data using ZeroMQ."""
52
52
53 session = Instance(Session)
53 session = Instance(Session)
54 pub_socket = Instance('zmq.Socket')
54 pub_socket = Instance('zmq.Socket')
55 parent_header = Dict({})
55 parent_header = Dict({})
56
56
57 def set_parent(self, parent):
57 def set_parent(self, parent):
58 """Set the parent for outbound messages."""
58 """Set the parent for outbound messages."""
59 self.parent_header = extract_header(parent)
59 self.parent_header = extract_header(parent)
60
60
61 def start_displayhook(self):
61 def start_displayhook(self):
62 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
62 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
63
63
64 def write_output_prompt(self):
64 def write_output_prompt(self):
65 """Write the output prompt."""
65 """Write the output prompt."""
66 if self.do_full_cache:
66 if self.do_full_cache:
67 self.msg['content']['execution_count'] = self.prompt_count
67 self.msg['content']['execution_count'] = self.prompt_count
68
68
69 def write_format_data(self, format_dict):
69 def write_format_data(self, format_dict):
70 self.msg['content']['data'] = format_dict
70 self.msg['content']['data'] = format_dict
71
71
72 def finish_displayhook(self):
72 def finish_displayhook(self):
73 """Finish up all displayhook activities."""
73 """Finish up all displayhook activities."""
74 self.session.send(self.pub_socket, self.msg)
74 self.session.send(self.pub_socket, self.msg)
75 self.msg = None
75 self.msg = None
76
76
77
77
78 class ZMQDisplayPublisher(DisplayPublisher):
78 class ZMQDisplayPublisher(DisplayPublisher):
79 """A display publisher that publishes data using a ZeroMQ PUB socket."""
79 """A display publisher that publishes data using a ZeroMQ PUB socket."""
80
80
81 session = Instance(Session)
81 session = Instance(Session)
82 pub_socket = Instance('zmq.Socket')
82 pub_socket = Instance('zmq.Socket')
83 parent_header = Dict({})
83 parent_header = Dict({})
84
84
85 def set_parent(self, parent):
85 def set_parent(self, parent):
86 """Set the parent for outbound messages."""
86 """Set the parent for outbound messages."""
87 self.parent_header = extract_header(parent)
87 self.parent_header = extract_header(parent)
88
88
89 def publish(self, source, data, metadata=None):
89 def publish(self, source, data, metadata=None):
90 if metadata is None:
90 if metadata is None:
91 metadata = {}
91 metadata = {}
92 self._validate_data(source, data, metadata)
92 self._validate_data(source, data, metadata)
93 content = {}
93 content = {}
94 content['source'] = source
94 content['source'] = source
95 content['data'] = data
95 content['data'] = data
96 content['metadata'] = metadata
96 content['metadata'] = metadata
97 self.session.send(
97 self.session.send(
98 self.pub_socket, u'display_data', content,
98 self.pub_socket, u'display_data', content,
99 parent=self.parent_header
99 parent=self.parent_header
100 )
100 )
101
101
102
102
103 class ZMQInteractiveShell(InteractiveShell):
103 class ZMQInteractiveShell(InteractiveShell):
104 """A subclass of InteractiveShell for ZMQ."""
104 """A subclass of InteractiveShell for ZMQ."""
105
105
106 displayhook_class = Type(ZMQDisplayHook)
106 displayhook_class = Type(ZMQDisplayHook)
107 display_pub_class = Type(ZMQDisplayPublisher)
107 display_pub_class = Type(ZMQDisplayPublisher)
108
108
109 exiter = Instance(ZMQExitAutocall)
109 exiter = Instance(ZMQExitAutocall)
110 def _exiter_default(self):
110 def _exiter_default(self):
111 return ZMQExitAutocall(self)
111 return ZMQExitAutocall(self)
112
112
113 keepkernel_on_exit = None
113 keepkernel_on_exit = None
114
114
115 def init_environment(self):
115 def init_environment(self):
116 """Configure the user's environment.
116 """Configure the user's environment.
117
117
118 """
118 """
119 env = os.environ
119 env = os.environ
120 # These two ensure 'ls' produces nice coloring on BSD-derived systems
120 # These two ensure 'ls' produces nice coloring on BSD-derived systems
121 env['TERM'] = 'xterm-color'
121 env['TERM'] = 'xterm-color'
122 env['CLICOLOR'] = '1'
122 env['CLICOLOR'] = '1'
123 # Since normal pagers don't work at all (over pexpect we don't have
123 # Since normal pagers don't work at all (over pexpect we don't have
124 # single-key control of the subprocess), try to disable paging in
124 # single-key control of the subprocess), try to disable paging in
125 # subprocesses as much as possible.
125 # subprocesses as much as possible.
126 env['PAGER'] = 'cat'
126 env['PAGER'] = 'cat'
127 env['GIT_PAGER'] = 'cat'
127 env['GIT_PAGER'] = 'cat'
128
128
129 def auto_rewrite_input(self, cmd):
129 def auto_rewrite_input(self, cmd):
130 """Called to show the auto-rewritten input for autocall and friends.
130 """Called to show the auto-rewritten input for autocall and friends.
131
131
132 FIXME: this payload is currently not correctly processed by the
132 FIXME: this payload is currently not correctly processed by the
133 frontend.
133 frontend.
134 """
134 """
135 new = self.displayhook.prompt1.auto_rewrite() + cmd
135 new = self.displayhook.prompt1.auto_rewrite() + cmd
136 payload = dict(
136 payload = dict(
137 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
137 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
138 transformed_input=new,
138 transformed_input=new,
139 )
139 )
140 self.payload_manager.write_payload(payload)
140 self.payload_manager.write_payload(payload)
141
141
142 def ask_exit(self):
142 def ask_exit(self):
143 """Engage the exit actions."""
143 """Engage the exit actions."""
144 payload = dict(
144 payload = dict(
145 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
145 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
146 exit=True,
146 exit=True,
147 keepkernel=self.keepkernel_on_exit,
147 keepkernel=self.keepkernel_on_exit,
148 )
148 )
149 self.payload_manager.write_payload(payload)
149 self.payload_manager.write_payload(payload)
150
150
151 def _showtraceback(self, etype, evalue, stb):
151 def _showtraceback(self, etype, evalue, stb):
152
152
153 exc_content = {
153 exc_content = {
154 u'traceback' : stb,
154 u'traceback' : stb,
155 u'ename' : unicode(etype.__name__),
155 u'ename' : unicode(etype.__name__),
156 u'evalue' : unicode(evalue)
156 u'evalue' : unicode(evalue)
157 }
157 }
158
158
159 dh = self.displayhook
159 dh = self.displayhook
160 # Send exception info over pub socket for other clients than the caller
160 # Send exception info over pub socket for other clients than the caller
161 # to pick up
161 # to pick up
162 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', exc_content, dh.parent_header)
162 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', exc_content, dh.parent_header)
163
163
164 # FIXME - Hack: store exception info in shell object. Right now, the
164 # FIXME - Hack: store exception info in shell object. Right now, the
165 # caller is reading this info after the fact, we need to fix this logic
165 # caller is reading this info after the fact, we need to fix this logic
166 # to remove this hack. Even uglier, we need to store the error status
166 # to remove this hack. Even uglier, we need to store the error status
167 # here, because in the main loop, the logic that sets it is being
167 # here, because in the main loop, the logic that sets it is being
168 # skipped because runlines swallows the exceptions.
168 # skipped because runlines swallows the exceptions.
169 exc_content[u'status'] = u'error'
169 exc_content[u'status'] = u'error'
170 self._reply_content = exc_content
170 self._reply_content = exc_content
171 # /FIXME
171 # /FIXME
172
172
173 return exc_content
173 return exc_content
174
174
175 #------------------------------------------------------------------------
175 #------------------------------------------------------------------------
176 # Magic overrides
176 # Magic overrides
177 #------------------------------------------------------------------------
177 #------------------------------------------------------------------------
178 # Once the base class stops inheriting from magic, this code needs to be
178 # Once the base class stops inheriting from magic, this code needs to be
179 # moved into a separate machinery as well. For now, at least isolate here
179 # moved into a separate machinery as well. For now, at least isolate here
180 # the magics which this class needs to implement differently from the base
180 # the magics which this class needs to implement differently from the base
181 # class, or that are unique to it.
181 # class, or that are unique to it.
182
182
183 def magic_doctest_mode(self,parameter_s=''):
183 def magic_doctest_mode(self,parameter_s=''):
184 """Toggle doctest mode on and off.
184 """Toggle doctest mode on and off.
185
185
186 This mode is intended to make IPython behave as much as possible like a
186 This mode is intended to make IPython behave as much as possible like a
187 plain Python shell, from the perspective of how its prompts, exceptions
187 plain Python shell, from the perspective of how its prompts, exceptions
188 and output look. This makes it easy to copy and paste parts of a
188 and output look. This makes it easy to copy and paste parts of a
189 session into doctests. It does so by:
189 session into doctests. It does so by:
190
190
191 - Changing the prompts to the classic ``>>>`` ones.
191 - Changing the prompts to the classic ``>>>`` ones.
192 - Changing the exception reporting mode to 'Plain'.
192 - Changing the exception reporting mode to 'Plain'.
193 - Disabling pretty-printing of output.
193 - Disabling pretty-printing of output.
194
194
195 Note that IPython also supports the pasting of code snippets that have
195 Note that IPython also supports the pasting of code snippets that have
196 leading '>>>' and '...' prompts in them. This means that you can paste
196 leading '>>>' and '...' prompts in them. This means that you can paste
197 doctests from files or docstrings (even if they have leading
197 doctests from files or docstrings (even if they have leading
198 whitespace), and the code will execute correctly. You can then use
198 whitespace), and the code will execute correctly. You can then use
199 '%history -t' to see the translated history; this will give you the
199 '%history -t' to see the translated history; this will give you the
200 input after removal of all the leading prompts and whitespace, which
200 input after removal of all the leading prompts and whitespace, which
201 can be pasted back into an editor.
201 can be pasted back into an editor.
202
202
203 With these features, you can switch into this mode easily whenever you
203 With these features, you can switch into this mode easily whenever you
204 need to do testing and changes to doctests, without having to leave
204 need to do testing and changes to doctests, without having to leave
205 your existing IPython session.
205 your existing IPython session.
206 """
206 """
207
207
208 from IPython.utils.ipstruct import Struct
208 from IPython.utils.ipstruct import Struct
209
209
210 # Shorthands
210 # Shorthands
211 shell = self.shell
211 shell = self.shell
212 disp_formatter = self.shell.display_formatter
212 disp_formatter = self.shell.display_formatter
213 ptformatter = disp_formatter.formatters['text/plain']
213 ptformatter = disp_formatter.formatters['text/plain']
214 # dstore is a data store kept in the instance metadata bag to track any
214 # dstore is a data store kept in the instance metadata bag to track any
215 # changes we make, so we can undo them later.
215 # changes we make, so we can undo them later.
216 dstore = shell.meta.setdefault('doctest_mode', Struct())
216 dstore = shell.meta.setdefault('doctest_mode', Struct())
217 save_dstore = dstore.setdefault
217 save_dstore = dstore.setdefault
218
218
219 # save a few values we'll need to recover later
219 # save a few values we'll need to recover later
220 mode = save_dstore('mode', False)
220 mode = save_dstore('mode', False)
221 save_dstore('rc_pprint', ptformatter.pprint)
221 save_dstore('rc_pprint', ptformatter.pprint)
222 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
222 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
223 save_dstore('xmode', shell.InteractiveTB.mode)
223 save_dstore('xmode', shell.InteractiveTB.mode)
224
224
225 if mode == False:
225 if mode == False:
226 # turn on
226 # turn on
227 ptformatter.pprint = False
227 ptformatter.pprint = False
228 disp_formatter.plain_text_only = True
228 disp_formatter.plain_text_only = True
229 shell.magic_xmode('Plain')
229 shell.magic_xmode('Plain')
230 else:
230 else:
231 # turn off
231 # turn off
232 ptformatter.pprint = dstore.rc_pprint
232 ptformatter.pprint = dstore.rc_pprint
233 disp_formatter.plain_text_only = dstore.rc_plain_text_only
233 disp_formatter.plain_text_only = dstore.rc_plain_text_only
234 shell.magic_xmode(dstore.xmode)
234 shell.magic_xmode(dstore.xmode)
235
235
236 # Store new mode and inform on console
236 # Store new mode and inform on console
237 dstore.mode = bool(1-int(mode))
237 dstore.mode = bool(1-int(mode))
238 mode_label = ['OFF','ON'][dstore.mode]
238 mode_label = ['OFF','ON'][dstore.mode]
239 print('Doctest mode is:', mode_label)
239 print('Doctest mode is:', mode_label)
240
240
241 # Send the payload back so that clients can modify their prompt display
241 # Send the payload back so that clients can modify their prompt display
242 payload = dict(
242 payload = dict(
243 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
243 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
244 mode=dstore.mode)
244 mode=dstore.mode)
245 self.payload_manager.write_payload(payload)
245 self.payload_manager.write_payload(payload)
246
246
247 def magic_edit(self,parameter_s='',last_call=['','']):
247 def magic_edit(self,parameter_s='',last_call=['','']):
248 """Bring up an editor and execute the resulting code.
248 """Bring up an editor and execute the resulting code.
249
249
250 Usage:
250 Usage:
251 %edit [options] [args]
251 %edit [options] [args]
252
252
253 %edit runs IPython's editor hook. The default version of this hook is
253 %edit runs IPython's editor hook. The default version of this hook is
254 set to call the __IPYTHON__.rc.editor command. This is read from your
254 set to call the __IPYTHON__.rc.editor command. This is read from your
255 environment variable $EDITOR. If this isn't found, it will default to
255 environment variable $EDITOR. If this isn't found, it will default to
256 vi under Linux/Unix and to notepad under Windows. See the end of this
256 vi under Linux/Unix and to notepad under Windows. See the end of this
257 docstring for how to change the editor hook.
257 docstring for how to change the editor hook.
258
258
259 You can also set the value of this editor via the command line option
259 You can also set the value of this editor via the command line option
260 '-editor' or in your ipythonrc file. This is useful if you wish to use
260 '-editor' or in your ipythonrc file. This is useful if you wish to use
261 specifically for IPython an editor different from your typical default
261 specifically for IPython an editor different from your typical default
262 (and for Windows users who typically don't set environment variables).
262 (and for Windows users who typically don't set environment variables).
263
263
264 This command allows you to conveniently edit multi-line code right in
264 This command allows you to conveniently edit multi-line code right in
265 your IPython session.
265 your IPython session.
266
266
267 If called without arguments, %edit opens up an empty editor with a
267 If called without arguments, %edit opens up an empty editor with a
268 temporary file and will execute the contents of this file when you
268 temporary file and will execute the contents of this file when you
269 close it (don't forget to save it!).
269 close it (don't forget to save it!).
270
270
271
271
272 Options:
272 Options:
273
273
274 -n <number>: open the editor at a specified line number. By default,
274 -n <number>: open the editor at a specified line number. By default,
275 the IPython editor hook uses the unix syntax 'editor +N filename', but
275 the IPython editor hook uses the unix syntax 'editor +N filename', but
276 you can configure this by providing your own modified hook if your
276 you can configure this by providing your own modified hook if your
277 favorite editor supports line-number specifications with a different
277 favorite editor supports line-number specifications with a different
278 syntax.
278 syntax.
279
279
280 -p: this will call the editor with the same data as the previous time
280 -p: this will call the editor with the same data as the previous time
281 it was used, regardless of how long ago (in your current session) it
281 it was used, regardless of how long ago (in your current session) it
282 was.
282 was.
283
283
284 -r: use 'raw' input. This option only applies to input taken from the
284 -r: use 'raw' input. This option only applies to input taken from the
285 user's history. By default, the 'processed' history is used, so that
285 user's history. By default, the 'processed' history is used, so that
286 magics are loaded in their transformed version to valid Python. If
286 magics are loaded in their transformed version to valid Python. If
287 this option is given, the raw input as typed as the command line is
287 this option is given, the raw input as typed as the command line is
288 used instead. When you exit the editor, it will be executed by
288 used instead. When you exit the editor, it will be executed by
289 IPython's own processor.
289 IPython's own processor.
290
290
291 -x: do not execute the edited code immediately upon exit. This is
291 -x: do not execute the edited code immediately upon exit. This is
292 mainly useful if you are editing programs which need to be called with
292 mainly useful if you are editing programs which need to be called with
293 command line arguments, which you can then do using %run.
293 command line arguments, which you can then do using %run.
294
294
295
295
296 Arguments:
296 Arguments:
297
297
298 If arguments are given, the following possibilites exist:
298 If arguments are given, the following possibilites exist:
299
299
300 - The arguments are numbers or pairs of colon-separated numbers (like
300 - The arguments are numbers or pairs of colon-separated numbers (like
301 1 4:8 9). These are interpreted as lines of previous input to be
301 1 4:8 9). These are interpreted as lines of previous input to be
302 loaded into the editor. The syntax is the same of the %macro command.
302 loaded into the editor. The syntax is the same of the %macro command.
303
303
304 - If the argument doesn't start with a number, it is evaluated as a
304 - If the argument doesn't start with a number, it is evaluated as a
305 variable and its contents loaded into the editor. You can thus edit
305 variable and its contents loaded into the editor. You can thus edit
306 any string which contains python code (including the result of
306 any string which contains python code (including the result of
307 previous edits).
307 previous edits).
308
308
309 - If the argument is the name of an object (other than a string),
309 - If the argument is the name of an object (other than a string),
310 IPython will try to locate the file where it was defined and open the
310 IPython will try to locate the file where it was defined and open the
311 editor at the point where it is defined. You can use `%edit function`
311 editor at the point where it is defined. You can use `%edit function`
312 to load an editor exactly at the point where 'function' is defined,
312 to load an editor exactly at the point where 'function' is defined,
313 edit it and have the file be executed automatically.
313 edit it and have the file be executed automatically.
314
314
315 If the object is a macro (see %macro for details), this opens up your
315 If the object is a macro (see %macro for details), this opens up your
316 specified editor with a temporary file containing the macro's data.
316 specified editor with a temporary file containing the macro's data.
317 Upon exit, the macro is reloaded with the contents of the file.
317 Upon exit, the macro is reloaded with the contents of the file.
318
318
319 Note: opening at an exact line is only supported under Unix, and some
319 Note: opening at an exact line is only supported under Unix, and some
320 editors (like kedit and gedit up to Gnome 2.8) do not understand the
320 editors (like kedit and gedit up to Gnome 2.8) do not understand the
321 '+NUMBER' parameter necessary for this feature. Good editors like
321 '+NUMBER' parameter necessary for this feature. Good editors like
322 (X)Emacs, vi, jed, pico and joe all do.
322 (X)Emacs, vi, jed, pico and joe all do.
323
323
324 - If the argument is not found as a variable, IPython will look for a
324 - If the argument is not found as a variable, IPython will look for a
325 file with that name (adding .py if necessary) and load it into the
325 file with that name (adding .py if necessary) and load it into the
326 editor. It will execute its contents with execfile() when you exit,
326 editor. It will execute its contents with execfile() when you exit,
327 loading any code in the file into your interactive namespace.
327 loading any code in the file into your interactive namespace.
328
328
329 After executing your code, %edit will return as output the code you
329 After executing your code, %edit will return as output the code you
330 typed in the editor (except when it was an existing file). This way
330 typed in the editor (except when it was an existing file). This way
331 you can reload the code in further invocations of %edit as a variable,
331 you can reload the code in further invocations of %edit as a variable,
332 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
332 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
333 the output.
333 the output.
334
334
335 Note that %edit is also available through the alias %ed.
335 Note that %edit is also available through the alias %ed.
336
336
337 This is an example of creating a simple function inside the editor and
337 This is an example of creating a simple function inside the editor and
338 then modifying it. First, start up the editor:
338 then modifying it. First, start up the editor:
339
339
340 In [1]: ed
340 In [1]: ed
341 Editing... done. Executing edited code...
341 Editing... done. Executing edited code...
342 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
342 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
343
343
344 We can then call the function foo():
344 We can then call the function foo():
345
345
346 In [2]: foo()
346 In [2]: foo()
347 foo() was defined in an editing session
347 foo() was defined in an editing session
348
348
349 Now we edit foo. IPython automatically loads the editor with the
349 Now we edit foo. IPython automatically loads the editor with the
350 (temporary) file where foo() was previously defined:
350 (temporary) file where foo() was previously defined:
351
351
352 In [3]: ed foo
352 In [3]: ed foo
353 Editing... done. Executing edited code...
353 Editing... done. Executing edited code...
354
354
355 And if we call foo() again we get the modified version:
355 And if we call foo() again we get the modified version:
356
356
357 In [4]: foo()
357 In [4]: foo()
358 foo() has now been changed!
358 foo() has now been changed!
359
359
360 Here is an example of how to edit a code snippet successive
360 Here is an example of how to edit a code snippet successive
361 times. First we call the editor:
361 times. First we call the editor:
362
362
363 In [5]: ed
363 In [5]: ed
364 Editing... done. Executing edited code...
364 Editing... done. Executing edited code...
365 hello
365 hello
366 Out[5]: "print 'hello'n"
366 Out[5]: "print 'hello'n"
367
367
368 Now we call it again with the previous output (stored in _):
368 Now we call it again with the previous output (stored in _):
369
369
370 In [6]: ed _
370 In [6]: ed _
371 Editing... done. Executing edited code...
371 Editing... done. Executing edited code...
372 hello world
372 hello world
373 Out[6]: "print 'hello world'n"
373 Out[6]: "print 'hello world'n"
374
374
375 Now we call it with the output #8 (stored in _8, also as Out[8]):
375 Now we call it with the output #8 (stored in _8, also as Out[8]):
376
376
377 In [7]: ed _8
377 In [7]: ed _8
378 Editing... done. Executing edited code...
378 Editing... done. Executing edited code...
379 hello again
379 hello again
380 Out[7]: "print 'hello again'n"
380 Out[7]: "print 'hello again'n"
381
381
382
382
383 Changing the default editor hook:
383 Changing the default editor hook:
384
384
385 If you wish to write your own editor hook, you can put it in a
385 If you wish to write your own editor hook, you can put it in a
386 configuration file which you load at startup time. The default hook
386 configuration file which you load at startup time. The default hook
387 is defined in the IPython.core.hooks module, and you can use that as a
387 is defined in the IPython.core.hooks module, and you can use that as a
388 starting example for further modifications. That file also has
388 starting example for further modifications. That file also has
389 general instructions on how to set a new hook for use once you've
389 general instructions on how to set a new hook for use once you've
390 defined it."""
390 defined it."""
391
391
392 # FIXME: This function has become a convoluted mess. It needs a
392 # FIXME: This function has become a convoluted mess. It needs a
393 # ground-up rewrite with clean, simple logic.
393 # ground-up rewrite with clean, simple logic.
394
394
395 def make_filename(arg):
395 def make_filename(arg):
396 "Make a filename from the given args"
396 "Make a filename from the given args"
397 try:
397 try:
398 filename = get_py_filename(arg)
398 filename = get_py_filename(arg)
399 except IOError:
399 except IOError:
400 if args.endswith('.py'):
400 if args.endswith('.py'):
401 filename = arg
401 filename = arg
402 else:
402 else:
403 filename = None
403 filename = None
404 return filename
404 return filename
405
405
406 # custom exceptions
406 # custom exceptions
407 class DataIsObject(Exception): pass
407 class DataIsObject(Exception): pass
408
408
409 opts,args = self.parse_options(parameter_s,'prn:')
409 opts,args = self.parse_options(parameter_s,'prn:')
410 # Set a few locals from the options for convenience:
410 # Set a few locals from the options for convenience:
411 opts_p = opts.has_key('p')
411 opts_p = opts.has_key('p')
412 opts_r = opts.has_key('r')
412 opts_r = opts.has_key('r')
413
413
414 # Default line number value
414 # Default line number value
415 lineno = opts.get('n',None)
415 lineno = opts.get('n',None)
416 if lineno is not None:
416 if lineno is not None:
417 try:
417 try:
418 lineno = int(lineno)
418 lineno = int(lineno)
419 except:
419 except:
420 warn("The -n argument must be an integer.")
420 warn("The -n argument must be an integer.")
421 return
421 return
422
422
423 if opts_p:
423 if opts_p:
424 args = '_%s' % last_call[0]
424 args = '_%s' % last_call[0]
425 if not self.shell.user_ns.has_key(args):
425 if not self.shell.user_ns.has_key(args):
426 args = last_call[1]
426 args = last_call[1]
427
427
428 # use last_call to remember the state of the previous call, but don't
428 # use last_call to remember the state of the previous call, but don't
429 # let it be clobbered by successive '-p' calls.
429 # let it be clobbered by successive '-p' calls.
430 try:
430 try:
431 last_call[0] = self.shell.displayhook.prompt_count
431 last_call[0] = self.shell.displayhook.prompt_count
432 if not opts_p:
432 if not opts_p:
433 last_call[1] = parameter_s
433 last_call[1] = parameter_s
434 except:
434 except:
435 pass
435 pass
436
436
437 # by default this is done with temp files, except when the given
437 # by default this is done with temp files, except when the given
438 # arg is a filename
438 # arg is a filename
439 use_temp = True
439 use_temp = True
440
440
441 data = ''
441 data = ''
442 if args[0].isdigit():
442 if args[0].isdigit():
443 # Mode where user specifies ranges of lines, like in %macro.
443 # Mode where user specifies ranges of lines, like in %macro.
444 # This means that you can't edit files whose names begin with
444 # This means that you can't edit files whose names begin with
445 # numbers this way. Tough.
445 # numbers this way. Tough.
446 ranges = args.split()
446 ranges = args.split()
447 data = ''.join(self.extract_input_slices(ranges,opts_r))
447 data = ''.join(self.extract_input_slices(ranges,opts_r))
448 elif args.endswith('.py'):
448 elif args.endswith('.py'):
449 filename = make_filename(args)
449 filename = make_filename(args)
450 use_temp = False
450 use_temp = False
451 elif args:
451 elif args:
452 try:
452 try:
453 # Load the parameter given as a variable. If not a string,
453 # Load the parameter given as a variable. If not a string,
454 # process it as an object instead (below)
454 # process it as an object instead (below)
455
455
456 #print '*** args',args,'type',type(args) # dbg
456 #print '*** args',args,'type',type(args) # dbg
457 data = eval(args, self.shell.user_ns)
457 data = eval(args, self.shell.user_ns)
458 if not isinstance(data, basestring):
458 if not isinstance(data, basestring):
459 raise DataIsObject
459 raise DataIsObject
460
460
461 except (NameError,SyntaxError):
461 except (NameError,SyntaxError):
462 # given argument is not a variable, try as a filename
462 # given argument is not a variable, try as a filename
463 filename = make_filename(args)
463 filename = make_filename(args)
464 if filename is None:
464 if filename is None:
465 warn("Argument given (%s) can't be found as a variable "
465 warn("Argument given (%s) can't be found as a variable "
466 "or as a filename." % args)
466 "or as a filename." % args)
467 return
467 return
468 use_temp = False
468 use_temp = False
469
469
470 except DataIsObject:
470 except DataIsObject:
471 # macros have a special edit function
471 # macros have a special edit function
472 if isinstance(data, Macro):
472 if isinstance(data, Macro):
473 self._edit_macro(args,data)
473 self._edit_macro(args,data)
474 return
474 return
475
475
476 # For objects, try to edit the file where they are defined
476 # For objects, try to edit the file where they are defined
477 try:
477 try:
478 filename = inspect.getabsfile(data)
478 filename = inspect.getabsfile(data)
479 if 'fakemodule' in filename.lower() and inspect.isclass(data):
479 if 'fakemodule' in filename.lower() and inspect.isclass(data):
480 # class created by %edit? Try to find source
480 # class created by %edit? Try to find source
481 # by looking for method definitions instead, the
481 # by looking for method definitions instead, the
482 # __module__ in those classes is FakeModule.
482 # __module__ in those classes is FakeModule.
483 attrs = [getattr(data, aname) for aname in dir(data)]
483 attrs = [getattr(data, aname) for aname in dir(data)]
484 for attr in attrs:
484 for attr in attrs:
485 if not inspect.ismethod(attr):
485 if not inspect.ismethod(attr):
486 continue
486 continue
487 filename = inspect.getabsfile(attr)
487 filename = inspect.getabsfile(attr)
488 if filename and 'fakemodule' not in filename.lower():
488 if filename and 'fakemodule' not in filename.lower():
489 # change the attribute to be the edit target instead
489 # change the attribute to be the edit target instead
490 data = attr
490 data = attr
491 break
491 break
492
492
493 datafile = 1
493 datafile = 1
494 except TypeError:
494 except TypeError:
495 filename = make_filename(args)
495 filename = make_filename(args)
496 datafile = 1
496 datafile = 1
497 warn('Could not find file where `%s` is defined.\n'
497 warn('Could not find file where `%s` is defined.\n'
498 'Opening a file named `%s`' % (args,filename))
498 'Opening a file named `%s`' % (args,filename))
499 # Now, make sure we can actually read the source (if it was in
499 # Now, make sure we can actually read the source (if it was in
500 # a temp file it's gone by now).
500 # a temp file it's gone by now).
501 if datafile:
501 if datafile:
502 try:
502 try:
503 if lineno is None:
503 if lineno is None:
504 lineno = inspect.getsourcelines(data)[1]
504 lineno = inspect.getsourcelines(data)[1]
505 except IOError:
505 except IOError:
506 filename = make_filename(args)
506 filename = make_filename(args)
507 if filename is None:
507 if filename is None:
508 warn('The file `%s` where `%s` was defined cannot '
508 warn('The file `%s` where `%s` was defined cannot '
509 'be read.' % (filename,data))
509 'be read.' % (filename,data))
510 return
510 return
511 use_temp = False
511 use_temp = False
512
512
513 if use_temp:
513 if use_temp:
514 filename = self.shell.mktempfile(data)
514 filename = self.shell.mktempfile(data)
515 print('IPython will make a temporary file named:', filename)
515 print('IPython will make a temporary file named:', filename)
516
516
517 # Make sure we send to the client an absolute path, in case the working
517 # Make sure we send to the client an absolute path, in case the working
518 # directory of client and kernel don't match
518 # directory of client and kernel don't match
519 filename = os.path.abspath(filename)
519 filename = os.path.abspath(filename)
520
520
521 payload = {
521 payload = {
522 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
522 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
523 'filename' : filename,
523 'filename' : filename,
524 'line_number' : lineno
524 'line_number' : lineno
525 }
525 }
526 self.payload_manager.write_payload(payload)
526 self.payload_manager.write_payload(payload)
527
527
528 def magic_gui(self, *args, **kwargs):
528 def magic_gui(self, *args, **kwargs):
529 raise NotImplementedError(
529 raise NotImplementedError(
530 'GUI support must be enabled in command line options.')
530 'GUI support must be enabled in command line options.')
531
531
532 def magic_pylab(self, *args, **kwargs):
532 def magic_pylab(self, *args, **kwargs):
533 raise NotImplementedError(
533 raise NotImplementedError(
534 'pylab support must be enabled in command line options.')
534 'pylab support must be enabled in command line options.')
535
535
536 # A few magics that are adapted to the specifics of using pexpect and a
536 # A few magics that are adapted to the specifics of using pexpect and a
537 # remote terminal
537 # remote terminal
538
538
539 def magic_clear(self, arg_s):
539 def magic_clear(self, arg_s):
540 """Clear the terminal."""
540 """Clear the terminal."""
541 if os.name == 'posix':
541 if os.name == 'posix':
542 self.shell.system("clear")
542 self.shell.system("clear")
543 else:
543 else:
544 self.shell.system("cls")
544 self.shell.system("cls")
545
545
546 if os.name == 'nt':
546 if os.name == 'nt':
547 # This is the usual name in windows
547 # This is the usual name in windows
548 magic_cls = magic_clear
548 magic_cls = magic_clear
549
549
550 # Terminal pagers won't work over pexpect, but we do have our own pager
550 # Terminal pagers won't work over pexpect, but we do have our own pager
551
551
552 def magic_less(self, arg_s):
552 def magic_less(self, arg_s):
553 """Show a file through the pager.
553 """Show a file through the pager.
554
554
555 Files ending in .py are syntax-highlighted."""
555 Files ending in .py are syntax-highlighted."""
556 cont = open(arg_s).read()
556 cont = open(arg_s).read()
557 if arg_s.endswith('.py'):
557 if arg_s.endswith('.py'):
558 cont = self.shell.pycolorize(cont)
558 cont = self.shell.pycolorize(cont)
559 page.page(cont)
559 page.page(cont)
560
560
561 magic_more = magic_less
561 magic_more = magic_less
562
562
563 # Man calls a pager, so we also need to redefine it
563 # Man calls a pager, so we also need to redefine it
564 if os.name == 'posix':
564 if os.name == 'posix':
565 def magic_man(self, arg_s):
565 def magic_man(self, arg_s):
566 """Find the man page for the given command and display in pager."""
566 """Find the man page for the given command and display in pager."""
567 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
567 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
568 split=False))
568 split=False))
569
569
570 # FIXME: this is specific to the GUI, so we should let the gui app load
570 # FIXME: this is specific to the GUI, so we should let the gui app load
571 # magics at startup that are only for the gui. Once the gui app has proper
571 # magics at startup that are only for the gui. Once the gui app has proper
572 # profile and configuration management, we can have it initialize a kernel
572 # profile and configuration management, we can have it initialize a kernel
573 # with a special config file that provides these.
573 # with a special config file that provides these.
574 def magic_guiref(self, arg_s):
574 def magic_guiref(self, arg_s):
575 """Show a basic reference about the GUI console."""
575 """Show a basic reference about the GUI console."""
576 from IPython.core.usage import gui_reference
576 from IPython.core.usage import gui_reference
577 page.page(gui_reference, auto_html=True)
577 page.page(gui_reference, auto_html=True)
578
578
579 def magic_loadpy(self, arg_s):
579 def magic_loadpy(self, arg_s):
580 """Load a .py python script into the GUI console.
580 """Load a .py python script into the GUI console.
581
581
582 This magic command can either take a local filename or a url::
582 This magic command can either take a local filename or a url::
583
583
584 %loadpy myscript.py
584 %loadpy myscript.py
585 %loadpy http://www.example.com/myscript.py
585 %loadpy http://www.example.com/myscript.py
586 """
586 """
587 if not arg_s.endswith('.py'):
587 if not arg_s.endswith('.py'):
588 raise ValueError('%%load only works with .py files: %s' % arg_s)
588 raise ValueError('%%load only works with .py files: %s' % arg_s)
589 if arg_s.startswith('http'):
589 if arg_s.startswith('http'):
590 import urllib2
590 import urllib2
591 response = urllib2.urlopen(arg_s)
591 response = urllib2.urlopen(arg_s)
592 content = response.read()
592 content = response.read()
593 else:
593 else:
594 content = open(arg_s).read()
594 content = open(arg_s).read()
595 self.set_next_input(content)
596
597 def set_next_input(self, text):
598 """Send the specified text to the frontend to be presented at the next
599 input cell."""
595 payload = dict(
600 payload = dict(
596 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_loadpy',
601 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
597 text=content
602 text=text
598 )
603 )
599 self.payload_manager.write_payload(payload)
604 self.payload_manager.write_payload(payload)
600
605
601 InteractiveShellABC.register(ZMQInteractiveShell)
606 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now