##// END OF EJS Templates
fix topic on displayhook in ZMQShell
MinRK -
Show More
@@ -1,72 +1,73 b''
1 import __builtin__
1 import __builtin__
2 import sys
2 import sys
3 from base64 import encodestring
3 from base64 import encodestring
4
4
5 from IPython.core.displayhook import DisplayHook
5 from IPython.core.displayhook import DisplayHook
6 from IPython.utils.traitlets import Instance, Dict
6 from IPython.utils.traitlets import Instance, Dict
7 from session import extract_header, Session
7 from session import extract_header, Session
8
8
9 class ZMQDisplayHook(object):
9 class ZMQDisplayHook(object):
10 """A simple displayhook that publishes the object's repr over a ZeroMQ
10 """A simple displayhook that publishes the object's repr over a ZeroMQ
11 socket."""
11 socket."""
12 topic=None
12 topic=None
13
13
14 def __init__(self, session, pub_socket):
14 def __init__(self, session, pub_socket):
15 self.session = session
15 self.session = session
16 self.pub_socket = pub_socket
16 self.pub_socket = pub_socket
17 self.parent_header = {}
17 self.parent_header = {}
18
18
19 def __call__(self, obj):
19 def __call__(self, obj):
20 if obj is None:
20 if obj is None:
21 return
21 return
22
22
23 __builtin__._ = obj
23 __builtin__._ = obj
24 sys.stdout.flush()
24 sys.stdout.flush()
25 sys.stderr.flush()
25 sys.stderr.flush()
26 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
26 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
27 parent=self.parent_header, ident=self.topic)
27 parent=self.parent_header, ident=self.topic)
28
28
29 def set_parent(self, parent):
29 def set_parent(self, parent):
30 self.parent_header = extract_header(parent)
30 self.parent_header = extract_header(parent)
31
31
32
32
33 def _encode_binary(format_dict):
33 def _encode_binary(format_dict):
34 pngdata = format_dict.get('image/png')
34 pngdata = format_dict.get('image/png')
35 if pngdata is not None:
35 if pngdata is not None:
36 format_dict['image/png'] = encodestring(pngdata).decode('ascii')
36 format_dict['image/png'] = encodestring(pngdata).decode('ascii')
37 jpegdata = format_dict.get('image/jpeg')
37 jpegdata = format_dict.get('image/jpeg')
38 if jpegdata is not None:
38 if jpegdata is not None:
39 format_dict['image/jpeg'] = encodestring(jpegdata).decode('ascii')
39 format_dict['image/jpeg'] = encodestring(jpegdata).decode('ascii')
40
40
41
41
42 class ZMQShellDisplayHook(DisplayHook):
42 class ZMQShellDisplayHook(DisplayHook):
43 """A displayhook subclass that publishes data using ZeroMQ. This is intended
43 """A displayhook subclass that publishes data using ZeroMQ. This is intended
44 to work with an InteractiveShell instance. It sends a dict of different
44 to work with an InteractiveShell instance. It sends a dict of different
45 representations of the object."""
45 representations of the object."""
46 topic=None
46
47
47 session = Instance(Session)
48 session = Instance(Session)
48 pub_socket = Instance('zmq.Socket')
49 pub_socket = Instance('zmq.Socket')
49 parent_header = Dict({})
50 parent_header = Dict({})
50
51
51 def set_parent(self, parent):
52 def set_parent(self, parent):
52 """Set the parent for outbound messages."""
53 """Set the parent for outbound messages."""
53 self.parent_header = extract_header(parent)
54 self.parent_header = extract_header(parent)
54
55
55 def start_displayhook(self):
56 def start_displayhook(self):
56 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
57 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
57
58
58 def write_output_prompt(self):
59 def write_output_prompt(self):
59 """Write the output prompt."""
60 """Write the output prompt."""
60 self.msg['content']['execution_count'] = self.prompt_count
61 self.msg['content']['execution_count'] = self.prompt_count
61
62
62 def write_format_data(self, format_dict):
63 def write_format_data(self, format_dict):
63 _encode_binary(format_dict)
64 _encode_binary(format_dict)
64 self.msg['content']['data'] = format_dict
65 self.msg['content']['data'] = format_dict
65
66
66 def finish_displayhook(self):
67 def finish_displayhook(self):
67 """Finish up all displayhook activities."""
68 """Finish up all displayhook activities."""
68 sys.stdout.flush()
69 sys.stdout.flush()
69 sys.stderr.flush()
70 sys.stderr.flush()
70 self.session.send(self.pub_socket, self.msg)
71 self.session.send(self.pub_socket, self.msg, ident=self.topic)
71 self.msg = None
72 self.msg = None
72
73
@@ -1,897 +1,898 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
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 # Standard library imports
18 # Standard library imports
19 import __builtin__
19 import __builtin__
20 import atexit
20 import atexit
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24 import logging
24 import logging
25 import uuid
25 import uuid
26
26
27 from datetime import datetime
27 from datetime import datetime
28 from signal import (
28 from signal import (
29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
30 )
30 )
31
31
32 # System library imports
32 # System library imports
33 import zmq
33 import zmq
34 from zmq.eventloop import ioloop
34 from zmq.eventloop import ioloop
35 from zmq.eventloop.zmqstream import ZMQStream
35 from zmq.eventloop.zmqstream import ZMQStream
36
36
37 # Local imports
37 # Local imports
38 from IPython.core import pylabtools
38 from IPython.core import pylabtools
39 from IPython.config.configurable import Configurable
39 from IPython.config.configurable import Configurable
40 from IPython.config.application import boolean_flag, catch_config_error
40 from IPython.config.application import boolean_flag, catch_config_error
41 from IPython.core.application import ProfileDir
41 from IPython.core.application import ProfileDir
42 from IPython.core.error import StdinNotImplementedError
42 from IPython.core.error import StdinNotImplementedError
43 from IPython.core.shellapp import (
43 from IPython.core.shellapp import (
44 InteractiveShellApp, shell_flags, shell_aliases
44 InteractiveShellApp, shell_flags, shell_aliases
45 )
45 )
46 from IPython.utils import io
46 from IPython.utils import io
47 from IPython.utils import py3compat
47 from IPython.utils import py3compat
48 from IPython.utils.frame import extract_module_locals
48 from IPython.utils.frame import extract_module_locals
49 from IPython.utils.jsonutil import json_clean
49 from IPython.utils.jsonutil import json_clean
50 from IPython.utils.traitlets import (
50 from IPython.utils.traitlets import (
51 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
51 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
52 )
52 )
53
53
54 from entry_point import base_launch_kernel
54 from entry_point import base_launch_kernel
55 from kernelapp import KernelApp, kernel_flags, kernel_aliases
55 from kernelapp import KernelApp, kernel_flags, kernel_aliases
56 from serialize import serialize_object, unpack_apply_message
56 from serialize import serialize_object, unpack_apply_message
57 from session import Session, Message
57 from session import Session, Message
58 from zmqshell import ZMQInteractiveShell
58 from zmqshell import ZMQInteractiveShell
59
59
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Main kernel class
62 # Main kernel class
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 class Kernel(Configurable):
65 class Kernel(Configurable):
66
66
67 #---------------------------------------------------------------------------
67 #---------------------------------------------------------------------------
68 # Kernel interface
68 # Kernel interface
69 #---------------------------------------------------------------------------
69 #---------------------------------------------------------------------------
70
70
71 # attribute to override with a GUI
71 # attribute to override with a GUI
72 eventloop = Any(None)
72 eventloop = Any(None)
73 def _eventloop_changed(self, name, old, new):
73 def _eventloop_changed(self, name, old, new):
74 """schedule call to eventloop from IOLoop"""
74 """schedule call to eventloop from IOLoop"""
75 loop = ioloop.IOLoop.instance()
75 loop = ioloop.IOLoop.instance()
76 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
76 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
77
77
78 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
78 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
79 session = Instance(Session)
79 session = Instance(Session)
80 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
80 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
81 shell_streams = List()
81 shell_streams = List()
82 control_stream = Instance(ZMQStream)
82 control_stream = Instance(ZMQStream)
83 iopub_socket = Instance(zmq.Socket)
83 iopub_socket = Instance(zmq.Socket)
84 stdin_socket = Instance(zmq.Socket)
84 stdin_socket = Instance(zmq.Socket)
85 log = Instance(logging.Logger)
85 log = Instance(logging.Logger)
86
86
87 user_module = Instance('types.ModuleType')
87 user_module = Instance('types.ModuleType')
88 def _user_module_changed(self, name, old, new):
88 def _user_module_changed(self, name, old, new):
89 if self.shell is not None:
89 if self.shell is not None:
90 self.shell.user_module = new
90 self.shell.user_module = new
91
91
92 user_ns = Dict(default_value=None)
92 user_ns = Dict(default_value=None)
93 def _user_ns_changed(self, name, old, new):
93 def _user_ns_changed(self, name, old, new):
94 if self.shell is not None:
94 if self.shell is not None:
95 self.shell.user_ns = new
95 self.shell.user_ns = new
96 self.shell.init_user_ns()
96 self.shell.init_user_ns()
97
97
98 # identities:
98 # identities:
99 int_id = Integer(-1)
99 int_id = Integer(-1)
100 ident = Unicode()
100 ident = Unicode()
101
101
102 def _ident_default(self):
102 def _ident_default(self):
103 return unicode(uuid.uuid4())
103 return unicode(uuid.uuid4())
104
104
105
105
106 # Private interface
106 # Private interface
107
107
108 # Time to sleep after flushing the stdout/err buffers in each execute
108 # Time to sleep after flushing the stdout/err buffers in each execute
109 # cycle. While this introduces a hard limit on the minimal latency of the
109 # cycle. While this introduces a hard limit on the minimal latency of the
110 # execute cycle, it helps prevent output synchronization problems for
110 # execute cycle, it helps prevent output synchronization problems for
111 # clients.
111 # clients.
112 # Units are in seconds. The minimum zmq latency on local host is probably
112 # Units are in seconds. The minimum zmq latency on local host is probably
113 # ~150 microseconds, set this to 500us for now. We may need to increase it
113 # ~150 microseconds, set this to 500us for now. We may need to increase it
114 # a little if it's not enough after more interactive testing.
114 # a little if it's not enough after more interactive testing.
115 _execute_sleep = Float(0.0005, config=True)
115 _execute_sleep = Float(0.0005, config=True)
116
116
117 # Frequency of the kernel's event loop.
117 # Frequency of the kernel's event loop.
118 # Units are in seconds, kernel subclasses for GUI toolkits may need to
118 # Units are in seconds, kernel subclasses for GUI toolkits may need to
119 # adapt to milliseconds.
119 # adapt to milliseconds.
120 _poll_interval = Float(0.05, config=True)
120 _poll_interval = Float(0.05, config=True)
121
121
122 # If the shutdown was requested over the network, we leave here the
122 # If the shutdown was requested over the network, we leave here the
123 # necessary reply message so it can be sent by our registered atexit
123 # necessary reply message so it can be sent by our registered atexit
124 # handler. This ensures that the reply is only sent to clients truly at
124 # handler. This ensures that the reply is only sent to clients truly at
125 # the end of our shutdown process (which happens after the underlying
125 # the end of our shutdown process (which happens after the underlying
126 # IPython shell's own shutdown).
126 # IPython shell's own shutdown).
127 _shutdown_message = None
127 _shutdown_message = None
128
128
129 # This is a dict of port number that the kernel is listening on. It is set
129 # This is a dict of port number that the kernel is listening on. It is set
130 # by record_ports and used by connect_request.
130 # by record_ports and used by connect_request.
131 _recorded_ports = Dict()
131 _recorded_ports = Dict()
132
132
133 # set of aborted msg_ids
133 # set of aborted msg_ids
134 aborted = Set()
134 aborted = Set()
135
135
136
136
137 def __init__(self, **kwargs):
137 def __init__(self, **kwargs):
138 super(Kernel, self).__init__(**kwargs)
138 super(Kernel, self).__init__(**kwargs)
139
139
140 # Initialize the InteractiveShell subclass
140 # Initialize the InteractiveShell subclass
141 self.shell = ZMQInteractiveShell.instance(config=self.config,
141 self.shell = ZMQInteractiveShell.instance(config=self.config,
142 profile_dir = self.profile_dir,
142 profile_dir = self.profile_dir,
143 user_module = self.user_module,
143 user_module = self.user_module,
144 user_ns = self.user_ns,
144 user_ns = self.user_ns,
145 )
145 )
146 self.shell.displayhook.session = self.session
146 self.shell.displayhook.session = self.session
147 self.shell.displayhook.pub_socket = self.iopub_socket
147 self.shell.displayhook.pub_socket = self.iopub_socket
148 self.shell.displayhook.topic = self._topic('pyout')
148 self.shell.display_pub.session = self.session
149 self.shell.display_pub.session = self.session
149 self.shell.display_pub.pub_socket = self.iopub_socket
150 self.shell.display_pub.pub_socket = self.iopub_socket
150
151
151 # TMP - hack while developing
152 # TMP - hack while developing
152 self.shell._reply_content = None
153 self.shell._reply_content = None
153
154
154 # Build dict of handlers for message types
155 # Build dict of handlers for message types
155 msg_types = [ 'execute_request', 'complete_request',
156 msg_types = [ 'execute_request', 'complete_request',
156 'object_info_request', 'history_request',
157 'object_info_request', 'history_request',
157 'connect_request', 'shutdown_request',
158 'connect_request', 'shutdown_request',
158 'apply_request',
159 'apply_request',
159 ]
160 ]
160 self.shell_handlers = {}
161 self.shell_handlers = {}
161 for msg_type in msg_types:
162 for msg_type in msg_types:
162 self.shell_handlers[msg_type] = getattr(self, msg_type)
163 self.shell_handlers[msg_type] = getattr(self, msg_type)
163
164
164 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
165 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
165 self.control_handlers = {}
166 self.control_handlers = {}
166 for msg_type in control_msg_types:
167 for msg_type in control_msg_types:
167 self.control_handlers[msg_type] = getattr(self, msg_type)
168 self.control_handlers[msg_type] = getattr(self, msg_type)
168
169
169 def dispatch_control(self, msg):
170 def dispatch_control(self, msg):
170 """dispatch control requests"""
171 """dispatch control requests"""
171 idents,msg = self.session.feed_identities(msg, copy=False)
172 idents,msg = self.session.feed_identities(msg, copy=False)
172 try:
173 try:
173 msg = self.session.unserialize(msg, content=True, copy=False)
174 msg = self.session.unserialize(msg, content=True, copy=False)
174 except:
175 except:
175 self.log.error("Invalid Control Message", exc_info=True)
176 self.log.error("Invalid Control Message", exc_info=True)
176 return
177 return
177
178
178 self.log.debug("Control received: %s", msg)
179 self.log.debug("Control received: %s", msg)
179
180
180 header = msg['header']
181 header = msg['header']
181 msg_id = header['msg_id']
182 msg_id = header['msg_id']
182 msg_type = header['msg_type']
183 msg_type = header['msg_type']
183
184
184 handler = self.control_handlers.get(msg_type, None)
185 handler = self.control_handlers.get(msg_type, None)
185 if handler is None:
186 if handler is None:
186 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
187 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
187 else:
188 else:
188 try:
189 try:
189 handler(self.control_stream, idents, msg)
190 handler(self.control_stream, idents, msg)
190 except Exception:
191 except Exception:
191 self.log.error("Exception in control handler:", exc_info=True)
192 self.log.error("Exception in control handler:", exc_info=True)
192
193
193 def dispatch_shell(self, stream, msg):
194 def dispatch_shell(self, stream, msg):
194 """dispatch shell requests"""
195 """dispatch shell requests"""
195 # flush control requests first
196 # flush control requests first
196 if self.control_stream:
197 if self.control_stream:
197 self.control_stream.flush()
198 self.control_stream.flush()
198
199
199 idents,msg = self.session.feed_identities(msg, copy=False)
200 idents,msg = self.session.feed_identities(msg, copy=False)
200 try:
201 try:
201 msg = self.session.unserialize(msg, content=True, copy=False)
202 msg = self.session.unserialize(msg, content=True, copy=False)
202 except:
203 except:
203 self.log.error("Invalid Message", exc_info=True)
204 self.log.error("Invalid Message", exc_info=True)
204 return
205 return
205
206
206 header = msg['header']
207 header = msg['header']
207 msg_id = header['msg_id']
208 msg_id = header['msg_id']
208 msg_type = msg['header']['msg_type']
209 msg_type = msg['header']['msg_type']
209
210
210 # Print some info about this message and leave a '--->' marker, so it's
211 # Print some info about this message and leave a '--->' marker, so it's
211 # easier to trace visually the message chain when debugging. Each
212 # easier to trace visually the message chain when debugging. Each
212 # handler prints its message at the end.
213 # handler prints its message at the end.
213 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
214 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
214 self.log.debug(' Content: %s\n --->\n ', msg['content'])
215 self.log.debug(' Content: %s\n --->\n ', msg['content'])
215
216
216 if msg_id in self.aborted:
217 if msg_id in self.aborted:
217 self.aborted.remove(msg_id)
218 self.aborted.remove(msg_id)
218 # is it safe to assume a msg_id will not be resubmitted?
219 # is it safe to assume a msg_id will not be resubmitted?
219 reply_type = msg_type.split('_')[0] + '_reply'
220 reply_type = msg_type.split('_')[0] + '_reply'
220 status = {'status' : 'aborted'}
221 status = {'status' : 'aborted'}
221 sub = {'engine' : self.ident}
222 sub = {'engine' : self.ident}
222 sub.update(status)
223 sub.update(status)
223 reply_msg = self.session.send(stream, reply_type, subheader=sub,
224 reply_msg = self.session.send(stream, reply_type, subheader=sub,
224 content=status, parent=msg, ident=idents)
225 content=status, parent=msg, ident=idents)
225 return
226 return
226
227
227 handler = self.shell_handlers.get(msg_type, None)
228 handler = self.shell_handlers.get(msg_type, None)
228 if handler is None:
229 if handler is None:
229 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
230 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
230 else:
231 else:
231 # ensure default_int_handler during handler call
232 # ensure default_int_handler during handler call
232 sig = signal(SIGINT, default_int_handler)
233 sig = signal(SIGINT, default_int_handler)
233 try:
234 try:
234 handler(stream, idents, msg)
235 handler(stream, idents, msg)
235 except Exception:
236 except Exception:
236 self.log.error("Exception in message handler:", exc_info=True)
237 self.log.error("Exception in message handler:", exc_info=True)
237 finally:
238 finally:
238 signal(SIGINT, sig)
239 signal(SIGINT, sig)
239
240
240 def enter_eventloop(self):
241 def enter_eventloop(self):
241 """enter eventloop"""
242 """enter eventloop"""
242 self.log.critical("entering eventloop")
243 self.log.critical("entering eventloop")
243 # restore default_int_handler
244 # restore default_int_handler
244 signal(SIGINT, default_int_handler)
245 signal(SIGINT, default_int_handler)
245 self.eventloop(self)
246 self.eventloop(self)
246 self.log.critical("exiting eventloop")
247 self.log.critical("exiting eventloop")
247 # if eventloop exits, IOLoop should stop
248 # if eventloop exits, IOLoop should stop
248 ioloop.IOLoop.instance().stop()
249 ioloop.IOLoop.instance().stop()
249
250
250 def start(self):
251 def start(self):
251 """register dispatchers for streams"""
252 """register dispatchers for streams"""
252 if self.control_stream:
253 if self.control_stream:
253 self.control_stream.on_recv(self.dispatch_control, copy=False)
254 self.control_stream.on_recv(self.dispatch_control, copy=False)
254
255
255 def make_dispatcher(stream):
256 def make_dispatcher(stream):
256 def dispatcher(msg):
257 def dispatcher(msg):
257 return self.dispatch_shell(stream, msg)
258 return self.dispatch_shell(stream, msg)
258 return dispatcher
259 return dispatcher
259
260
260 for s in self.shell_streams:
261 for s in self.shell_streams:
261 s.on_recv(make_dispatcher(s), copy=False)
262 s.on_recv(make_dispatcher(s), copy=False)
262
263
263 def do_one_iteration(self):
264 def do_one_iteration(self):
264 """step eventloop just once"""
265 """step eventloop just once"""
265 if self.control_stream:
266 if self.control_stream:
266 self.control_stream.flush()
267 self.control_stream.flush()
267 for stream in self.shell_streams:
268 for stream in self.shell_streams:
268 # handle at most one request per iteration
269 # handle at most one request per iteration
269 stream.flush(zmq.POLLIN, 1)
270 stream.flush(zmq.POLLIN, 1)
270 stream.flush(zmq.POLLOUT)
271 stream.flush(zmq.POLLOUT)
271
272
272
273
273 def record_ports(self, ports):
274 def record_ports(self, ports):
274 """Record the ports that this kernel is using.
275 """Record the ports that this kernel is using.
275
276
276 The creator of the Kernel instance must call this methods if they
277 The creator of the Kernel instance must call this methods if they
277 want the :meth:`connect_request` method to return the port numbers.
278 want the :meth:`connect_request` method to return the port numbers.
278 """
279 """
279 self._recorded_ports = ports
280 self._recorded_ports = ports
280
281
281 #---------------------------------------------------------------------------
282 #---------------------------------------------------------------------------
282 # Kernel request handlers
283 # Kernel request handlers
283 #---------------------------------------------------------------------------
284 #---------------------------------------------------------------------------
284
285
285 def _make_subheader(self):
286 def _make_subheader(self):
286 """init subheader dict, for execute/apply_reply"""
287 """init subheader dict, for execute/apply_reply"""
287 return {
288 return {
288 'dependencies_met' : True,
289 'dependencies_met' : True,
289 'engine' : self.ident,
290 'engine' : self.ident,
290 'started': datetime.now(),
291 'started': datetime.now(),
291 }
292 }
292
293
293 def _publish_pyin(self, code, parent, execution_count):
294 def _publish_pyin(self, code, parent, execution_count):
294 """Publish the code request on the pyin stream."""
295 """Publish the code request on the pyin stream."""
295
296
296 self.session.send(self.iopub_socket, u'pyin',
297 self.session.send(self.iopub_socket, u'pyin',
297 {u'code':code, u'execution_count': execution_count},
298 {u'code':code, u'execution_count': execution_count},
298 parent=parent, ident=self._topic('pyin')
299 parent=parent, ident=self._topic('pyin')
299 )
300 )
300
301
301 def execute_request(self, stream, ident, parent):
302 def execute_request(self, stream, ident, parent):
302
303
303 self.session.send(self.iopub_socket,
304 self.session.send(self.iopub_socket,
304 u'status',
305 u'status',
305 {u'execution_state':u'busy'},
306 {u'execution_state':u'busy'},
306 parent=parent,
307 parent=parent,
307 ident=self._topic('status'),
308 ident=self._topic('status'),
308 )
309 )
309
310
310 try:
311 try:
311 content = parent[u'content']
312 content = parent[u'content']
312 code = content[u'code']
313 code = content[u'code']
313 silent = content[u'silent']
314 silent = content[u'silent']
314 except:
315 except:
315 self.log.error("Got bad msg: ")
316 self.log.error("Got bad msg: ")
316 self.log.error("%s", parent)
317 self.log.error("%s", parent)
317 return
318 return
318
319
319 sub = self._make_subheader()
320 sub = self._make_subheader()
320
321
321 shell = self.shell # we'll need this a lot here
322 shell = self.shell # we'll need this a lot here
322
323
323 # Replace raw_input. Note that is not sufficient to replace
324 # Replace raw_input. Note that is not sufficient to replace
324 # raw_input in the user namespace.
325 # raw_input in the user namespace.
325 if content.get('allow_stdin', False):
326 if content.get('allow_stdin', False):
326 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
327 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
327 else:
328 else:
328 raw_input = lambda prompt='' : self._no_raw_input()
329 raw_input = lambda prompt='' : self._no_raw_input()
329
330
330 if py3compat.PY3:
331 if py3compat.PY3:
331 __builtin__.input = raw_input
332 __builtin__.input = raw_input
332 else:
333 else:
333 __builtin__.raw_input = raw_input
334 __builtin__.raw_input = raw_input
334
335
335 # Set the parent message of the display hook and out streams.
336 # Set the parent message of the display hook and out streams.
336 shell.displayhook.set_parent(parent)
337 shell.displayhook.set_parent(parent)
337 shell.display_pub.set_parent(parent)
338 shell.display_pub.set_parent(parent)
338 sys.stdout.set_parent(parent)
339 sys.stdout.set_parent(parent)
339 sys.stderr.set_parent(parent)
340 sys.stderr.set_parent(parent)
340
341
341 # Re-broadcast our input for the benefit of listening clients, and
342 # Re-broadcast our input for the benefit of listening clients, and
342 # start computing output
343 # start computing output
343 if not silent:
344 if not silent:
344 self._publish_pyin(code, parent, shell.execution_count)
345 self._publish_pyin(code, parent, shell.execution_count)
345
346
346 reply_content = {}
347 reply_content = {}
347 try:
348 try:
348 # FIXME: the shell calls the exception handler itself.
349 # FIXME: the shell calls the exception handler itself.
349 shell.run_cell(code, store_history=not silent, silent=silent)
350 shell.run_cell(code, store_history=not silent, silent=silent)
350 except:
351 except:
351 status = u'error'
352 status = u'error'
352 # FIXME: this code right now isn't being used yet by default,
353 # FIXME: this code right now isn't being used yet by default,
353 # because the run_cell() call above directly fires off exception
354 # because the run_cell() call above directly fires off exception
354 # reporting. This code, therefore, is only active in the scenario
355 # reporting. This code, therefore, is only active in the scenario
355 # where runlines itself has an unhandled exception. We need to
356 # where runlines itself has an unhandled exception. We need to
356 # uniformize this, for all exception construction to come from a
357 # uniformize this, for all exception construction to come from a
357 # single location in the codbase.
358 # single location in the codbase.
358 etype, evalue, tb = sys.exc_info()
359 etype, evalue, tb = sys.exc_info()
359 tb_list = traceback.format_exception(etype, evalue, tb)
360 tb_list = traceback.format_exception(etype, evalue, tb)
360 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
361 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
361 else:
362 else:
362 status = u'ok'
363 status = u'ok'
363
364
364 reply_content[u'status'] = status
365 reply_content[u'status'] = status
365
366
366 # Return the execution counter so clients can display prompts
367 # Return the execution counter so clients can display prompts
367 reply_content['execution_count'] = shell.execution_count - 1
368 reply_content['execution_count'] = shell.execution_count - 1
368
369
369 # FIXME - fish exception info out of shell, possibly left there by
370 # FIXME - fish exception info out of shell, possibly left there by
370 # runlines. We'll need to clean up this logic later.
371 # runlines. We'll need to clean up this logic later.
371 if shell._reply_content is not None:
372 if shell._reply_content is not None:
372 reply_content.update(shell._reply_content)
373 reply_content.update(shell._reply_content)
373 # reset after use
374 # reset after use
374 shell._reply_content = None
375 shell._reply_content = None
375
376
376 # At this point, we can tell whether the main code execution succeeded
377 # At this point, we can tell whether the main code execution succeeded
377 # or not. If it did, we proceed to evaluate user_variables/expressions
378 # or not. If it did, we proceed to evaluate user_variables/expressions
378 if reply_content['status'] == 'ok':
379 if reply_content['status'] == 'ok':
379 reply_content[u'user_variables'] = \
380 reply_content[u'user_variables'] = \
380 shell.user_variables(content.get(u'user_variables', []))
381 shell.user_variables(content.get(u'user_variables', []))
381 reply_content[u'user_expressions'] = \
382 reply_content[u'user_expressions'] = \
382 shell.user_expressions(content.get(u'user_expressions', {}))
383 shell.user_expressions(content.get(u'user_expressions', {}))
383 else:
384 else:
384 # If there was an error, don't even try to compute variables or
385 # If there was an error, don't even try to compute variables or
385 # expressions
386 # expressions
386 reply_content[u'user_variables'] = {}
387 reply_content[u'user_variables'] = {}
387 reply_content[u'user_expressions'] = {}
388 reply_content[u'user_expressions'] = {}
388
389
389 # Payloads should be retrieved regardless of outcome, so we can both
390 # Payloads should be retrieved regardless of outcome, so we can both
390 # recover partial output (that could have been generated early in a
391 # recover partial output (that could have been generated early in a
391 # block, before an error) and clear the payload system always.
392 # block, before an error) and clear the payload system always.
392 reply_content[u'payload'] = shell.payload_manager.read_payload()
393 reply_content[u'payload'] = shell.payload_manager.read_payload()
393 # Be agressive about clearing the payload because we don't want
394 # Be agressive about clearing the payload because we don't want
394 # it to sit in memory until the next execute_request comes in.
395 # it to sit in memory until the next execute_request comes in.
395 shell.payload_manager.clear_payload()
396 shell.payload_manager.clear_payload()
396
397
397 # Flush output before sending the reply.
398 # Flush output before sending the reply.
398 sys.stdout.flush()
399 sys.stdout.flush()
399 sys.stderr.flush()
400 sys.stderr.flush()
400 # FIXME: on rare occasions, the flush doesn't seem to make it to the
401 # FIXME: on rare occasions, the flush doesn't seem to make it to the
401 # clients... This seems to mitigate the problem, but we definitely need
402 # clients... This seems to mitigate the problem, but we definitely need
402 # to better understand what's going on.
403 # to better understand what's going on.
403 if self._execute_sleep:
404 if self._execute_sleep:
404 time.sleep(self._execute_sleep)
405 time.sleep(self._execute_sleep)
405
406
406 # Send the reply.
407 # Send the reply.
407 reply_content = json_clean(reply_content)
408 reply_content = json_clean(reply_content)
408
409
409 sub['status'] = reply_content['status']
410 sub['status'] = reply_content['status']
410 if reply_content['status'] == 'error' and \
411 if reply_content['status'] == 'error' and \
411 reply_content['ename'] == 'UnmetDependency':
412 reply_content['ename'] == 'UnmetDependency':
412 sub['dependencies_met'] = False
413 sub['dependencies_met'] = False
413
414
414 reply_msg = self.session.send(stream, u'execute_reply',
415 reply_msg = self.session.send(stream, u'execute_reply',
415 reply_content, parent, subheader=sub,
416 reply_content, parent, subheader=sub,
416 ident=ident)
417 ident=ident)
417
418
418 self.log.debug("%s", reply_msg)
419 self.log.debug("%s", reply_msg)
419
420
420 if not silent and reply_msg['content']['status'] == u'error':
421 if not silent and reply_msg['content']['status'] == u'error':
421 self._abort_queues()
422 self._abort_queues()
422
423
423 self.session.send(self.iopub_socket,
424 self.session.send(self.iopub_socket,
424 u'status',
425 u'status',
425 {u'execution_state':u'idle'},
426 {u'execution_state':u'idle'},
426 parent=parent,
427 parent=parent,
427 ident=self._topic('status'))
428 ident=self._topic('status'))
428
429
429 def complete_request(self, stream, ident, parent):
430 def complete_request(self, stream, ident, parent):
430 txt, matches = self._complete(parent)
431 txt, matches = self._complete(parent)
431 matches = {'matches' : matches,
432 matches = {'matches' : matches,
432 'matched_text' : txt,
433 'matched_text' : txt,
433 'status' : 'ok'}
434 'status' : 'ok'}
434 matches = json_clean(matches)
435 matches = json_clean(matches)
435 completion_msg = self.session.send(stream, 'complete_reply',
436 completion_msg = self.session.send(stream, 'complete_reply',
436 matches, parent, ident)
437 matches, parent, ident)
437 self.log.debug("%s", completion_msg)
438 self.log.debug("%s", completion_msg)
438
439
439 def object_info_request(self, stream, ident, parent):
440 def object_info_request(self, stream, ident, parent):
440 content = parent['content']
441 content = parent['content']
441 object_info = self.shell.object_inspect(content['oname'],
442 object_info = self.shell.object_inspect(content['oname'],
442 detail_level = content.get('detail_level', 0)
443 detail_level = content.get('detail_level', 0)
443 )
444 )
444 # Before we send this object over, we scrub it for JSON usage
445 # Before we send this object over, we scrub it for JSON usage
445 oinfo = json_clean(object_info)
446 oinfo = json_clean(object_info)
446 msg = self.session.send(stream, 'object_info_reply',
447 msg = self.session.send(stream, 'object_info_reply',
447 oinfo, parent, ident)
448 oinfo, parent, ident)
448 self.log.debug("%s", msg)
449 self.log.debug("%s", msg)
449
450
450 def history_request(self, stream, ident, parent):
451 def history_request(self, stream, ident, parent):
451 # We need to pull these out, as passing **kwargs doesn't work with
452 # We need to pull these out, as passing **kwargs doesn't work with
452 # unicode keys before Python 2.6.5.
453 # unicode keys before Python 2.6.5.
453 hist_access_type = parent['content']['hist_access_type']
454 hist_access_type = parent['content']['hist_access_type']
454 raw = parent['content']['raw']
455 raw = parent['content']['raw']
455 output = parent['content']['output']
456 output = parent['content']['output']
456 if hist_access_type == 'tail':
457 if hist_access_type == 'tail':
457 n = parent['content']['n']
458 n = parent['content']['n']
458 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
459 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
459 include_latest=True)
460 include_latest=True)
460
461
461 elif hist_access_type == 'range':
462 elif hist_access_type == 'range':
462 session = parent['content']['session']
463 session = parent['content']['session']
463 start = parent['content']['start']
464 start = parent['content']['start']
464 stop = parent['content']['stop']
465 stop = parent['content']['stop']
465 hist = self.shell.history_manager.get_range(session, start, stop,
466 hist = self.shell.history_manager.get_range(session, start, stop,
466 raw=raw, output=output)
467 raw=raw, output=output)
467
468
468 elif hist_access_type == 'search':
469 elif hist_access_type == 'search':
469 pattern = parent['content']['pattern']
470 pattern = parent['content']['pattern']
470 hist = self.shell.history_manager.search(pattern, raw=raw,
471 hist = self.shell.history_manager.search(pattern, raw=raw,
471 output=output)
472 output=output)
472
473
473 else:
474 else:
474 hist = []
475 hist = []
475 hist = list(hist)
476 hist = list(hist)
476 content = {'history' : hist}
477 content = {'history' : hist}
477 content = json_clean(content)
478 content = json_clean(content)
478 msg = self.session.send(stream, 'history_reply',
479 msg = self.session.send(stream, 'history_reply',
479 content, parent, ident)
480 content, parent, ident)
480 self.log.debug("Sending history reply with %i entries", len(hist))
481 self.log.debug("Sending history reply with %i entries", len(hist))
481
482
482 def connect_request(self, stream, ident, parent):
483 def connect_request(self, stream, ident, parent):
483 if self._recorded_ports is not None:
484 if self._recorded_ports is not None:
484 content = self._recorded_ports.copy()
485 content = self._recorded_ports.copy()
485 else:
486 else:
486 content = {}
487 content = {}
487 msg = self.session.send(stream, 'connect_reply',
488 msg = self.session.send(stream, 'connect_reply',
488 content, parent, ident)
489 content, parent, ident)
489 self.log.debug("%s", msg)
490 self.log.debug("%s", msg)
490
491
491 def shutdown_request(self, stream, ident, parent):
492 def shutdown_request(self, stream, ident, parent):
492 self.shell.exit_now = True
493 self.shell.exit_now = True
493 content = dict(status='ok')
494 content = dict(status='ok')
494 content.update(parent['content'])
495 content.update(parent['content'])
495 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
496 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
496 # same content, but different msg_id for broadcasting on IOPub
497 # same content, but different msg_id for broadcasting on IOPub
497 self._shutdown_message = self.session.msg(u'shutdown_reply',
498 self._shutdown_message = self.session.msg(u'shutdown_reply',
498 content, parent
499 content, parent
499 )
500 )
500
501
501 self._at_shutdown()
502 self._at_shutdown()
502 # call sys.exit after a short delay
503 # call sys.exit after a short delay
503 ioloop.IOLoop.instance().add_timeout(time.time()+0.1, lambda : sys.exit(0))
504 ioloop.IOLoop.instance().add_timeout(time.time()+0.1, lambda : sys.exit(0))
504
505
505 #---------------------------------------------------------------------------
506 #---------------------------------------------------------------------------
506 # Engine methods
507 # Engine methods
507 #---------------------------------------------------------------------------
508 #---------------------------------------------------------------------------
508
509
509 def apply_request(self, stream, ident, parent):
510 def apply_request(self, stream, ident, parent):
510 try:
511 try:
511 content = parent[u'content']
512 content = parent[u'content']
512 bufs = parent[u'buffers']
513 bufs = parent[u'buffers']
513 msg_id = parent['header']['msg_id']
514 msg_id = parent['header']['msg_id']
514 except:
515 except:
515 self.log.error("Got bad msg: %s", parent, exc_info=True)
516 self.log.error("Got bad msg: %s", parent, exc_info=True)
516 return
517 return
517 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
518 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
518 # self.iopub_socket.send(pyin_msg)
519 # self.iopub_socket.send(pyin_msg)
519 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
520 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
520 sub = self._make_subheader()
521 sub = self._make_subheader()
521 try:
522 try:
522 # allow for not overriding displayhook
523 # allow for not overriding displayhook
523 if hasattr(sys.displayhook, 'set_parent'):
524 if hasattr(sys.displayhook, 'set_parent'):
524 sys.displayhook.set_parent(parent)
525 sys.displayhook.set_parent(parent)
525 sys.stdout.set_parent(parent)
526 sys.stdout.set_parent(parent)
526 sys.stderr.set_parent(parent)
527 sys.stderr.set_parent(parent)
527 working = self.shell.user_ns
528 working = self.shell.user_ns
528
529
529 prefix = "_"+str(msg_id).replace("-","")+"_"
530 prefix = "_"+str(msg_id).replace("-","")+"_"
530
531
531 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
532 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
532
533
533 fname = getattr(f, '__name__', 'f')
534 fname = getattr(f, '__name__', 'f')
534
535
535 fname = prefix+"f"
536 fname = prefix+"f"
536 argname = prefix+"args"
537 argname = prefix+"args"
537 kwargname = prefix+"kwargs"
538 kwargname = prefix+"kwargs"
538 resultname = prefix+"result"
539 resultname = prefix+"result"
539
540
540 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
541 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
541 # print ns
542 # print ns
542 working.update(ns)
543 working.update(ns)
543 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
544 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
544 try:
545 try:
545 exec code in self.shell.user_global_ns, self.shell.user_ns
546 exec code in self.shell.user_global_ns, self.shell.user_ns
546 result = working.get(resultname)
547 result = working.get(resultname)
547 finally:
548 finally:
548 for key in ns.iterkeys():
549 for key in ns.iterkeys():
549 working.pop(key)
550 working.pop(key)
550
551
551 packed_result,buf = serialize_object(result)
552 packed_result,buf = serialize_object(result)
552 result_buf = [packed_result]+buf
553 result_buf = [packed_result]+buf
553 except:
554 except:
554 exc_content = self._wrap_exception('apply')
555 exc_content = self._wrap_exception('apply')
555 # exc_msg = self.session.msg(u'pyerr', exc_content, parent)
556 # exc_msg = self.session.msg(u'pyerr', exc_content, parent)
556 self.session.send(self.iopub_socket, u'pyerr', exc_content, parent=parent,
557 self.session.send(self.iopub_socket, u'pyerr', exc_content, parent=parent,
557 ident=self._topic('pyerr'))
558 ident=self._topic('pyerr'))
558 reply_content = exc_content
559 reply_content = exc_content
559 result_buf = []
560 result_buf = []
560
561
561 if exc_content['ename'] == 'UnmetDependency':
562 if exc_content['ename'] == 'UnmetDependency':
562 sub['dependencies_met'] = False
563 sub['dependencies_met'] = False
563 else:
564 else:
564 reply_content = {'status' : 'ok'}
565 reply_content = {'status' : 'ok'}
565
566
566 # put 'ok'/'error' status in header, for scheduler introspection:
567 # put 'ok'/'error' status in header, for scheduler introspection:
567 sub['status'] = reply_content['status']
568 sub['status'] = reply_content['status']
568
569
569 # flush i/o
570 # flush i/o
570 sys.stdout.flush()
571 sys.stdout.flush()
571 sys.stderr.flush()
572 sys.stderr.flush()
572
573
573 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
574 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
574 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
575 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
575
576
576 #---------------------------------------------------------------------------
577 #---------------------------------------------------------------------------
577 # Control messages
578 # Control messages
578 #---------------------------------------------------------------------------
579 #---------------------------------------------------------------------------
579
580
580 def abort_request(self, stream, ident, parent):
581 def abort_request(self, stream, ident, parent):
581 """abort a specifig msg by id"""
582 """abort a specifig msg by id"""
582 msg_ids = parent['content'].get('msg_ids', None)
583 msg_ids = parent['content'].get('msg_ids', None)
583 if isinstance(msg_ids, basestring):
584 if isinstance(msg_ids, basestring):
584 msg_ids = [msg_ids]
585 msg_ids = [msg_ids]
585 if not msg_ids:
586 if not msg_ids:
586 self.abort_queues()
587 self.abort_queues()
587 for mid in msg_ids:
588 for mid in msg_ids:
588 self.aborted.add(str(mid))
589 self.aborted.add(str(mid))
589
590
590 content = dict(status='ok')
591 content = dict(status='ok')
591 reply_msg = self.session.send(stream, 'abort_reply', content=content,
592 reply_msg = self.session.send(stream, 'abort_reply', content=content,
592 parent=parent, ident=ident)
593 parent=parent, ident=ident)
593 self.log.debug("%s", reply_msg)
594 self.log.debug("%s", reply_msg)
594
595
595 def clear_request(self, stream, idents, parent):
596 def clear_request(self, stream, idents, parent):
596 """Clear our namespace."""
597 """Clear our namespace."""
597 self.shell.reset(False)
598 self.shell.reset(False)
598 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
599 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
599 content = dict(status='ok'))
600 content = dict(status='ok'))
600
601
601
602
602 #---------------------------------------------------------------------------
603 #---------------------------------------------------------------------------
603 # Protected interface
604 # Protected interface
604 #---------------------------------------------------------------------------
605 #---------------------------------------------------------------------------
605
606
606
607
607 def _wrap_exception(self, method=None):
608 def _wrap_exception(self, method=None):
608 # import here, because _wrap_exception is only used in parallel,
609 # import here, because _wrap_exception is only used in parallel,
609 # and parallel has higher min pyzmq version
610 # and parallel has higher min pyzmq version
610 from IPython.parallel.error import wrap_exception
611 from IPython.parallel.error import wrap_exception
611 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
612 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
612 content = wrap_exception(e_info)
613 content = wrap_exception(e_info)
613 return content
614 return content
614
615
615 def _topic(self, topic):
616 def _topic(self, topic):
616 """prefixed topic for IOPub messages"""
617 """prefixed topic for IOPub messages"""
617 if self.int_id >= 0:
618 if self.int_id >= 0:
618 base = "engine.%i" % self.int_id
619 base = "engine.%i" % self.int_id
619 else:
620 else:
620 base = "kernel.%s" % self.ident
621 base = "kernel.%s" % self.ident
621
622
622 return py3compat.cast_bytes("%s.%s" % (base, topic))
623 return py3compat.cast_bytes("%s.%s" % (base, topic))
623
624
624 def _abort_queues(self):
625 def _abort_queues(self):
625 for stream in self.shell_streams:
626 for stream in self.shell_streams:
626 if stream:
627 if stream:
627 self._abort_queue(stream)
628 self._abort_queue(stream)
628
629
629 def _abort_queue(self, stream):
630 def _abort_queue(self, stream):
630 poller = zmq.Poller()
631 poller = zmq.Poller()
631 poller.register(stream.socket, zmq.POLLIN)
632 poller.register(stream.socket, zmq.POLLIN)
632 while True:
633 while True:
633 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
634 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
634 if msg is None:
635 if msg is None:
635 return
636 return
636
637
637 self.log.info("Aborting:")
638 self.log.info("Aborting:")
638 self.log.info("%s", msg)
639 self.log.info("%s", msg)
639 msg_type = msg['header']['msg_type']
640 msg_type = msg['header']['msg_type']
640 reply_type = msg_type.split('_')[0] + '_reply'
641 reply_type = msg_type.split('_')[0] + '_reply'
641
642
642 status = {'status' : 'aborted'}
643 status = {'status' : 'aborted'}
643 sub = {'engine' : self.ident}
644 sub = {'engine' : self.ident}
644 sub.update(status)
645 sub.update(status)
645 reply_msg = self.session.send(stream, reply_type, subheader=sub,
646 reply_msg = self.session.send(stream, reply_type, subheader=sub,
646 content=status, parent=msg, ident=idents)
647 content=status, parent=msg, ident=idents)
647 self.log.debug("%s", reply_msg)
648 self.log.debug("%s", reply_msg)
648 # We need to wait a bit for requests to come in. This can probably
649 # We need to wait a bit for requests to come in. This can probably
649 # be set shorter for true asynchronous clients.
650 # be set shorter for true asynchronous clients.
650 poller.poll(50)
651 poller.poll(50)
651
652
652
653
653 def _no_raw_input(self):
654 def _no_raw_input(self):
654 """Raise StdinNotImplentedError if active frontend doesn't support
655 """Raise StdinNotImplentedError if active frontend doesn't support
655 stdin."""
656 stdin."""
656 raise StdinNotImplementedError("raw_input was called, but this "
657 raise StdinNotImplementedError("raw_input was called, but this "
657 "frontend does not support stdin.")
658 "frontend does not support stdin.")
658
659
659 def _raw_input(self, prompt, ident, parent):
660 def _raw_input(self, prompt, ident, parent):
660 # Flush output before making the request.
661 # Flush output before making the request.
661 sys.stderr.flush()
662 sys.stderr.flush()
662 sys.stdout.flush()
663 sys.stdout.flush()
663
664
664 # Send the input request.
665 # Send the input request.
665 content = json_clean(dict(prompt=prompt))
666 content = json_clean(dict(prompt=prompt))
666 self.session.send(self.stdin_socket, u'input_request', content, parent,
667 self.session.send(self.stdin_socket, u'input_request', content, parent,
667 ident=ident)
668 ident=ident)
668
669
669 # Await a response.
670 # Await a response.
670 while True:
671 while True:
671 try:
672 try:
672 ident, reply = self.session.recv(self.stdin_socket, 0)
673 ident, reply = self.session.recv(self.stdin_socket, 0)
673 except Exception:
674 except Exception:
674 self.log.warn("Invalid Message:", exc_info=True)
675 self.log.warn("Invalid Message:", exc_info=True)
675 else:
676 else:
676 break
677 break
677 try:
678 try:
678 value = reply['content']['value']
679 value = reply['content']['value']
679 except:
680 except:
680 self.log.error("Got bad raw_input reply: ")
681 self.log.error("Got bad raw_input reply: ")
681 self.log.error("%s", parent)
682 self.log.error("%s", parent)
682 value = ''
683 value = ''
683 if value == '\x04':
684 if value == '\x04':
684 # EOF
685 # EOF
685 raise EOFError
686 raise EOFError
686 return value
687 return value
687
688
688 def _complete(self, msg):
689 def _complete(self, msg):
689 c = msg['content']
690 c = msg['content']
690 try:
691 try:
691 cpos = int(c['cursor_pos'])
692 cpos = int(c['cursor_pos'])
692 except:
693 except:
693 # If we don't get something that we can convert to an integer, at
694 # If we don't get something that we can convert to an integer, at
694 # least attempt the completion guessing the cursor is at the end of
695 # least attempt the completion guessing the cursor is at the end of
695 # the text, if there's any, and otherwise of the line
696 # the text, if there's any, and otherwise of the line
696 cpos = len(c['text'])
697 cpos = len(c['text'])
697 if cpos==0:
698 if cpos==0:
698 cpos = len(c['line'])
699 cpos = len(c['line'])
699 return self.shell.complete(c['text'], c['line'], cpos)
700 return self.shell.complete(c['text'], c['line'], cpos)
700
701
701 def _object_info(self, context):
702 def _object_info(self, context):
702 symbol, leftover = self._symbol_from_context(context)
703 symbol, leftover = self._symbol_from_context(context)
703 if symbol is not None and not leftover:
704 if symbol is not None and not leftover:
704 doc = getattr(symbol, '__doc__', '')
705 doc = getattr(symbol, '__doc__', '')
705 else:
706 else:
706 doc = ''
707 doc = ''
707 object_info = dict(docstring = doc)
708 object_info = dict(docstring = doc)
708 return object_info
709 return object_info
709
710
710 def _symbol_from_context(self, context):
711 def _symbol_from_context(self, context):
711 if not context:
712 if not context:
712 return None, context
713 return None, context
713
714
714 base_symbol_string = context[0]
715 base_symbol_string = context[0]
715 symbol = self.shell.user_ns.get(base_symbol_string, None)
716 symbol = self.shell.user_ns.get(base_symbol_string, None)
716 if symbol is None:
717 if symbol is None:
717 symbol = __builtin__.__dict__.get(base_symbol_string, None)
718 symbol = __builtin__.__dict__.get(base_symbol_string, None)
718 if symbol is None:
719 if symbol is None:
719 return None, context
720 return None, context
720
721
721 context = context[1:]
722 context = context[1:]
722 for i, name in enumerate(context):
723 for i, name in enumerate(context):
723 new_symbol = getattr(symbol, name, None)
724 new_symbol = getattr(symbol, name, None)
724 if new_symbol is None:
725 if new_symbol is None:
725 return symbol, context[i:]
726 return symbol, context[i:]
726 else:
727 else:
727 symbol = new_symbol
728 symbol = new_symbol
728
729
729 return symbol, []
730 return symbol, []
730
731
731 def _at_shutdown(self):
732 def _at_shutdown(self):
732 """Actions taken at shutdown by the kernel, called by python's atexit.
733 """Actions taken at shutdown by the kernel, called by python's atexit.
733 """
734 """
734 # io.rprint("Kernel at_shutdown") # dbg
735 # io.rprint("Kernel at_shutdown") # dbg
735 if self._shutdown_message is not None:
736 if self._shutdown_message is not None:
736 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
737 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
737 self.log.debug("%s", self._shutdown_message)
738 self.log.debug("%s", self._shutdown_message)
738 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
739 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
739
740
740 #-----------------------------------------------------------------------------
741 #-----------------------------------------------------------------------------
741 # Aliases and Flags for the IPKernelApp
742 # Aliases and Flags for the IPKernelApp
742 #-----------------------------------------------------------------------------
743 #-----------------------------------------------------------------------------
743
744
744 flags = dict(kernel_flags)
745 flags = dict(kernel_flags)
745 flags.update(shell_flags)
746 flags.update(shell_flags)
746
747
747 addflag = lambda *args: flags.update(boolean_flag(*args))
748 addflag = lambda *args: flags.update(boolean_flag(*args))
748
749
749 flags['pylab'] = (
750 flags['pylab'] = (
750 {'IPKernelApp' : {'pylab' : 'auto'}},
751 {'IPKernelApp' : {'pylab' : 'auto'}},
751 """Pre-load matplotlib and numpy for interactive use with
752 """Pre-load matplotlib and numpy for interactive use with
752 the default matplotlib backend."""
753 the default matplotlib backend."""
753 )
754 )
754
755
755 aliases = dict(kernel_aliases)
756 aliases = dict(kernel_aliases)
756 aliases.update(shell_aliases)
757 aliases.update(shell_aliases)
757
758
758 # it's possible we don't want short aliases for *all* of these:
759 # it's possible we don't want short aliases for *all* of these:
759 aliases.update(dict(
760 aliases.update(dict(
760 pylab='IPKernelApp.pylab',
761 pylab='IPKernelApp.pylab',
761 ))
762 ))
762
763
763 #-----------------------------------------------------------------------------
764 #-----------------------------------------------------------------------------
764 # The IPKernelApp class
765 # The IPKernelApp class
765 #-----------------------------------------------------------------------------
766 #-----------------------------------------------------------------------------
766
767
767 class IPKernelApp(KernelApp, InteractiveShellApp):
768 class IPKernelApp(KernelApp, InteractiveShellApp):
768 name = 'ipkernel'
769 name = 'ipkernel'
769
770
770 aliases = Dict(aliases)
771 aliases = Dict(aliases)
771 flags = Dict(flags)
772 flags = Dict(flags)
772 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
773 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
773
774
774 # configurables
775 # configurables
775 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
776 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
776 config=True,
777 config=True,
777 help="""Pre-load matplotlib and numpy for interactive use,
778 help="""Pre-load matplotlib and numpy for interactive use,
778 selecting a particular matplotlib backend and loop integration.
779 selecting a particular matplotlib backend and loop integration.
779 """
780 """
780 )
781 )
781
782
782 @catch_config_error
783 @catch_config_error
783 def initialize(self, argv=None):
784 def initialize(self, argv=None):
784 super(IPKernelApp, self).initialize(argv)
785 super(IPKernelApp, self).initialize(argv)
785 self.init_path()
786 self.init_path()
786 self.init_shell()
787 self.init_shell()
787 self.init_extensions()
788 self.init_extensions()
788 self.init_code()
789 self.init_code()
789
790
790 def init_kernel(self):
791 def init_kernel(self):
791
792
792 shell_stream = ZMQStream(self.shell_socket)
793 shell_stream = ZMQStream(self.shell_socket)
793
794
794 kernel = Kernel(config=self.config, session=self.session,
795 kernel = Kernel(config=self.config, session=self.session,
795 shell_streams=[shell_stream],
796 shell_streams=[shell_stream],
796 iopub_socket=self.iopub_socket,
797 iopub_socket=self.iopub_socket,
797 stdin_socket=self.stdin_socket,
798 stdin_socket=self.stdin_socket,
798 log=self.log,
799 log=self.log,
799 profile_dir=self.profile_dir,
800 profile_dir=self.profile_dir,
800 )
801 )
801 self.kernel = kernel
802 self.kernel = kernel
802 kernel.record_ports(self.ports)
803 kernel.record_ports(self.ports)
803 shell = kernel.shell
804 shell = kernel.shell
804 if self.pylab:
805 if self.pylab:
805 try:
806 try:
806 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
807 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
807 shell.enable_pylab(gui, import_all=self.pylab_import_all)
808 shell.enable_pylab(gui, import_all=self.pylab_import_all)
808 except Exception:
809 except Exception:
809 self.log.error("Pylab initialization failed", exc_info=True)
810 self.log.error("Pylab initialization failed", exc_info=True)
810 # print exception straight to stdout, because normally
811 # print exception straight to stdout, because normally
811 # _showtraceback associates the reply with an execution,
812 # _showtraceback associates the reply with an execution,
812 # which means frontends will never draw it, as this exception
813 # which means frontends will never draw it, as this exception
813 # is not associated with any execute request.
814 # is not associated with any execute request.
814
815
815 # replace pyerr-sending traceback with stdout
816 # replace pyerr-sending traceback with stdout
816 _showtraceback = shell._showtraceback
817 _showtraceback = shell._showtraceback
817 def print_tb(etype, evalue, stb):
818 def print_tb(etype, evalue, stb):
818 print ("Error initializing pylab, pylab mode will not "
819 print ("Error initializing pylab, pylab mode will not "
819 "be active", file=io.stderr)
820 "be active", file=io.stderr)
820 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
821 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
821 shell._showtraceback = print_tb
822 shell._showtraceback = print_tb
822
823
823 # send the traceback over stdout
824 # send the traceback over stdout
824 shell.showtraceback(tb_offset=0)
825 shell.showtraceback(tb_offset=0)
825
826
826 # restore proper _showtraceback method
827 # restore proper _showtraceback method
827 shell._showtraceback = _showtraceback
828 shell._showtraceback = _showtraceback
828
829
829
830
830 def init_shell(self):
831 def init_shell(self):
831 self.shell = self.kernel.shell
832 self.shell = self.kernel.shell
832 self.shell.configurables.append(self)
833 self.shell.configurables.append(self)
833
834
834
835
835 #-----------------------------------------------------------------------------
836 #-----------------------------------------------------------------------------
836 # Kernel main and launch functions
837 # Kernel main and launch functions
837 #-----------------------------------------------------------------------------
838 #-----------------------------------------------------------------------------
838
839
839 def launch_kernel(*args, **kwargs):
840 def launch_kernel(*args, **kwargs):
840 """Launches a localhost IPython kernel, binding to the specified ports.
841 """Launches a localhost IPython kernel, binding to the specified ports.
841
842
842 This function simply calls entry_point.base_launch_kernel with the right
843 This function simply calls entry_point.base_launch_kernel with the right
843 first command to start an ipkernel. See base_launch_kernel for arguments.
844 first command to start an ipkernel. See base_launch_kernel for arguments.
844
845
845 Returns
846 Returns
846 -------
847 -------
847 A tuple of form:
848 A tuple of form:
848 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
849 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
849 where kernel_process is a Popen object and the ports are integers.
850 where kernel_process is a Popen object and the ports are integers.
850 """
851 """
851 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
852 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
852 *args, **kwargs)
853 *args, **kwargs)
853
854
854
855
855 def embed_kernel(module=None, local_ns=None, **kwargs):
856 def embed_kernel(module=None, local_ns=None, **kwargs):
856 """Embed and start an IPython kernel in a given scope.
857 """Embed and start an IPython kernel in a given scope.
857
858
858 Parameters
859 Parameters
859 ----------
860 ----------
860 module : ModuleType, optional
861 module : ModuleType, optional
861 The module to load into IPython globals (default: caller)
862 The module to load into IPython globals (default: caller)
862 local_ns : dict, optional
863 local_ns : dict, optional
863 The namespace to load into IPython user namespace (default: caller)
864 The namespace to load into IPython user namespace (default: caller)
864
865
865 kwargs : various, optional
866 kwargs : various, optional
866 Further keyword args are relayed to the KernelApp constructor,
867 Further keyword args are relayed to the KernelApp constructor,
867 allowing configuration of the Kernel. Will only have an effect
868 allowing configuration of the Kernel. Will only have an effect
868 on the first embed_kernel call for a given process.
869 on the first embed_kernel call for a given process.
869
870
870 """
871 """
871 # get the app if it exists, or set it up if it doesn't
872 # get the app if it exists, or set it up if it doesn't
872 if IPKernelApp.initialized():
873 if IPKernelApp.initialized():
873 app = IPKernelApp.instance()
874 app = IPKernelApp.instance()
874 else:
875 else:
875 app = IPKernelApp.instance(**kwargs)
876 app = IPKernelApp.instance(**kwargs)
876 app.initialize([])
877 app.initialize([])
877
878
878 # load the calling scope if not given
879 # load the calling scope if not given
879 (caller_module, caller_locals) = extract_module_locals(1)
880 (caller_module, caller_locals) = extract_module_locals(1)
880 if module is None:
881 if module is None:
881 module = caller_module
882 module = caller_module
882 if local_ns is None:
883 if local_ns is None:
883 local_ns = caller_locals
884 local_ns = caller_locals
884
885
885 app.kernel.user_module = module
886 app.kernel.user_module = module
886 app.kernel.user_ns = local_ns
887 app.kernel.user_ns = local_ns
887 app.start()
888 app.start()
888
889
889 def main():
890 def main():
890 """Run an IPKernel as an application"""
891 """Run an IPKernel as an application"""
891 app = IPKernelApp.instance()
892 app = IPKernelApp.instance()
892 app.initialize()
893 app.initialize()
893 app.start()
894 app.start()
894
895
895
896
896 if __name__ == '__main__':
897 if __name__ == '__main__':
897 main()
898 main()
@@ -1,536 +1,540 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
12 """
12 """
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import inspect
19 import inspect
20 import os
20 import os
21 import sys
21 import sys
22 import time
22 import time
23 from subprocess import Popen, PIPE
23 from subprocess import Popen, PIPE
24
24
25 # System library imports
25 # System library imports
26 from zmq.eventloop import ioloop
26 from zmq.eventloop import ioloop
27
27
28 # Our own
28 # Our own
29 from IPython.core.interactiveshell import (
29 from IPython.core.interactiveshell import (
30 InteractiveShell, InteractiveShellABC
30 InteractiveShell, InteractiveShellABC
31 )
31 )
32 from IPython.core import page, pylabtools
32 from IPython.core import page, pylabtools
33 from IPython.core.autocall import ZMQExitAutocall
33 from IPython.core.autocall import ZMQExitAutocall
34 from IPython.core.displaypub import DisplayPublisher
34 from IPython.core.displaypub import DisplayPublisher
35 from IPython.core.macro import Macro
35 from IPython.core.macro import Macro
36 from IPython.core.magic import MacroToEdit
36 from IPython.core.magic import MacroToEdit
37 from IPython.core.payloadpage import install_payload_page
37 from IPython.core.payloadpage import install_payload_page
38 from IPython.lib.kernel import (
38 from IPython.lib.kernel import (
39 get_connection_file, get_connection_info, connect_qtconsole
39 get_connection_file, get_connection_info, connect_qtconsole
40 )
40 )
41 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import io
42 from IPython.utils import io
43 from IPython.utils.jsonutil import json_clean
43 from IPython.utils.jsonutil import json_clean
44 from IPython.utils.path import get_py_filename
44 from IPython.utils.path import get_py_filename
45 from IPython.utils.process import arg_split
45 from IPython.utils.process import arg_split
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool
47 from IPython.utils.warn import warn, error
47 from IPython.utils.warn import warn, error
48 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
48 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
49 from IPython.zmq.session import extract_header
49 from IPython.zmq.session import extract_header
50 from session import Session
50 from session import Session
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Functions and classes
54 # Functions and classes
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 class ZMQDisplayPublisher(DisplayPublisher):
57 class ZMQDisplayPublisher(DisplayPublisher):
58 """A display publisher that publishes data using a ZeroMQ PUB socket."""
58 """A display publisher that publishes data using a ZeroMQ PUB socket."""
59
59
60 session = Instance(Session)
60 session = Instance(Session)
61 pub_socket = Instance('zmq.Socket')
61 pub_socket = Instance('zmq.Socket')
62 parent_header = Dict({})
62 parent_header = Dict({})
63
63
64 def set_parent(self, parent):
64 def set_parent(self, parent):
65 """Set the parent for outbound messages."""
65 """Set the parent for outbound messages."""
66 self.parent_header = extract_header(parent)
66 self.parent_header = extract_header(parent)
67
67
68 def _flush_streams(self):
68 def _flush_streams(self):
69 """flush IO Streams prior to display"""
69 """flush IO Streams prior to display"""
70 sys.stdout.flush()
70 sys.stdout.flush()
71 sys.stderr.flush()
71 sys.stderr.flush()
72
72
73 def publish(self, source, data, metadata=None):
73 def publish(self, source, data, metadata=None):
74 self._flush_streams()
74 self._flush_streams()
75 if metadata is None:
75 if metadata is None:
76 metadata = {}
76 metadata = {}
77 self._validate_data(source, data, metadata)
77 self._validate_data(source, data, metadata)
78 content = {}
78 content = {}
79 content['source'] = source
79 content['source'] = source
80 _encode_binary(data)
80 _encode_binary(data)
81 content['data'] = data
81 content['data'] = data
82 content['metadata'] = metadata
82 content['metadata'] = metadata
83 self.session.send(
83 self.session.send(
84 self.pub_socket, u'display_data', json_clean(content),
84 self.pub_socket, u'display_data', json_clean(content),
85 parent=self.parent_header
85 parent=self.parent_header
86 )
86 )
87
87
88 def clear_output(self, stdout=True, stderr=True, other=True):
88 def clear_output(self, stdout=True, stderr=True, other=True):
89 content = dict(stdout=stdout, stderr=stderr, other=other)
89 content = dict(stdout=stdout, stderr=stderr, other=other)
90
90
91 if stdout:
91 if stdout:
92 print('\r', file=sys.stdout, end='')
92 print('\r', file=sys.stdout, end='')
93 if stderr:
93 if stderr:
94 print('\r', file=sys.stderr, end='')
94 print('\r', file=sys.stderr, end='')
95
95
96 self._flush_streams()
96 self._flush_streams()
97
97
98 self.session.send(
98 self.session.send(
99 self.pub_socket, u'clear_output', content,
99 self.pub_socket, u'clear_output', content,
100 parent=self.parent_header
100 parent=self.parent_header
101 )
101 )
102
102
103 class ZMQInteractiveShell(InteractiveShell):
103 class ZMQInteractiveShell(InteractiveShell):
104 """A subclass of InteractiveShell for ZMQ."""
104 """A subclass of InteractiveShell for ZMQ."""
105
105
106 displayhook_class = Type(ZMQShellDisplayHook)
106 displayhook_class = Type(ZMQShellDisplayHook)
107 display_pub_class = Type(ZMQDisplayPublisher)
107 display_pub_class = Type(ZMQDisplayPublisher)
108
108
109 # Override the traitlet in the parent class, because there's no point using
109 # Override the traitlet in the parent class, because there's no point using
110 # readline for the kernel. Can be removed when the readline code is moved
110 # readline for the kernel. Can be removed when the readline code is moved
111 # to the terminal frontend.
111 # to the terminal frontend.
112 colors_force = CBool(True)
112 colors_force = CBool(True)
113 readline_use = CBool(False)
113 readline_use = CBool(False)
114 # autoindent has no meaning in a zmqshell, and attempting to enable it
114 # autoindent has no meaning in a zmqshell, and attempting to enable it
115 # will print a warning in the absence of readline.
115 # will print a warning in the absence of readline.
116 autoindent = CBool(False)
116 autoindent = CBool(False)
117
117
118 exiter = Instance(ZMQExitAutocall)
118 exiter = Instance(ZMQExitAutocall)
119 def _exiter_default(self):
119 def _exiter_default(self):
120 return ZMQExitAutocall(self)
120 return ZMQExitAutocall(self)
121
121
122 def _exit_now_changed(self, name, old, new):
122 def _exit_now_changed(self, name, old, new):
123 """stop eventloop when exit_now fires"""
123 """stop eventloop when exit_now fires"""
124 if new:
124 if new:
125 loop = ioloop.IOLoop.instance()
125 loop = ioloop.IOLoop.instance()
126 loop.add_timeout(time.time()+0.1, loop.stop)
126 loop.add_timeout(time.time()+0.1, loop.stop)
127
127
128 keepkernel_on_exit = None
128 keepkernel_on_exit = None
129
129
130 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
130 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
131 # interactive input being read; we provide event loop support in ipkernel
131 # interactive input being read; we provide event loop support in ipkernel
132 from .eventloops import enable_gui
132 from .eventloops import enable_gui
133 enable_gui = staticmethod(enable_gui)
133 enable_gui = staticmethod(enable_gui)
134
134
135 def init_environment(self):
135 def init_environment(self):
136 """Configure the user's environment.
136 """Configure the user's environment.
137
137
138 """
138 """
139 env = os.environ
139 env = os.environ
140 # These two ensure 'ls' produces nice coloring on BSD-derived systems
140 # These two ensure 'ls' produces nice coloring on BSD-derived systems
141 env['TERM'] = 'xterm-color'
141 env['TERM'] = 'xterm-color'
142 env['CLICOLOR'] = '1'
142 env['CLICOLOR'] = '1'
143 # Since normal pagers don't work at all (over pexpect we don't have
143 # Since normal pagers don't work at all (over pexpect we don't have
144 # single-key control of the subprocess), try to disable paging in
144 # single-key control of the subprocess), try to disable paging in
145 # subprocesses as much as possible.
145 # subprocesses as much as possible.
146 env['PAGER'] = 'cat'
146 env['PAGER'] = 'cat'
147 env['GIT_PAGER'] = 'cat'
147 env['GIT_PAGER'] = 'cat'
148
148
149 # And install the payload version of page.
149 # And install the payload version of page.
150 install_payload_page()
150 install_payload_page()
151
151
152 def auto_rewrite_input(self, cmd):
152 def auto_rewrite_input(self, cmd):
153 """Called to show the auto-rewritten input for autocall and friends.
153 """Called to show the auto-rewritten input for autocall and friends.
154
154
155 FIXME: this payload is currently not correctly processed by the
155 FIXME: this payload is currently not correctly processed by the
156 frontend.
156 frontend.
157 """
157 """
158 new = self.prompt_manager.render('rewrite') + cmd
158 new = self.prompt_manager.render('rewrite') + cmd
159 payload = dict(
159 payload = dict(
160 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
160 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
161 transformed_input=new,
161 transformed_input=new,
162 )
162 )
163 self.payload_manager.write_payload(payload)
163 self.payload_manager.write_payload(payload)
164
164
165 def ask_exit(self):
165 def ask_exit(self):
166 """Engage the exit actions."""
166 """Engage the exit actions."""
167 self.exit_now = True
167 self.exit_now = True
168 payload = dict(
168 payload = dict(
169 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
169 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
170 exit=True,
170 exit=True,
171 keepkernel=self.keepkernel_on_exit,
171 keepkernel=self.keepkernel_on_exit,
172 )
172 )
173 self.payload_manager.write_payload(payload)
173 self.payload_manager.write_payload(payload)
174
174
175 def _showtraceback(self, etype, evalue, stb):
175 def _showtraceback(self, etype, evalue, stb):
176
176
177 exc_content = {
177 exc_content = {
178 u'traceback' : stb,
178 u'traceback' : stb,
179 u'ename' : unicode(etype.__name__),
179 u'ename' : unicode(etype.__name__),
180 u'evalue' : unicode(evalue)
180 u'evalue' : unicode(evalue)
181 }
181 }
182
182
183 dh = self.displayhook
183 dh = self.displayhook
184 # Send exception info over pub socket for other clients than the caller
184 # Send exception info over pub socket for other clients than the caller
185 # to pick up
185 # to pick up
186 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header)
186 topic = None
187 if dh.topic:
188 topic = dh.topic.replace(b'pyout', b'pyerr')
189
190 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
187
191
188 # FIXME - Hack: store exception info in shell object. Right now, the
192 # FIXME - Hack: store exception info in shell object. Right now, the
189 # caller is reading this info after the fact, we need to fix this logic
193 # caller is reading this info after the fact, we need to fix this logic
190 # to remove this hack. Even uglier, we need to store the error status
194 # to remove this hack. Even uglier, we need to store the error status
191 # here, because in the main loop, the logic that sets it is being
195 # here, because in the main loop, the logic that sets it is being
192 # skipped because runlines swallows the exceptions.
196 # skipped because runlines swallows the exceptions.
193 exc_content[u'status'] = u'error'
197 exc_content[u'status'] = u'error'
194 self._reply_content = exc_content
198 self._reply_content = exc_content
195 # /FIXME
199 # /FIXME
196
200
197 return exc_content
201 return exc_content
198
202
199 #------------------------------------------------------------------------
203 #------------------------------------------------------------------------
200 # Magic overrides
204 # Magic overrides
201 #------------------------------------------------------------------------
205 #------------------------------------------------------------------------
202 # Once the base class stops inheriting from magic, this code needs to be
206 # Once the base class stops inheriting from magic, this code needs to be
203 # moved into a separate machinery as well. For now, at least isolate here
207 # moved into a separate machinery as well. For now, at least isolate here
204 # the magics which this class needs to implement differently from the base
208 # the magics which this class needs to implement differently from the base
205 # class, or that are unique to it.
209 # class, or that are unique to it.
206
210
207 def magic_doctest_mode(self,parameter_s=''):
211 def magic_doctest_mode(self,parameter_s=''):
208 """Toggle doctest mode on and off.
212 """Toggle doctest mode on and off.
209
213
210 This mode is intended to make IPython behave as much as possible like a
214 This mode is intended to make IPython behave as much as possible like a
211 plain Python shell, from the perspective of how its prompts, exceptions
215 plain Python shell, from the perspective of how its prompts, exceptions
212 and output look. This makes it easy to copy and paste parts of a
216 and output look. This makes it easy to copy and paste parts of a
213 session into doctests. It does so by:
217 session into doctests. It does so by:
214
218
215 - Changing the prompts to the classic ``>>>`` ones.
219 - Changing the prompts to the classic ``>>>`` ones.
216 - Changing the exception reporting mode to 'Plain'.
220 - Changing the exception reporting mode to 'Plain'.
217 - Disabling pretty-printing of output.
221 - Disabling pretty-printing of output.
218
222
219 Note that IPython also supports the pasting of code snippets that have
223 Note that IPython also supports the pasting of code snippets that have
220 leading '>>>' and '...' prompts in them. This means that you can paste
224 leading '>>>' and '...' prompts in them. This means that you can paste
221 doctests from files or docstrings (even if they have leading
225 doctests from files or docstrings (even if they have leading
222 whitespace), and the code will execute correctly. You can then use
226 whitespace), and the code will execute correctly. You can then use
223 '%history -t' to see the translated history; this will give you the
227 '%history -t' to see the translated history; this will give you the
224 input after removal of all the leading prompts and whitespace, which
228 input after removal of all the leading prompts and whitespace, which
225 can be pasted back into an editor.
229 can be pasted back into an editor.
226
230
227 With these features, you can switch into this mode easily whenever you
231 With these features, you can switch into this mode easily whenever you
228 need to do testing and changes to doctests, without having to leave
232 need to do testing and changes to doctests, without having to leave
229 your existing IPython session.
233 your existing IPython session.
230 """
234 """
231
235
232 from IPython.utils.ipstruct import Struct
236 from IPython.utils.ipstruct import Struct
233
237
234 # Shorthands
238 # Shorthands
235 shell = self.shell
239 shell = self.shell
236 disp_formatter = self.shell.display_formatter
240 disp_formatter = self.shell.display_formatter
237 ptformatter = disp_formatter.formatters['text/plain']
241 ptformatter = disp_formatter.formatters['text/plain']
238 # dstore is a data store kept in the instance metadata bag to track any
242 # dstore is a data store kept in the instance metadata bag to track any
239 # changes we make, so we can undo them later.
243 # changes we make, so we can undo them later.
240 dstore = shell.meta.setdefault('doctest_mode', Struct())
244 dstore = shell.meta.setdefault('doctest_mode', Struct())
241 save_dstore = dstore.setdefault
245 save_dstore = dstore.setdefault
242
246
243 # save a few values we'll need to recover later
247 # save a few values we'll need to recover later
244 mode = save_dstore('mode', False)
248 mode = save_dstore('mode', False)
245 save_dstore('rc_pprint', ptformatter.pprint)
249 save_dstore('rc_pprint', ptformatter.pprint)
246 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
250 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
247 save_dstore('xmode', shell.InteractiveTB.mode)
251 save_dstore('xmode', shell.InteractiveTB.mode)
248
252
249 if mode == False:
253 if mode == False:
250 # turn on
254 # turn on
251 ptformatter.pprint = False
255 ptformatter.pprint = False
252 disp_formatter.plain_text_only = True
256 disp_formatter.plain_text_only = True
253 shell.magic_xmode('Plain')
257 shell.magic_xmode('Plain')
254 else:
258 else:
255 # turn off
259 # turn off
256 ptformatter.pprint = dstore.rc_pprint
260 ptformatter.pprint = dstore.rc_pprint
257 disp_formatter.plain_text_only = dstore.rc_plain_text_only
261 disp_formatter.plain_text_only = dstore.rc_plain_text_only
258 shell.magic_xmode(dstore.xmode)
262 shell.magic_xmode(dstore.xmode)
259
263
260 # Store new mode and inform on console
264 # Store new mode and inform on console
261 dstore.mode = bool(1-int(mode))
265 dstore.mode = bool(1-int(mode))
262 mode_label = ['OFF','ON'][dstore.mode]
266 mode_label = ['OFF','ON'][dstore.mode]
263 print('Doctest mode is:', mode_label)
267 print('Doctest mode is:', mode_label)
264
268
265 # Send the payload back so that clients can modify their prompt display
269 # Send the payload back so that clients can modify their prompt display
266 payload = dict(
270 payload = dict(
267 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
271 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
268 mode=dstore.mode)
272 mode=dstore.mode)
269 self.payload_manager.write_payload(payload)
273 self.payload_manager.write_payload(payload)
270
274
271 @skip_doctest
275 @skip_doctest
272 def magic_edit(self,parameter_s='',last_call=['','']):
276 def magic_edit(self,parameter_s='',last_call=['','']):
273 """Bring up an editor and execute the resulting code.
277 """Bring up an editor and execute the resulting code.
274
278
275 Usage:
279 Usage:
276 %edit [options] [args]
280 %edit [options] [args]
277
281
278 %edit runs an external text editor. You will need to set the command for
282 %edit runs an external text editor. You will need to set the command for
279 this editor via the ``TerminalInteractiveShell.editor`` option in your
283 this editor via the ``TerminalInteractiveShell.editor`` option in your
280 configuration file before it will work.
284 configuration file before it will work.
281
285
282 This command allows you to conveniently edit multi-line code right in
286 This command allows you to conveniently edit multi-line code right in
283 your IPython session.
287 your IPython session.
284
288
285 If called without arguments, %edit opens up an empty editor with a
289 If called without arguments, %edit opens up an empty editor with a
286 temporary file and will execute the contents of this file when you
290 temporary file and will execute the contents of this file when you
287 close it (don't forget to save it!).
291 close it (don't forget to save it!).
288
292
289
293
290 Options:
294 Options:
291
295
292 -n <number>: open the editor at a specified line number. By default,
296 -n <number>: open the editor at a specified line number. By default,
293 the IPython editor hook uses the unix syntax 'editor +N filename', but
297 the IPython editor hook uses the unix syntax 'editor +N filename', but
294 you can configure this by providing your own modified hook if your
298 you can configure this by providing your own modified hook if your
295 favorite editor supports line-number specifications with a different
299 favorite editor supports line-number specifications with a different
296 syntax.
300 syntax.
297
301
298 -p: this will call the editor with the same data as the previous time
302 -p: this will call the editor with the same data as the previous time
299 it was used, regardless of how long ago (in your current session) it
303 it was used, regardless of how long ago (in your current session) it
300 was.
304 was.
301
305
302 -r: use 'raw' input. This option only applies to input taken from the
306 -r: use 'raw' input. This option only applies to input taken from the
303 user's history. By default, the 'processed' history is used, so that
307 user's history. By default, the 'processed' history is used, so that
304 magics are loaded in their transformed version to valid Python. If
308 magics are loaded in their transformed version to valid Python. If
305 this option is given, the raw input as typed as the command line is
309 this option is given, the raw input as typed as the command line is
306 used instead. When you exit the editor, it will be executed by
310 used instead. When you exit the editor, it will be executed by
307 IPython's own processor.
311 IPython's own processor.
308
312
309 -x: do not execute the edited code immediately upon exit. This is
313 -x: do not execute the edited code immediately upon exit. This is
310 mainly useful if you are editing programs which need to be called with
314 mainly useful if you are editing programs which need to be called with
311 command line arguments, which you can then do using %run.
315 command line arguments, which you can then do using %run.
312
316
313
317
314 Arguments:
318 Arguments:
315
319
316 If arguments are given, the following possibilites exist:
320 If arguments are given, the following possibilites exist:
317
321
318 - The arguments are numbers or pairs of colon-separated numbers (like
322 - The arguments are numbers or pairs of colon-separated numbers (like
319 1 4:8 9). These are interpreted as lines of previous input to be
323 1 4:8 9). These are interpreted as lines of previous input to be
320 loaded into the editor. The syntax is the same of the %macro command.
324 loaded into the editor. The syntax is the same of the %macro command.
321
325
322 - If the argument doesn't start with a number, it is evaluated as a
326 - If the argument doesn't start with a number, it is evaluated as a
323 variable and its contents loaded into the editor. You can thus edit
327 variable and its contents loaded into the editor. You can thus edit
324 any string which contains python code (including the result of
328 any string which contains python code (including the result of
325 previous edits).
329 previous edits).
326
330
327 - If the argument is the name of an object (other than a string),
331 - If the argument is the name of an object (other than a string),
328 IPython will try to locate the file where it was defined and open the
332 IPython will try to locate the file where it was defined and open the
329 editor at the point where it is defined. You can use `%edit function`
333 editor at the point where it is defined. You can use `%edit function`
330 to load an editor exactly at the point where 'function' is defined,
334 to load an editor exactly at the point where 'function' is defined,
331 edit it and have the file be executed automatically.
335 edit it and have the file be executed automatically.
332
336
333 If the object is a macro (see %macro for details), this opens up your
337 If the object is a macro (see %macro for details), this opens up your
334 specified editor with a temporary file containing the macro's data.
338 specified editor with a temporary file containing the macro's data.
335 Upon exit, the macro is reloaded with the contents of the file.
339 Upon exit, the macro is reloaded with the contents of the file.
336
340
337 Note: opening at an exact line is only supported under Unix, and some
341 Note: opening at an exact line is only supported under Unix, and some
338 editors (like kedit and gedit up to Gnome 2.8) do not understand the
342 editors (like kedit and gedit up to Gnome 2.8) do not understand the
339 '+NUMBER' parameter necessary for this feature. Good editors like
343 '+NUMBER' parameter necessary for this feature. Good editors like
340 (X)Emacs, vi, jed, pico and joe all do.
344 (X)Emacs, vi, jed, pico and joe all do.
341
345
342 - If the argument is not found as a variable, IPython will look for a
346 - If the argument is not found as a variable, IPython will look for a
343 file with that name (adding .py if necessary) and load it into the
347 file with that name (adding .py if necessary) and load it into the
344 editor. It will execute its contents with execfile() when you exit,
348 editor. It will execute its contents with execfile() when you exit,
345 loading any code in the file into your interactive namespace.
349 loading any code in the file into your interactive namespace.
346
350
347 After executing your code, %edit will return as output the code you
351 After executing your code, %edit will return as output the code you
348 typed in the editor (except when it was an existing file). This way
352 typed in the editor (except when it was an existing file). This way
349 you can reload the code in further invocations of %edit as a variable,
353 you can reload the code in further invocations of %edit as a variable,
350 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
354 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
351 the output.
355 the output.
352
356
353 Note that %edit is also available through the alias %ed.
357 Note that %edit is also available through the alias %ed.
354
358
355 This is an example of creating a simple function inside the editor and
359 This is an example of creating a simple function inside the editor and
356 then modifying it. First, start up the editor:
360 then modifying it. First, start up the editor:
357
361
358 In [1]: ed
362 In [1]: ed
359 Editing... done. Executing edited code...
363 Editing... done. Executing edited code...
360 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
364 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
361
365
362 We can then call the function foo():
366 We can then call the function foo():
363
367
364 In [2]: foo()
368 In [2]: foo()
365 foo() was defined in an editing session
369 foo() was defined in an editing session
366
370
367 Now we edit foo. IPython automatically loads the editor with the
371 Now we edit foo. IPython automatically loads the editor with the
368 (temporary) file where foo() was previously defined:
372 (temporary) file where foo() was previously defined:
369
373
370 In [3]: ed foo
374 In [3]: ed foo
371 Editing... done. Executing edited code...
375 Editing... done. Executing edited code...
372
376
373 And if we call foo() again we get the modified version:
377 And if we call foo() again we get the modified version:
374
378
375 In [4]: foo()
379 In [4]: foo()
376 foo() has now been changed!
380 foo() has now been changed!
377
381
378 Here is an example of how to edit a code snippet successive
382 Here is an example of how to edit a code snippet successive
379 times. First we call the editor:
383 times. First we call the editor:
380
384
381 In [5]: ed
385 In [5]: ed
382 Editing... done. Executing edited code...
386 Editing... done. Executing edited code...
383 hello
387 hello
384 Out[5]: "print 'hello'n"
388 Out[5]: "print 'hello'n"
385
389
386 Now we call it again with the previous output (stored in _):
390 Now we call it again with the previous output (stored in _):
387
391
388 In [6]: ed _
392 In [6]: ed _
389 Editing... done. Executing edited code...
393 Editing... done. Executing edited code...
390 hello world
394 hello world
391 Out[6]: "print 'hello world'n"
395 Out[6]: "print 'hello world'n"
392
396
393 Now we call it with the output #8 (stored in _8, also as Out[8]):
397 Now we call it with the output #8 (stored in _8, also as Out[8]):
394
398
395 In [7]: ed _8
399 In [7]: ed _8
396 Editing... done. Executing edited code...
400 Editing... done. Executing edited code...
397 hello again
401 hello again
398 Out[7]: "print 'hello again'n"
402 Out[7]: "print 'hello again'n"
399 """
403 """
400
404
401 opts,args = self.parse_options(parameter_s,'prn:')
405 opts,args = self.parse_options(parameter_s,'prn:')
402
406
403 try:
407 try:
404 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
408 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
405 except MacroToEdit as e:
409 except MacroToEdit as e:
406 # TODO: Implement macro editing over 2 processes.
410 # TODO: Implement macro editing over 2 processes.
407 print("Macro editing not yet implemented in 2-process model.")
411 print("Macro editing not yet implemented in 2-process model.")
408 return
412 return
409
413
410 # Make sure we send to the client an absolute path, in case the working
414 # Make sure we send to the client an absolute path, in case the working
411 # directory of client and kernel don't match
415 # directory of client and kernel don't match
412 filename = os.path.abspath(filename)
416 filename = os.path.abspath(filename)
413
417
414 payload = {
418 payload = {
415 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
419 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
416 'filename' : filename,
420 'filename' : filename,
417 'line_number' : lineno
421 'line_number' : lineno
418 }
422 }
419 self.payload_manager.write_payload(payload)
423 self.payload_manager.write_payload(payload)
420
424
421 # A few magics that are adapted to the specifics of using pexpect and a
425 # A few magics that are adapted to the specifics of using pexpect and a
422 # remote terminal
426 # remote terminal
423
427
424 def magic_clear(self, arg_s):
428 def magic_clear(self, arg_s):
425 """Clear the terminal."""
429 """Clear the terminal."""
426 if os.name == 'posix':
430 if os.name == 'posix':
427 self.shell.system("clear")
431 self.shell.system("clear")
428 else:
432 else:
429 self.shell.system("cls")
433 self.shell.system("cls")
430
434
431 if os.name == 'nt':
435 if os.name == 'nt':
432 # This is the usual name in windows
436 # This is the usual name in windows
433 magic_cls = magic_clear
437 magic_cls = magic_clear
434
438
435 # Terminal pagers won't work over pexpect, but we do have our own pager
439 # Terminal pagers won't work over pexpect, but we do have our own pager
436
440
437 def magic_less(self, arg_s):
441 def magic_less(self, arg_s):
438 """Show a file through the pager.
442 """Show a file through the pager.
439
443
440 Files ending in .py are syntax-highlighted."""
444 Files ending in .py are syntax-highlighted."""
441 cont = open(arg_s).read()
445 cont = open(arg_s).read()
442 if arg_s.endswith('.py'):
446 if arg_s.endswith('.py'):
443 cont = self.shell.pycolorize(cont)
447 cont = self.shell.pycolorize(cont)
444 page.page(cont)
448 page.page(cont)
445
449
446 magic_more = magic_less
450 magic_more = magic_less
447
451
448 # Man calls a pager, so we also need to redefine it
452 # Man calls a pager, so we also need to redefine it
449 if os.name == 'posix':
453 if os.name == 'posix':
450 def magic_man(self, arg_s):
454 def magic_man(self, arg_s):
451 """Find the man page for the given command and display in pager."""
455 """Find the man page for the given command and display in pager."""
452 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
456 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
453 split=False))
457 split=False))
454
458
455 # FIXME: this is specific to the GUI, so we should let the gui app load
459 # FIXME: this is specific to the GUI, so we should let the gui app load
456 # magics at startup that are only for the gui. Once the gui app has proper
460 # magics at startup that are only for the gui. Once the gui app has proper
457 # profile and configuration management, we can have it initialize a kernel
461 # profile and configuration management, we can have it initialize a kernel
458 # with a special config file that provides these.
462 # with a special config file that provides these.
459 def magic_guiref(self, arg_s):
463 def magic_guiref(self, arg_s):
460 """Show a basic reference about the GUI console."""
464 """Show a basic reference about the GUI console."""
461 from IPython.core.usage import gui_reference
465 from IPython.core.usage import gui_reference
462 page.page(gui_reference, auto_html=True)
466 page.page(gui_reference, auto_html=True)
463
467
464 def magic_connect_info(self, arg_s):
468 def magic_connect_info(self, arg_s):
465 """Print information for connecting other clients to this kernel
469 """Print information for connecting other clients to this kernel
466
470
467 It will print the contents of this session's connection file, as well as
471 It will print the contents of this session's connection file, as well as
468 shortcuts for local clients.
472 shortcuts for local clients.
469
473
470 In the simplest case, when called from the most recently launched kernel,
474 In the simplest case, when called from the most recently launched kernel,
471 secondary clients can be connected, simply with:
475 secondary clients can be connected, simply with:
472
476
473 $> ipython <app> --existing
477 $> ipython <app> --existing
474
478
475 """
479 """
476
480
477 from IPython.core.application import BaseIPythonApplication as BaseIPApp
481 from IPython.core.application import BaseIPythonApplication as BaseIPApp
478
482
479 if BaseIPApp.initialized():
483 if BaseIPApp.initialized():
480 app = BaseIPApp.instance()
484 app = BaseIPApp.instance()
481 security_dir = app.profile_dir.security_dir
485 security_dir = app.profile_dir.security_dir
482 profile = app.profile
486 profile = app.profile
483 else:
487 else:
484 profile = 'default'
488 profile = 'default'
485 security_dir = ''
489 security_dir = ''
486
490
487 try:
491 try:
488 connection_file = get_connection_file()
492 connection_file = get_connection_file()
489 info = get_connection_info(unpack=False)
493 info = get_connection_info(unpack=False)
490 except Exception as e:
494 except Exception as e:
491 error("Could not get connection info: %r" % e)
495 error("Could not get connection info: %r" % e)
492 return
496 return
493
497
494 # add profile flag for non-default profile
498 # add profile flag for non-default profile
495 profile_flag = "--profile %s" % profile if profile != 'default' else ""
499 profile_flag = "--profile %s" % profile if profile != 'default' else ""
496
500
497 # if it's in the security dir, truncate to basename
501 # if it's in the security dir, truncate to basename
498 if security_dir == os.path.dirname(connection_file):
502 if security_dir == os.path.dirname(connection_file):
499 connection_file = os.path.basename(connection_file)
503 connection_file = os.path.basename(connection_file)
500
504
501
505
502 print (info + '\n')
506 print (info + '\n')
503 print ("Paste the above JSON into a file, and connect with:\n"
507 print ("Paste the above JSON into a file, and connect with:\n"
504 " $> ipython <app> --existing <file>\n"
508 " $> ipython <app> --existing <file>\n"
505 "or, if you are local, you can connect with just:\n"
509 "or, if you are local, you can connect with just:\n"
506 " $> ipython <app> --existing {0} {1}\n"
510 " $> ipython <app> --existing {0} {1}\n"
507 "or even just:\n"
511 "or even just:\n"
508 " $> ipython <app> --existing {1}\n"
512 " $> ipython <app> --existing {1}\n"
509 "if this is the most recent IPython session you have started.".format(
513 "if this is the most recent IPython session you have started.".format(
510 connection_file, profile_flag
514 connection_file, profile_flag
511 )
515 )
512 )
516 )
513
517
514 def magic_qtconsole(self, arg_s):
518 def magic_qtconsole(self, arg_s):
515 """Open a qtconsole connected to this kernel.
519 """Open a qtconsole connected to this kernel.
516
520
517 Useful for connecting a qtconsole to running notebooks, for better
521 Useful for connecting a qtconsole to running notebooks, for better
518 debugging.
522 debugging.
519 """
523 """
520 try:
524 try:
521 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
525 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
522 except Exception as e:
526 except Exception as e:
523 error("Could not start qtconsole: %r" % e)
527 error("Could not start qtconsole: %r" % e)
524 return
528 return
525
529
526 def set_next_input(self, text):
530 def set_next_input(self, text):
527 """Send the specified text to the frontend to be presented at the next
531 """Send the specified text to the frontend to be presented at the next
528 input cell."""
532 input cell."""
529 payload = dict(
533 payload = dict(
530 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
534 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
531 text=text
535 text=text
532 )
536 )
533 self.payload_manager.write_payload(payload)
537 self.payload_manager.write_payload(payload)
534
538
535
539
536 InteractiveShellABC.register(ZMQInteractiveShell)
540 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now