##// END OF EJS Templates
add %autosave magic from autosave extension
MinRK -
Show More
@@ -1,591 +1,615 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 os
19 import os
20 import sys
20 import sys
21 import time
21 import time
22
22
23 # System library imports
23 # System library imports
24 from zmq.eventloop import ioloop
24 from zmq.eventloop import ioloop
25
25
26 # Our own
26 # Our own
27 from IPython.core.interactiveshell import (
27 from IPython.core.interactiveshell import (
28 InteractiveShell, InteractiveShellABC
28 InteractiveShell, InteractiveShellABC
29 )
29 )
30 from IPython.core import page
30 from IPython.core import page
31 from IPython.core.autocall import ZMQExitAutocall
31 from IPython.core.autocall import ZMQExitAutocall
32 from IPython.core.displaypub import DisplayPublisher
32 from IPython.core.displaypub import DisplayPublisher
33 from IPython.core.error import UsageError
33 from IPython.core.error import UsageError
34 from IPython.core.magics import MacroToEdit, CodeMagics
34 from IPython.core.magics import MacroToEdit, CodeMagics
35 from IPython.core.magic import magics_class, line_magic, Magics
35 from IPython.core.magic import magics_class, line_magic, Magics
36 from IPython.core.payloadpage import install_payload_page
36 from IPython.core.payloadpage import install_payload_page
37 from IPython.display import display, Javascript
37 from IPython.kernel.inprocess.socket import SocketABC
38 from IPython.kernel.inprocess.socket import SocketABC
38 from IPython.kernel import (
39 from IPython.kernel import (
39 get_connection_file, get_connection_info, connect_qtconsole
40 get_connection_file, get_connection_info, connect_qtconsole
40 )
41 )
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import io, openpy
43 from IPython.utils import io, openpy
43 from IPython.utils.jsonutil import json_clean, encode_images
44 from IPython.utils.jsonutil import json_clean, encode_images
44 from IPython.utils.process import arg_split
45 from IPython.utils.process import arg_split
45 from IPython.utils import py3compat
46 from IPython.utils import py3compat
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
47 from IPython.utils.warn import warn, error
48 from IPython.utils.warn import warn, error
48 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
49 from IPython.kernel.zmq.datapub import ZMQDataPublisher
50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
50 from IPython.kernel.zmq.session import extract_header
51 from IPython.kernel.zmq.session import extract_header
51 from session import Session
52 from session import Session
52
53
53 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
54 # Functions and classes
55 # Functions and classes
55 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
56
57
57 class ZMQDisplayPublisher(DisplayPublisher):
58 class ZMQDisplayPublisher(DisplayPublisher):
58 """A display publisher that publishes data using a ZeroMQ PUB socket."""
59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
59
60
60 session = Instance(Session)
61 session = Instance(Session)
61 pub_socket = Instance(SocketABC)
62 pub_socket = Instance(SocketABC)
62 parent_header = Dict({})
63 parent_header = Dict({})
63 topic = CBytes(b'displaypub')
64 topic = CBytes(b'displaypub')
64
65
65 def set_parent(self, parent):
66 def set_parent(self, parent):
66 """Set the parent for outbound messages."""
67 """Set the parent for outbound messages."""
67 self.parent_header = extract_header(parent)
68 self.parent_header = extract_header(parent)
68
69
69 def _flush_streams(self):
70 def _flush_streams(self):
70 """flush IO Streams prior to display"""
71 """flush IO Streams prior to display"""
71 sys.stdout.flush()
72 sys.stdout.flush()
72 sys.stderr.flush()
73 sys.stderr.flush()
73
74
74 def publish(self, source, data, metadata=None):
75 def publish(self, source, data, metadata=None):
75 self._flush_streams()
76 self._flush_streams()
76 if metadata is None:
77 if metadata is None:
77 metadata = {}
78 metadata = {}
78 self._validate_data(source, data, metadata)
79 self._validate_data(source, data, metadata)
79 content = {}
80 content = {}
80 content['source'] = source
81 content['source'] = source
81 content['data'] = encode_images(data)
82 content['data'] = encode_images(data)
82 content['metadata'] = metadata
83 content['metadata'] = metadata
83 self.session.send(
84 self.session.send(
84 self.pub_socket, u'display_data', json_clean(content),
85 self.pub_socket, u'display_data', json_clean(content),
85 parent=self.parent_header, ident=self.topic,
86 parent=self.parent_header, ident=self.topic,
86 )
87 )
87
88
88 def clear_output(self, stdout=True, stderr=True, other=True):
89 def clear_output(self, stdout=True, stderr=True, other=True):
89 content = dict(stdout=stdout, stderr=stderr, other=other)
90 content = dict(stdout=stdout, stderr=stderr, other=other)
90
91
91 if stdout:
92 if stdout:
92 print('\r', file=sys.stdout, end='')
93 print('\r', file=sys.stdout, end='')
93 if stderr:
94 if stderr:
94 print('\r', file=sys.stderr, end='')
95 print('\r', file=sys.stderr, end='')
95
96
96 self._flush_streams()
97 self._flush_streams()
97
98
98 self.session.send(
99 self.session.send(
99 self.pub_socket, u'clear_output', content,
100 self.pub_socket, u'clear_output', content,
100 parent=self.parent_header, ident=self.topic,
101 parent=self.parent_header, ident=self.topic,
101 )
102 )
102
103
103 @magics_class
104 @magics_class
104 class KernelMagics(Magics):
105 class KernelMagics(Magics):
105 #------------------------------------------------------------------------
106 #------------------------------------------------------------------------
106 # Magic overrides
107 # Magic overrides
107 #------------------------------------------------------------------------
108 #------------------------------------------------------------------------
108 # Once the base class stops inheriting from magic, this code needs to be
109 # Once the base class stops inheriting from magic, this code needs to be
109 # moved into a separate machinery as well. For now, at least isolate here
110 # moved into a separate machinery as well. For now, at least isolate here
110 # the magics which this class needs to implement differently from the base
111 # the magics which this class needs to implement differently from the base
111 # class, or that are unique to it.
112 # class, or that are unique to it.
112
113
113 @line_magic
114 @line_magic
114 def doctest_mode(self, parameter_s=''):
115 def doctest_mode(self, parameter_s=''):
115 """Toggle doctest mode on and off.
116 """Toggle doctest mode on and off.
116
117
117 This mode is intended to make IPython behave as much as possible like a
118 This mode is intended to make IPython behave as much as possible like a
118 plain Python shell, from the perspective of how its prompts, exceptions
119 plain Python shell, from the perspective of how its prompts, exceptions
119 and output look. This makes it easy to copy and paste parts of a
120 and output look. This makes it easy to copy and paste parts of a
120 session into doctests. It does so by:
121 session into doctests. It does so by:
121
122
122 - Changing the prompts to the classic ``>>>`` ones.
123 - Changing the prompts to the classic ``>>>`` ones.
123 - Changing the exception reporting mode to 'Plain'.
124 - Changing the exception reporting mode to 'Plain'.
124 - Disabling pretty-printing of output.
125 - Disabling pretty-printing of output.
125
126
126 Note that IPython also supports the pasting of code snippets that have
127 Note that IPython also supports the pasting of code snippets that have
127 leading '>>>' and '...' prompts in them. This means that you can paste
128 leading '>>>' and '...' prompts in them. This means that you can paste
128 doctests from files or docstrings (even if they have leading
129 doctests from files or docstrings (even if they have leading
129 whitespace), and the code will execute correctly. You can then use
130 whitespace), and the code will execute correctly. You can then use
130 '%history -t' to see the translated history; this will give you the
131 '%history -t' to see the translated history; this will give you the
131 input after removal of all the leading prompts and whitespace, which
132 input after removal of all the leading prompts and whitespace, which
132 can be pasted back into an editor.
133 can be pasted back into an editor.
133
134
134 With these features, you can switch into this mode easily whenever you
135 With these features, you can switch into this mode easily whenever you
135 need to do testing and changes to doctests, without having to leave
136 need to do testing and changes to doctests, without having to leave
136 your existing IPython session.
137 your existing IPython session.
137 """
138 """
138
139
139 from IPython.utils.ipstruct import Struct
140 from IPython.utils.ipstruct import Struct
140
141
141 # Shorthands
142 # Shorthands
142 shell = self.shell
143 shell = self.shell
143 disp_formatter = self.shell.display_formatter
144 disp_formatter = self.shell.display_formatter
144 ptformatter = disp_formatter.formatters['text/plain']
145 ptformatter = disp_formatter.formatters['text/plain']
145 # dstore is a data store kept in the instance metadata bag to track any
146 # dstore is a data store kept in the instance metadata bag to track any
146 # changes we make, so we can undo them later.
147 # changes we make, so we can undo them later.
147 dstore = shell.meta.setdefault('doctest_mode', Struct())
148 dstore = shell.meta.setdefault('doctest_mode', Struct())
148 save_dstore = dstore.setdefault
149 save_dstore = dstore.setdefault
149
150
150 # save a few values we'll need to recover later
151 # save a few values we'll need to recover later
151 mode = save_dstore('mode', False)
152 mode = save_dstore('mode', False)
152 save_dstore('rc_pprint', ptformatter.pprint)
153 save_dstore('rc_pprint', ptformatter.pprint)
153 save_dstore('rc_active_types',disp_formatter.active_types)
154 save_dstore('rc_active_types',disp_formatter.active_types)
154 save_dstore('xmode', shell.InteractiveTB.mode)
155 save_dstore('xmode', shell.InteractiveTB.mode)
155
156
156 if mode == False:
157 if mode == False:
157 # turn on
158 # turn on
158 ptformatter.pprint = False
159 ptformatter.pprint = False
159 disp_formatter.active_types = ['text/plain']
160 disp_formatter.active_types = ['text/plain']
160 shell.magic('xmode Plain')
161 shell.magic('xmode Plain')
161 else:
162 else:
162 # turn off
163 # turn off
163 ptformatter.pprint = dstore.rc_pprint
164 ptformatter.pprint = dstore.rc_pprint
164 disp_formatter.active_types = dstore.rc_active_types
165 disp_formatter.active_types = dstore.rc_active_types
165 shell.magic("xmode " + dstore.xmode)
166 shell.magic("xmode " + dstore.xmode)
166
167
167 # Store new mode and inform on console
168 # Store new mode and inform on console
168 dstore.mode = bool(1-int(mode))
169 dstore.mode = bool(1-int(mode))
169 mode_label = ['OFF','ON'][dstore.mode]
170 mode_label = ['OFF','ON'][dstore.mode]
170 print('Doctest mode is:', mode_label)
171 print('Doctest mode is:', mode_label)
171
172
172 # Send the payload back so that clients can modify their prompt display
173 # Send the payload back so that clients can modify their prompt display
173 payload = dict(
174 payload = dict(
174 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
175 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
175 mode=dstore.mode)
176 mode=dstore.mode)
176 shell.payload_manager.write_payload(payload)
177 shell.payload_manager.write_payload(payload)
177
178
178
179
179 _find_edit_target = CodeMagics._find_edit_target
180 _find_edit_target = CodeMagics._find_edit_target
180
181
181 @skip_doctest
182 @skip_doctest
182 @line_magic
183 @line_magic
183 def edit(self, parameter_s='', last_call=['','']):
184 def edit(self, parameter_s='', last_call=['','']):
184 """Bring up an editor and execute the resulting code.
185 """Bring up an editor and execute the resulting code.
185
186
186 Usage:
187 Usage:
187 %edit [options] [args]
188 %edit [options] [args]
188
189
189 %edit runs an external text editor. You will need to set the command for
190 %edit runs an external text editor. You will need to set the command for
190 this editor via the ``TerminalInteractiveShell.editor`` option in your
191 this editor via the ``TerminalInteractiveShell.editor`` option in your
191 configuration file before it will work.
192 configuration file before it will work.
192
193
193 This command allows you to conveniently edit multi-line code right in
194 This command allows you to conveniently edit multi-line code right in
194 your IPython session.
195 your IPython session.
195
196
196 If called without arguments, %edit opens up an empty editor with a
197 If called without arguments, %edit opens up an empty editor with a
197 temporary file and will execute the contents of this file when you
198 temporary file and will execute the contents of this file when you
198 close it (don't forget to save it!).
199 close it (don't forget to save it!).
199
200
200
201
201 Options:
202 Options:
202
203
203 -n <number>: open the editor at a specified line number. By default,
204 -n <number>: open the editor at a specified line number. By default,
204 the IPython editor hook uses the unix syntax 'editor +N filename', but
205 the IPython editor hook uses the unix syntax 'editor +N filename', but
205 you can configure this by providing your own modified hook if your
206 you can configure this by providing your own modified hook if your
206 favorite editor supports line-number specifications with a different
207 favorite editor supports line-number specifications with a different
207 syntax.
208 syntax.
208
209
209 -p: this will call the editor with the same data as the previous time
210 -p: this will call the editor with the same data as the previous time
210 it was used, regardless of how long ago (in your current session) it
211 it was used, regardless of how long ago (in your current session) it
211 was.
212 was.
212
213
213 -r: use 'raw' input. This option only applies to input taken from the
214 -r: use 'raw' input. This option only applies to input taken from the
214 user's history. By default, the 'processed' history is used, so that
215 user's history. By default, the 'processed' history is used, so that
215 magics are loaded in their transformed version to valid Python. If
216 magics are loaded in their transformed version to valid Python. If
216 this option is given, the raw input as typed as the command line is
217 this option is given, the raw input as typed as the command line is
217 used instead. When you exit the editor, it will be executed by
218 used instead. When you exit the editor, it will be executed by
218 IPython's own processor.
219 IPython's own processor.
219
220
220 -x: do not execute the edited code immediately upon exit. This is
221 -x: do not execute the edited code immediately upon exit. This is
221 mainly useful if you are editing programs which need to be called with
222 mainly useful if you are editing programs which need to be called with
222 command line arguments, which you can then do using %run.
223 command line arguments, which you can then do using %run.
223
224
224
225
225 Arguments:
226 Arguments:
226
227
227 If arguments are given, the following possibilites exist:
228 If arguments are given, the following possibilites exist:
228
229
229 - The arguments are numbers or pairs of colon-separated numbers (like
230 - The arguments are numbers or pairs of colon-separated numbers (like
230 1 4:8 9). These are interpreted as lines of previous input to be
231 1 4:8 9). These are interpreted as lines of previous input to be
231 loaded into the editor. The syntax is the same of the %macro command.
232 loaded into the editor. The syntax is the same of the %macro command.
232
233
233 - If the argument doesn't start with a number, it is evaluated as a
234 - If the argument doesn't start with a number, it is evaluated as a
234 variable and its contents loaded into the editor. You can thus edit
235 variable and its contents loaded into the editor. You can thus edit
235 any string which contains python code (including the result of
236 any string which contains python code (including the result of
236 previous edits).
237 previous edits).
237
238
238 - If the argument is the name of an object (other than a string),
239 - If the argument is the name of an object (other than a string),
239 IPython will try to locate the file where it was defined and open the
240 IPython will try to locate the file where it was defined and open the
240 editor at the point where it is defined. You can use `%edit function`
241 editor at the point where it is defined. You can use `%edit function`
241 to load an editor exactly at the point where 'function' is defined,
242 to load an editor exactly at the point where 'function' is defined,
242 edit it and have the file be executed automatically.
243 edit it and have the file be executed automatically.
243
244
244 If the object is a macro (see %macro for details), this opens up your
245 If the object is a macro (see %macro for details), this opens up your
245 specified editor with a temporary file containing the macro's data.
246 specified editor with a temporary file containing the macro's data.
246 Upon exit, the macro is reloaded with the contents of the file.
247 Upon exit, the macro is reloaded with the contents of the file.
247
248
248 Note: opening at an exact line is only supported under Unix, and some
249 Note: opening at an exact line is only supported under Unix, and some
249 editors (like kedit and gedit up to Gnome 2.8) do not understand the
250 editors (like kedit and gedit up to Gnome 2.8) do not understand the
250 '+NUMBER' parameter necessary for this feature. Good editors like
251 '+NUMBER' parameter necessary for this feature. Good editors like
251 (X)Emacs, vi, jed, pico and joe all do.
252 (X)Emacs, vi, jed, pico and joe all do.
252
253
253 - If the argument is not found as a variable, IPython will look for a
254 - If the argument is not found as a variable, IPython will look for a
254 file with that name (adding .py if necessary) and load it into the
255 file with that name (adding .py if necessary) and load it into the
255 editor. It will execute its contents with execfile() when you exit,
256 editor. It will execute its contents with execfile() when you exit,
256 loading any code in the file into your interactive namespace.
257 loading any code in the file into your interactive namespace.
257
258
258 After executing your code, %edit will return as output the code you
259 After executing your code, %edit will return as output the code you
259 typed in the editor (except when it was an existing file). This way
260 typed in the editor (except when it was an existing file). This way
260 you can reload the code in further invocations of %edit as a variable,
261 you can reload the code in further invocations of %edit as a variable,
261 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
262 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
262 the output.
263 the output.
263
264
264 Note that %edit is also available through the alias %ed.
265 Note that %edit is also available through the alias %ed.
265
266
266 This is an example of creating a simple function inside the editor and
267 This is an example of creating a simple function inside the editor and
267 then modifying it. First, start up the editor:
268 then modifying it. First, start up the editor:
268
269
269 In [1]: ed
270 In [1]: ed
270 Editing... done. Executing edited code...
271 Editing... done. Executing edited code...
271 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
272 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
272
273
273 We can then call the function foo():
274 We can then call the function foo():
274
275
275 In [2]: foo()
276 In [2]: foo()
276 foo() was defined in an editing session
277 foo() was defined in an editing session
277
278
278 Now we edit foo. IPython automatically loads the editor with the
279 Now we edit foo. IPython automatically loads the editor with the
279 (temporary) file where foo() was previously defined:
280 (temporary) file where foo() was previously defined:
280
281
281 In [3]: ed foo
282 In [3]: ed foo
282 Editing... done. Executing edited code...
283 Editing... done. Executing edited code...
283
284
284 And if we call foo() again we get the modified version:
285 And if we call foo() again we get the modified version:
285
286
286 In [4]: foo()
287 In [4]: foo()
287 foo() has now been changed!
288 foo() has now been changed!
288
289
289 Here is an example of how to edit a code snippet successive
290 Here is an example of how to edit a code snippet successive
290 times. First we call the editor:
291 times. First we call the editor:
291
292
292 In [5]: ed
293 In [5]: ed
293 Editing... done. Executing edited code...
294 Editing... done. Executing edited code...
294 hello
295 hello
295 Out[5]: "print 'hello'n"
296 Out[5]: "print 'hello'n"
296
297
297 Now we call it again with the previous output (stored in _):
298 Now we call it again with the previous output (stored in _):
298
299
299 In [6]: ed _
300 In [6]: ed _
300 Editing... done. Executing edited code...
301 Editing... done. Executing edited code...
301 hello world
302 hello world
302 Out[6]: "print 'hello world'n"
303 Out[6]: "print 'hello world'n"
303
304
304 Now we call it with the output #8 (stored in _8, also as Out[8]):
305 Now we call it with the output #8 (stored in _8, also as Out[8]):
305
306
306 In [7]: ed _8
307 In [7]: ed _8
307 Editing... done. Executing edited code...
308 Editing... done. Executing edited code...
308 hello again
309 hello again
309 Out[7]: "print 'hello again'n"
310 Out[7]: "print 'hello again'n"
310 """
311 """
311
312
312 opts,args = self.parse_options(parameter_s,'prn:')
313 opts,args = self.parse_options(parameter_s,'prn:')
313
314
314 try:
315 try:
315 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
316 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
316 except MacroToEdit as e:
317 except MacroToEdit as e:
317 # TODO: Implement macro editing over 2 processes.
318 # TODO: Implement macro editing over 2 processes.
318 print("Macro editing not yet implemented in 2-process model.")
319 print("Macro editing not yet implemented in 2-process model.")
319 return
320 return
320
321
321 # Make sure we send to the client an absolute path, in case the working
322 # Make sure we send to the client an absolute path, in case the working
322 # directory of client and kernel don't match
323 # directory of client and kernel don't match
323 filename = os.path.abspath(filename)
324 filename = os.path.abspath(filename)
324
325
325 payload = {
326 payload = {
326 'source' : 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
327 'source' : 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
327 'filename' : filename,
328 'filename' : filename,
328 'line_number' : lineno
329 'line_number' : lineno
329 }
330 }
330 self.shell.payload_manager.write_payload(payload)
331 self.shell.payload_manager.write_payload(payload)
331
332
332 # A few magics that are adapted to the specifics of using pexpect and a
333 # A few magics that are adapted to the specifics of using pexpect and a
333 # remote terminal
334 # remote terminal
334
335
335 @line_magic
336 @line_magic
336 def clear(self, arg_s):
337 def clear(self, arg_s):
337 """Clear the terminal."""
338 """Clear the terminal."""
338 if os.name == 'posix':
339 if os.name == 'posix':
339 self.shell.system("clear")
340 self.shell.system("clear")
340 else:
341 else:
341 self.shell.system("cls")
342 self.shell.system("cls")
342
343
343 if os.name == 'nt':
344 if os.name == 'nt':
344 # This is the usual name in windows
345 # This is the usual name in windows
345 cls = line_magic('cls')(clear)
346 cls = line_magic('cls')(clear)
346
347
347 # Terminal pagers won't work over pexpect, but we do have our own pager
348 # Terminal pagers won't work over pexpect, but we do have our own pager
348
349
349 @line_magic
350 @line_magic
350 def less(self, arg_s):
351 def less(self, arg_s):
351 """Show a file through the pager.
352 """Show a file through the pager.
352
353
353 Files ending in .py are syntax-highlighted."""
354 Files ending in .py are syntax-highlighted."""
354 if not arg_s:
355 if not arg_s:
355 raise UsageError('Missing filename.')
356 raise UsageError('Missing filename.')
356
357
357 cont = open(arg_s).read()
358 cont = open(arg_s).read()
358 if arg_s.endswith('.py'):
359 if arg_s.endswith('.py'):
359 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
360 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
360 else:
361 else:
361 cont = open(arg_s).read()
362 cont = open(arg_s).read()
362 page.page(cont)
363 page.page(cont)
363
364
364 more = line_magic('more')(less)
365 more = line_magic('more')(less)
365
366
366 # Man calls a pager, so we also need to redefine it
367 # Man calls a pager, so we also need to redefine it
367 if os.name == 'posix':
368 if os.name == 'posix':
368 @line_magic
369 @line_magic
369 def man(self, arg_s):
370 def man(self, arg_s):
370 """Find the man page for the given command and display in pager."""
371 """Find the man page for the given command and display in pager."""
371 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
372 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
372 split=False))
373 split=False))
373
374
374 @line_magic
375 @line_magic
375 def connect_info(self, arg_s):
376 def connect_info(self, arg_s):
376 """Print information for connecting other clients to this kernel
377 """Print information for connecting other clients to this kernel
377
378
378 It will print the contents of this session's connection file, as well as
379 It will print the contents of this session's connection file, as well as
379 shortcuts for local clients.
380 shortcuts for local clients.
380
381
381 In the simplest case, when called from the most recently launched kernel,
382 In the simplest case, when called from the most recently launched kernel,
382 secondary clients can be connected, simply with:
383 secondary clients can be connected, simply with:
383
384
384 $> ipython <app> --existing
385 $> ipython <app> --existing
385
386
386 """
387 """
387
388
388 from IPython.core.application import BaseIPythonApplication as BaseIPApp
389 from IPython.core.application import BaseIPythonApplication as BaseIPApp
389
390
390 if BaseIPApp.initialized():
391 if BaseIPApp.initialized():
391 app = BaseIPApp.instance()
392 app = BaseIPApp.instance()
392 security_dir = app.profile_dir.security_dir
393 security_dir = app.profile_dir.security_dir
393 profile = app.profile
394 profile = app.profile
394 else:
395 else:
395 profile = 'default'
396 profile = 'default'
396 security_dir = ''
397 security_dir = ''
397
398
398 try:
399 try:
399 connection_file = get_connection_file()
400 connection_file = get_connection_file()
400 info = get_connection_info(unpack=False)
401 info = get_connection_info(unpack=False)
401 except Exception as e:
402 except Exception as e:
402 error("Could not get connection info: %r" % e)
403 error("Could not get connection info: %r" % e)
403 return
404 return
404
405
405 # add profile flag for non-default profile
406 # add profile flag for non-default profile
406 profile_flag = "--profile %s" % profile if profile != 'default' else ""
407 profile_flag = "--profile %s" % profile if profile != 'default' else ""
407
408
408 # if it's in the security dir, truncate to basename
409 # if it's in the security dir, truncate to basename
409 if security_dir == os.path.dirname(connection_file):
410 if security_dir == os.path.dirname(connection_file):
410 connection_file = os.path.basename(connection_file)
411 connection_file = os.path.basename(connection_file)
411
412
412
413
413 print (info + '\n')
414 print (info + '\n')
414 print ("Paste the above JSON into a file, and connect with:\n"
415 print ("Paste the above JSON into a file, and connect with:\n"
415 " $> ipython <app> --existing <file>\n"
416 " $> ipython <app> --existing <file>\n"
416 "or, if you are local, you can connect with just:\n"
417 "or, if you are local, you can connect with just:\n"
417 " $> ipython <app> --existing {0} {1}\n"
418 " $> ipython <app> --existing {0} {1}\n"
418 "or even just:\n"
419 "or even just:\n"
419 " $> ipython <app> --existing {1}\n"
420 " $> ipython <app> --existing {1}\n"
420 "if this is the most recent IPython session you have started.".format(
421 "if this is the most recent IPython session you have started.".format(
421 connection_file, profile_flag
422 connection_file, profile_flag
422 )
423 )
423 )
424 )
424
425
425 @line_magic
426 @line_magic
426 def qtconsole(self, arg_s):
427 def qtconsole(self, arg_s):
427 """Open a qtconsole connected to this kernel.
428 """Open a qtconsole connected to this kernel.
428
429
429 Useful for connecting a qtconsole to running notebooks, for better
430 Useful for connecting a qtconsole to running notebooks, for better
430 debugging.
431 debugging.
431 """
432 """
432
433
433 # %qtconsole should imply bind_kernel for engines:
434 # %qtconsole should imply bind_kernel for engines:
434 try:
435 try:
435 from IPython.parallel import bind_kernel
436 from IPython.parallel import bind_kernel
436 except ImportError:
437 except ImportError:
437 # technically possible, because parallel has higher pyzmq min-version
438 # technically possible, because parallel has higher pyzmq min-version
438 pass
439 pass
439 else:
440 else:
440 bind_kernel()
441 bind_kernel()
441
442
442 try:
443 try:
443 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
444 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
444 except Exception as e:
445 except Exception as e:
445 error("Could not start qtconsole: %r" % e)
446 error("Could not start qtconsole: %r" % e)
446 return
447 return
448
449 @line_magic
450 def autosave(self, arg_s):
451 """Set the lower-limit for the autosave frequency in the notebook (in seconds).
452
453 The default value is 120, or two minutes.
454 ``%autosave 0`` will disable autosave.
455 """
456
457 try:
458 interval = int(arg_s)
459 except ValueError:
460 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
461
462 # javascript wants milliseconds
463 milliseconds = 1000 * interval
464 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
465 include=['application/javascript']
466 )
467 if interval:
468 print("Autosaving every %i seconds" % interval)
469 else:
470 print("Autosave disabled")
447
471
448 def safe_unicode(e):
472 def safe_unicode(e):
449 """unicode(e) with various fallbacks. Used for exceptions, which may not be
473 """unicode(e) with various fallbacks. Used for exceptions, which may not be
450 safe to call unicode() on.
474 safe to call unicode() on.
451 """
475 """
452 try:
476 try:
453 return unicode(e)
477 return unicode(e)
454 except UnicodeError:
478 except UnicodeError:
455 pass
479 pass
456
480
457 try:
481 try:
458 return py3compat.str_to_unicode(str(e))
482 return py3compat.str_to_unicode(str(e))
459 except UnicodeError:
483 except UnicodeError:
460 pass
484 pass
461
485
462 try:
486 try:
463 return py3compat.str_to_unicode(repr(e))
487 return py3compat.str_to_unicode(repr(e))
464 except UnicodeError:
488 except UnicodeError:
465 pass
489 pass
466
490
467 return u'Unrecoverably corrupt evalue'
491 return u'Unrecoverably corrupt evalue'
468
492
469
493
470 class ZMQInteractiveShell(InteractiveShell):
494 class ZMQInteractiveShell(InteractiveShell):
471 """A subclass of InteractiveShell for ZMQ."""
495 """A subclass of InteractiveShell for ZMQ."""
472
496
473 displayhook_class = Type(ZMQShellDisplayHook)
497 displayhook_class = Type(ZMQShellDisplayHook)
474 display_pub_class = Type(ZMQDisplayPublisher)
498 display_pub_class = Type(ZMQDisplayPublisher)
475 data_pub_class = Type(ZMQDataPublisher)
499 data_pub_class = Type(ZMQDataPublisher)
476
500
477 # Override the traitlet in the parent class, because there's no point using
501 # Override the traitlet in the parent class, because there's no point using
478 # readline for the kernel. Can be removed when the readline code is moved
502 # readline for the kernel. Can be removed when the readline code is moved
479 # to the terminal frontend.
503 # to the terminal frontend.
480 colors_force = CBool(True)
504 colors_force = CBool(True)
481 readline_use = CBool(False)
505 readline_use = CBool(False)
482 # autoindent has no meaning in a zmqshell, and attempting to enable it
506 # autoindent has no meaning in a zmqshell, and attempting to enable it
483 # will print a warning in the absence of readline.
507 # will print a warning in the absence of readline.
484 autoindent = CBool(False)
508 autoindent = CBool(False)
485
509
486 exiter = Instance(ZMQExitAutocall)
510 exiter = Instance(ZMQExitAutocall)
487 def _exiter_default(self):
511 def _exiter_default(self):
488 return ZMQExitAutocall(self)
512 return ZMQExitAutocall(self)
489
513
490 def _exit_now_changed(self, name, old, new):
514 def _exit_now_changed(self, name, old, new):
491 """stop eventloop when exit_now fires"""
515 """stop eventloop when exit_now fires"""
492 if new:
516 if new:
493 loop = ioloop.IOLoop.instance()
517 loop = ioloop.IOLoop.instance()
494 loop.add_timeout(time.time()+0.1, loop.stop)
518 loop.add_timeout(time.time()+0.1, loop.stop)
495
519
496 keepkernel_on_exit = None
520 keepkernel_on_exit = None
497
521
498 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
522 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
499 # interactive input being read; we provide event loop support in ipkernel
523 # interactive input being read; we provide event loop support in ipkernel
500 from .eventloops import enable_gui
524 from .eventloops import enable_gui
501 enable_gui = staticmethod(enable_gui)
525 enable_gui = staticmethod(enable_gui)
502
526
503 def init_environment(self):
527 def init_environment(self):
504 """Configure the user's environment.
528 """Configure the user's environment.
505
529
506 """
530 """
507 env = os.environ
531 env = os.environ
508 # These two ensure 'ls' produces nice coloring on BSD-derived systems
532 # These two ensure 'ls' produces nice coloring on BSD-derived systems
509 env['TERM'] = 'xterm-color'
533 env['TERM'] = 'xterm-color'
510 env['CLICOLOR'] = '1'
534 env['CLICOLOR'] = '1'
511 # Since normal pagers don't work at all (over pexpect we don't have
535 # Since normal pagers don't work at all (over pexpect we don't have
512 # single-key control of the subprocess), try to disable paging in
536 # single-key control of the subprocess), try to disable paging in
513 # subprocesses as much as possible.
537 # subprocesses as much as possible.
514 env['PAGER'] = 'cat'
538 env['PAGER'] = 'cat'
515 env['GIT_PAGER'] = 'cat'
539 env['GIT_PAGER'] = 'cat'
516
540
517 # And install the payload version of page.
541 # And install the payload version of page.
518 install_payload_page()
542 install_payload_page()
519
543
520 def auto_rewrite_input(self, cmd):
544 def auto_rewrite_input(self, cmd):
521 """Called to show the auto-rewritten input for autocall and friends.
545 """Called to show the auto-rewritten input for autocall and friends.
522
546
523 FIXME: this payload is currently not correctly processed by the
547 FIXME: this payload is currently not correctly processed by the
524 frontend.
548 frontend.
525 """
549 """
526 new = self.prompt_manager.render('rewrite') + cmd
550 new = self.prompt_manager.render('rewrite') + cmd
527 payload = dict(
551 payload = dict(
528 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
552 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
529 transformed_input=new,
553 transformed_input=new,
530 )
554 )
531 self.payload_manager.write_payload(payload)
555 self.payload_manager.write_payload(payload)
532
556
533 def ask_exit(self):
557 def ask_exit(self):
534 """Engage the exit actions."""
558 """Engage the exit actions."""
535 self.exit_now = True
559 self.exit_now = True
536 payload = dict(
560 payload = dict(
537 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
561 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
538 exit=True,
562 exit=True,
539 keepkernel=self.keepkernel_on_exit,
563 keepkernel=self.keepkernel_on_exit,
540 )
564 )
541 self.payload_manager.write_payload(payload)
565 self.payload_manager.write_payload(payload)
542
566
543 def _showtraceback(self, etype, evalue, stb):
567 def _showtraceback(self, etype, evalue, stb):
544
568
545 exc_content = {
569 exc_content = {
546 u'traceback' : stb,
570 u'traceback' : stb,
547 u'ename' : unicode(etype.__name__),
571 u'ename' : unicode(etype.__name__),
548 u'evalue' : safe_unicode(evalue)
572 u'evalue' : safe_unicode(evalue)
549 }
573 }
550
574
551 dh = self.displayhook
575 dh = self.displayhook
552 # Send exception info over pub socket for other clients than the caller
576 # Send exception info over pub socket for other clients than the caller
553 # to pick up
577 # to pick up
554 topic = None
578 topic = None
555 if dh.topic:
579 if dh.topic:
556 topic = dh.topic.replace(b'pyout', b'pyerr')
580 topic = dh.topic.replace(b'pyout', b'pyerr')
557
581
558 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
582 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
559
583
560 # FIXME - Hack: store exception info in shell object. Right now, the
584 # FIXME - Hack: store exception info in shell object. Right now, the
561 # caller is reading this info after the fact, we need to fix this logic
585 # caller is reading this info after the fact, we need to fix this logic
562 # to remove this hack. Even uglier, we need to store the error status
586 # to remove this hack. Even uglier, we need to store the error status
563 # here, because in the main loop, the logic that sets it is being
587 # here, because in the main loop, the logic that sets it is being
564 # skipped because runlines swallows the exceptions.
588 # skipped because runlines swallows the exceptions.
565 exc_content[u'status'] = u'error'
589 exc_content[u'status'] = u'error'
566 self._reply_content = exc_content
590 self._reply_content = exc_content
567 # /FIXME
591 # /FIXME
568
592
569 return exc_content
593 return exc_content
570
594
571 def set_next_input(self, text):
595 def set_next_input(self, text):
572 """Send the specified text to the frontend to be presented at the next
596 """Send the specified text to the frontend to be presented at the next
573 input cell."""
597 input cell."""
574 payload = dict(
598 payload = dict(
575 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
599 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
576 text=text
600 text=text
577 )
601 )
578 self.payload_manager.write_payload(payload)
602 self.payload_manager.write_payload(payload)
579
603
580 #-------------------------------------------------------------------------
604 #-------------------------------------------------------------------------
581 # Things related to magics
605 # Things related to magics
582 #-------------------------------------------------------------------------
606 #-------------------------------------------------------------------------
583
607
584 def init_magics(self):
608 def init_magics(self):
585 super(ZMQInteractiveShell, self).init_magics()
609 super(ZMQInteractiveShell, self).init_magics()
586 self.register_magics(KernelMagics)
610 self.register_magics(KernelMagics)
587 self.magics_manager.register_alias('ed', 'edit')
611 self.magics_manager.register_alias('ed', 'edit')
588
612
589
613
590
614
591 InteractiveShellABC.register(ZMQInteractiveShell)
615 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now