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