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