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