##// END OF EJS Templates
Added a first_reply signal to the heartbeat channel.
Brian Granger -
Show More
@@ -1,185 +1,202 b''
1 """ Defines a KernelManager that provides signals and slots.
1 """ Defines a KernelManager that provides signals and slots.
2 """
2 """
3
3
4 # System library imports.
4 # System library imports.
5 from PyQt4 import QtCore
5 from PyQt4 import QtCore
6 import zmq
7
6
8 # IPython imports.
7 # IPython imports.
9 from IPython.utils.traitlets import Type
8 from IPython.utils.traitlets import Type
10 from IPython.zmq.kernelmanager import KernelManager, SubSocketChannel, \
9 from IPython.zmq.kernelmanager import KernelManager, SubSocketChannel, \
11 XReqSocketChannel, RepSocketChannel, HBSocketChannel
10 XReqSocketChannel, RepSocketChannel, HBSocketChannel
12 from util import MetaQObjectHasTraits, SuperQObject
11 from util import MetaQObjectHasTraits, SuperQObject
13
12
14
13
15 class SocketChannelQObject(SuperQObject):
14 class SocketChannelQObject(SuperQObject):
16
15
17 # Emitted when the channel is started.
16 # Emitted when the channel is started.
18 started = QtCore.pyqtSignal()
17 started = QtCore.pyqtSignal()
19
18
20 # Emitted when the channel is stopped.
19 # Emitted when the channel is stopped.
21 stopped = QtCore.pyqtSignal()
20 stopped = QtCore.pyqtSignal()
22
21
23 #---------------------------------------------------------------------------
22 #---------------------------------------------------------------------------
24 # 'ZmqSocketChannel' interface
23 # 'ZmqSocketChannel' interface
25 #---------------------------------------------------------------------------
24 #---------------------------------------------------------------------------
26
25
27 def start(self):
26 def start(self):
28 """ Reimplemented to emit signal.
27 """ Reimplemented to emit signal.
29 """
28 """
30 super(SocketChannelQObject, self).start()
29 super(SocketChannelQObject, self).start()
31 self.started.emit()
30 self.started.emit()
32
31
33 def stop(self):
32 def stop(self):
34 """ Reimplemented to emit signal.
33 """ Reimplemented to emit signal.
35 """
34 """
36 super(SocketChannelQObject, self).stop()
35 super(SocketChannelQObject, self).stop()
37 self.stopped.emit()
36 self.stopped.emit()
38
37
39
38
40 class QtXReqSocketChannel(SocketChannelQObject, XReqSocketChannel):
39 class QtXReqSocketChannel(SocketChannelQObject, XReqSocketChannel):
41
40
42 # Emitted when any message is received.
41 # Emitted when any message is received.
43 message_received = QtCore.pyqtSignal(object)
42 message_received = QtCore.pyqtSignal(object)
44
43
45 # Emitted when a reply has been received for the corresponding request type.
44 # Emitted when a reply has been received for the corresponding request
45 # type.
46 execute_reply = QtCore.pyqtSignal(object)
46 execute_reply = QtCore.pyqtSignal(object)
47 complete_reply = QtCore.pyqtSignal(object)
47 complete_reply = QtCore.pyqtSignal(object)
48 object_info_reply = QtCore.pyqtSignal(object)
48 object_info_reply = QtCore.pyqtSignal(object)
49
49
50 # Emitted when the first reply comes back
51 first_reply = QtCore.pyqtSignal(object)
52
53 # Used by the first_reply signal logic to determine if a reply is the
54 # first.
55 _handlers_called = False
56
50 #---------------------------------------------------------------------------
57 #---------------------------------------------------------------------------
51 # 'XReqSocketChannel' interface
58 # 'XReqSocketChannel' interface
52 #---------------------------------------------------------------------------
59 #---------------------------------------------------------------------------
53
60
54 def call_handlers(self, msg):
61 def call_handlers(self, msg):
55 """ Reimplemented to emit signals instead of making callbacks.
62 """ Reimplemented to emit signals instead of making callbacks.
56 """
63 """
57 # Emit the generic signal.
64 # Emit the generic signal.
58 self.message_received.emit(msg)
65 self.message_received.emit(msg)
59
66
60 # Emit signals for specialized message types.
67 # Emit signals for specialized message types.
61 msg_type = msg['msg_type']
68 msg_type = msg['msg_type']
62 signal = getattr(self, msg_type, None)
69 signal = getattr(self, msg_type, None)
63 if signal:
70 if signal:
64 signal.emit(msg)
71 signal.emit(msg)
65
72
73 if not self._handlers_called:
74 self.first_reply.emit()
75
76 self._handlers_called = True
77
78 def reset_first_reply(self):
79 """ Reset the first_reply signal to fire again on the next reply.
80 """
81 self._handlers_called = False
82
66
83
67 class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
84 class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
68
85
69 # Emitted when any message is received.
86 # Emitted when any message is received.
70 message_received = QtCore.pyqtSignal(object)
87 message_received = QtCore.pyqtSignal(object)
71
88
72 # Emitted when a message of type 'stream' is received.
89 # Emitted when a message of type 'stream' is received.
73 stream_received = QtCore.pyqtSignal(object)
90 stream_received = QtCore.pyqtSignal(object)
74
91
75 # Emitted when a message of type 'pyin' is received.
92 # Emitted when a message of type 'pyin' is received.
76 pyin_received = QtCore.pyqtSignal(object)
93 pyin_received = QtCore.pyqtSignal(object)
77
94
78 # Emitted when a message of type 'pyout' is received.
95 # Emitted when a message of type 'pyout' is received.
79 pyout_received = QtCore.pyqtSignal(object)
96 pyout_received = QtCore.pyqtSignal(object)
80
97
81 # Emitted when a message of type 'pyerr' is received.
98 # Emitted when a message of type 'pyerr' is received.
82 pyerr_received = QtCore.pyqtSignal(object)
99 pyerr_received = QtCore.pyqtSignal(object)
83
100
84 # Emitted when a crash report message is received from the kernel's
101 # Emitted when a crash report message is received from the kernel's
85 # last-resort sys.excepthook.
102 # last-resort sys.excepthook.
86 crash_received = QtCore.pyqtSignal(object)
103 crash_received = QtCore.pyqtSignal(object)
87
104
88 #---------------------------------------------------------------------------
105 #---------------------------------------------------------------------------
89 # 'SubSocketChannel' interface
106 # 'SubSocketChannel' interface
90 #---------------------------------------------------------------------------
107 #---------------------------------------------------------------------------
91
108
92 def call_handlers(self, msg):
109 def call_handlers(self, msg):
93 """ Reimplemented to emit signals instead of making callbacks.
110 """ Reimplemented to emit signals instead of making callbacks.
94 """
111 """
95 # Emit the generic signal.
112 # Emit the generic signal.
96 self.message_received.emit(msg)
113 self.message_received.emit(msg)
97
114
98 # Emit signals for specialized message types.
115 # Emit signals for specialized message types.
99 msg_type = msg['msg_type']
116 msg_type = msg['msg_type']
100 signal = getattr(self, msg_type + '_received', None)
117 signal = getattr(self, msg_type + '_received', None)
101 if signal:
118 if signal:
102 signal.emit(msg)
119 signal.emit(msg)
103 elif msg_type in ('stdout', 'stderr'):
120 elif msg_type in ('stdout', 'stderr'):
104 self.stream_received.emit(msg)
121 self.stream_received.emit(msg)
105
122
106 def flush(self):
123 def flush(self):
107 """ Reimplemented to ensure that signals are dispatched immediately.
124 """ Reimplemented to ensure that signals are dispatched immediately.
108 """
125 """
109 super(QtSubSocketChannel, self).flush()
126 super(QtSubSocketChannel, self).flush()
110 QtCore.QCoreApplication.instance().processEvents()
127 QtCore.QCoreApplication.instance().processEvents()
111
128
112
129
113 class QtRepSocketChannel(SocketChannelQObject, RepSocketChannel):
130 class QtRepSocketChannel(SocketChannelQObject, RepSocketChannel):
114
131
115 # Emitted when any message is received.
132 # Emitted when any message is received.
116 message_received = QtCore.pyqtSignal(object)
133 message_received = QtCore.pyqtSignal(object)
117
134
118 # Emitted when an input request is received.
135 # Emitted when an input request is received.
119 input_requested = QtCore.pyqtSignal(object)
136 input_requested = QtCore.pyqtSignal(object)
120
137
121 #---------------------------------------------------------------------------
138 #---------------------------------------------------------------------------
122 # 'RepSocketChannel' interface
139 # 'RepSocketChannel' interface
123 #---------------------------------------------------------------------------
140 #---------------------------------------------------------------------------
124
141
125 def call_handlers(self, msg):
142 def call_handlers(self, msg):
126 """ Reimplemented to emit signals instead of making callbacks.
143 """ Reimplemented to emit signals instead of making callbacks.
127 """
144 """
128 # Emit the generic signal.
145 # Emit the generic signal.
129 self.message_received.emit(msg)
146 self.message_received.emit(msg)
130
147
131 # Emit signals for specialized message types.
148 # Emit signals for specialized message types.
132 msg_type = msg['msg_type']
149 msg_type = msg['msg_type']
133 if msg_type == 'input_request':
150 if msg_type == 'input_request':
134 self.input_requested.emit(msg)
151 self.input_requested.emit(msg)
135
152
136
153
137 class QtHBSocketChannel(SocketChannelQObject, HBSocketChannel):
154 class QtHBSocketChannel(SocketChannelQObject, HBSocketChannel):
138
155
139 # Emitted when the kernel has died.
156 # Emitted when the kernel has died.
140 kernel_died = QtCore.pyqtSignal(object)
157 kernel_died = QtCore.pyqtSignal(object)
141
158
142 #---------------------------------------------------------------------------
159 #---------------------------------------------------------------------------
143 # 'HBSocketChannel' interface
160 # 'HBSocketChannel' interface
144 #---------------------------------------------------------------------------
161 #---------------------------------------------------------------------------
145
162
146 def call_handlers(self, since_last_heartbeat):
163 def call_handlers(self, since_last_heartbeat):
147 """ Reimplemented to emit signals instead of making callbacks.
164 """ Reimplemented to emit signals instead of making callbacks.
148 """
165 """
149 # Emit the generic signal.
166 # Emit the generic signal.
150 self.kernel_died.emit(since_last_heartbeat)
167 self.kernel_died.emit(since_last_heartbeat)
151
168
152
169
153 class QtKernelManager(KernelManager, SuperQObject):
170 class QtKernelManager(KernelManager, SuperQObject):
154 """ A KernelManager that provides signals and slots.
171 """ A KernelManager that provides signals and slots.
155 """
172 """
156
173
157 __metaclass__ = MetaQObjectHasTraits
174 __metaclass__ = MetaQObjectHasTraits
158
175
159 # Emitted when the kernel manager has started listening.
176 # Emitted when the kernel manager has started listening.
160 started_channels = QtCore.pyqtSignal()
177 started_channels = QtCore.pyqtSignal()
161
178
162 # Emitted when the kernel manager has stopped listening.
179 # Emitted when the kernel manager has stopped listening.
163 stopped_channels = QtCore.pyqtSignal()
180 stopped_channels = QtCore.pyqtSignal()
164
181
165 # Use Qt-specific channel classes that emit signals.
182 # Use Qt-specific channel classes that emit signals.
166 sub_channel_class = Type(QtSubSocketChannel)
183 sub_channel_class = Type(QtSubSocketChannel)
167 xreq_channel_class = Type(QtXReqSocketChannel)
184 xreq_channel_class = Type(QtXReqSocketChannel)
168 rep_channel_class = Type(QtRepSocketChannel)
185 rep_channel_class = Type(QtRepSocketChannel)
169 hb_channel_class = Type(QtHBSocketChannel)
186 hb_channel_class = Type(QtHBSocketChannel)
170
187
171 #---------------------------------------------------------------------------
188 #---------------------------------------------------------------------------
172 # 'KernelManager' interface
189 # 'KernelManager' interface
173 #---------------------------------------------------------------------------
190 #---------------------------------------------------------------------------
174
191
175 def start_channels(self, *args, **kw):
192 def start_channels(self, *args, **kw):
176 """ Reimplemented to emit signal.
193 """ Reimplemented to emit signal.
177 """
194 """
178 super(QtKernelManager, self).start_channels(*args, **kw)
195 super(QtKernelManager, self).start_channels(*args, **kw)
179 self.started_channels.emit()
196 self.started_channels.emit()
180
197
181 def stop_channels(self):
198 def stop_channels(self):
182 """ Reimplemented to emit signal.
199 """ Reimplemented to emit signal.
183 """
200 """
184 super(QtKernelManager, self).stop_channels()
201 super(QtKernelManager, self).stop_channels()
185 self.stopped_channels.emit()
202 self.stopped_channels.emit()
@@ -1,612 +1,612 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
24
25 # System library imports.
25 # System library imports.
26 import zmq
26 import zmq
27
27
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.utils import io
30 from IPython.utils import io
31 from IPython.utils.jsonutil import json_clean
31 from IPython.utils.jsonutil import json_clean
32 from IPython.lib import pylabtools
32 from IPython.lib import pylabtools
33 from IPython.utils.traitlets import Instance, Float
33 from IPython.utils.traitlets import Instance, Float
34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
34 from entry_point import (base_launch_kernel, make_argument_parser, make_kernel,
35 start_kernel)
35 start_kernel)
36 from iostream import OutStream
36 from iostream import OutStream
37 from session import Session, Message
37 from session import Session, Message
38 from zmqshell import ZMQInteractiveShell
38 from zmqshell import ZMQInteractiveShell
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Main kernel class
41 # Main kernel class
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 class Kernel(Configurable):
44 class Kernel(Configurable):
45
45
46 #---------------------------------------------------------------------------
46 #---------------------------------------------------------------------------
47 # Kernel interface
47 # Kernel interface
48 #---------------------------------------------------------------------------
48 #---------------------------------------------------------------------------
49
49
50 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
50 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
51 session = Instance(Session)
51 session = Instance(Session)
52 reply_socket = Instance('zmq.Socket')
52 reply_socket = Instance('zmq.Socket')
53 pub_socket = Instance('zmq.Socket')
53 pub_socket = Instance('zmq.Socket')
54 req_socket = Instance('zmq.Socket')
54 req_socket = Instance('zmq.Socket')
55
55
56 # Private interface
56 # Private interface
57
57
58 # Time to sleep after flushing the stdout/err buffers in each execute
58 # Time to sleep after flushing the stdout/err buffers in each execute
59 # cycle. While this introduces a hard limit on the minimal latency of the
59 # cycle. While this introduces a hard limit on the minimal latency of the
60 # execute cycle, it helps prevent output synchronization problems for
60 # execute cycle, it helps prevent output synchronization problems for
61 # clients.
61 # clients.
62 # Units are in seconds. The minimum zmq latency on local host is probably
62 # Units are in seconds. The minimum zmq latency on local host is probably
63 # ~150 microseconds, set this to 500us for now. We may need to increase it
63 # ~150 microseconds, set this to 500us for now. We may need to increase it
64 # a little if it's not enough after more interactive testing.
64 # a little if it's not enough after more interactive testing.
65 _execute_sleep = Float(0.0005, config=True)
65 _execute_sleep = Float(0.0005, config=True)
66
66
67 # Frequency of the kernel's event loop.
67 # Frequency of the kernel's event loop.
68 # Units are in seconds, kernel subclasses for GUI toolkits may need to
68 # Units are in seconds, kernel subclasses for GUI toolkits may need to
69 # adapt to milliseconds.
69 # adapt to milliseconds.
70 _poll_interval = Float(0.05, config=True)
70 _poll_interval = Float(0.05, config=True)
71
71
72 # If the shutdown was requested over the network, we leave here the
72 # If the shutdown was requested over the network, we leave here the
73 # necessary reply message so it can be sent by our registered atexit
73 # necessary reply message so it can be sent by our registered atexit
74 # handler. This ensures that the reply is only sent to clients truly at
74 # handler. This ensures that the reply is only sent to clients truly at
75 # the end of our shutdown process (which happens after the underlying
75 # the end of our shutdown process (which happens after the underlying
76 # IPython shell's own shutdown).
76 # IPython shell's own shutdown).
77 _shutdown_message = None
77 _shutdown_message = None
78
78
79 # This is a dict of port number that the kernel is listening on. It is set
79 # This is a dict of port number that the kernel is listening on. It is set
80 # by record_ports and used by connect_request.
80 # by record_ports and used by connect_request.
81 _recorded_ports = None
81 _recorded_ports = None
82
82
83 def __init__(self, **kwargs):
83 def __init__(self, **kwargs):
84 super(Kernel, self).__init__(**kwargs)
84 super(Kernel, self).__init__(**kwargs)
85
85
86 # Before we even start up the shell, register *first* our exit handlers
86 # Before we even start up the shell, register *first* our exit handlers
87 # so they come before the shell's
87 # so they come before the shell's
88 atexit.register(self._at_shutdown)
88 atexit.register(self._at_shutdown)
89
89
90 # Initialize the InteractiveShell subclass
90 # Initialize the InteractiveShell subclass
91 self.shell = ZMQInteractiveShell.instance()
91 self.shell = ZMQInteractiveShell.instance()
92 self.shell.displayhook.session = self.session
92 self.shell.displayhook.session = self.session
93 self.shell.displayhook.pub_socket = self.pub_socket
93 self.shell.displayhook.pub_socket = self.pub_socket
94
94
95 # TMP - hack while developing
95 # TMP - hack while developing
96 self.shell._reply_content = None
96 self.shell._reply_content = None
97
97
98 # Build dict of handlers for message types
98 # Build dict of handlers for message types
99 msg_types = [ 'execute_request', 'complete_request',
99 msg_types = [ 'execute_request', 'complete_request',
100 'object_info_request', 'history_request',
100 'object_info_request', 'history_request',
101 'shutdown_request']
101 'connect_request', 'shutdown_request']
102 self.handlers = {}
102 self.handlers = {}
103 for msg_type in msg_types:
103 for msg_type in msg_types:
104 self.handlers[msg_type] = getattr(self, msg_type)
104 self.handlers[msg_type] = getattr(self, msg_type)
105
105
106 def do_one_iteration(self):
106 def do_one_iteration(self):
107 """Do one iteration of the kernel's evaluation loop.
107 """Do one iteration of the kernel's evaluation loop.
108 """
108 """
109 try:
109 try:
110 ident = self.reply_socket.recv(zmq.NOBLOCK)
110 ident = self.reply_socket.recv(zmq.NOBLOCK)
111 except zmq.ZMQError, e:
111 except zmq.ZMQError, e:
112 if e.errno == zmq.EAGAIN:
112 if e.errno == zmq.EAGAIN:
113 return
113 return
114 else:
114 else:
115 raise
115 raise
116 # FIXME: Bug in pyzmq/zmq?
116 # FIXME: Bug in pyzmq/zmq?
117 # assert self.reply_socket.rcvmore(), "Missing message part."
117 # assert self.reply_socket.rcvmore(), "Missing message part."
118 msg = self.reply_socket.recv_json()
118 msg = self.reply_socket.recv_json()
119
119
120 # Print some info about this message and leave a '--->' marker, so it's
120 # Print some info about this message and leave a '--->' marker, so it's
121 # easier to trace visually the message chain when debugging. Each
121 # easier to trace visually the message chain when debugging. Each
122 # handler prints its message at the end.
122 # handler prints its message at the end.
123 # Eventually we'll move these from stdout to a logger.
123 # Eventually we'll move these from stdout to a logger.
124 io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
124 io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
125 io.raw_print(' Content: ', msg['content'],
125 io.raw_print(' Content: ', msg['content'],
126 '\n --->\n ', sep='', end='')
126 '\n --->\n ', sep='', end='')
127
127
128 # Find and call actual handler for message
128 # Find and call actual handler for message
129 handler = self.handlers.get(msg['msg_type'], None)
129 handler = self.handlers.get(msg['msg_type'], None)
130 if handler is None:
130 if handler is None:
131 io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
131 io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
132 else:
132 else:
133 handler(ident, msg)
133 handler(ident, msg)
134
134
135 # Check whether we should exit, in case the incoming message set the
135 # Check whether we should exit, in case the incoming message set the
136 # exit flag on
136 # exit flag on
137 if self.shell.exit_now:
137 if self.shell.exit_now:
138 io.raw_print('\nExiting IPython kernel...')
138 io.raw_print('\nExiting IPython kernel...')
139 # We do a normal, clean exit, which allows any actions registered
139 # We do a normal, clean exit, which allows any actions registered
140 # via atexit (such as history saving) to take place.
140 # via atexit (such as history saving) to take place.
141 sys.exit(0)
141 sys.exit(0)
142
142
143
143
144 def start(self):
144 def start(self):
145 """ Start the kernel main loop.
145 """ Start the kernel main loop.
146 """
146 """
147 while True:
147 while True:
148 time.sleep(self._poll_interval)
148 time.sleep(self._poll_interval)
149 self.do_one_iteration()
149 self.do_one_iteration()
150
150
151 def record_ports(self, xrep_port, pub_port, req_port, hb_port):
151 def record_ports(self, xrep_port, pub_port, req_port, hb_port):
152 """Record the ports that this kernel is using.
152 """Record the ports that this kernel is using.
153
153
154 The creator of the Kernel instance must call this methods if they
154 The creator of the Kernel instance must call this methods if they
155 want the :meth:`connect_request` method to return the port numbers.
155 want the :meth:`connect_request` method to return the port numbers.
156 """
156 """
157 self._recorded_ports = {
157 self._recorded_ports = {
158 'xrep_port' : xrep_port,
158 'xrep_port' : xrep_port,
159 'pub_port' : pub_port,
159 'pub_port' : pub_port,
160 'req_port' : req_port,
160 'req_port' : req_port,
161 'hb_port' : hb_port
161 'hb_port' : hb_port
162 }
162 }
163
163
164 #---------------------------------------------------------------------------
164 #---------------------------------------------------------------------------
165 # Kernel request handlers
165 # Kernel request handlers
166 #---------------------------------------------------------------------------
166 #---------------------------------------------------------------------------
167
167
168 def _publish_pyin(self, code, parent):
168 def _publish_pyin(self, code, parent):
169 """Publish the code request on the pyin stream."""
169 """Publish the code request on the pyin stream."""
170
170
171 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
171 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
172 self.pub_socket.send_json(pyin_msg)
172 self.pub_socket.send_json(pyin_msg)
173
173
174 def execute_request(self, ident, parent):
174 def execute_request(self, ident, parent):
175 try:
175 try:
176 content = parent[u'content']
176 content = parent[u'content']
177 code = content[u'code']
177 code = content[u'code']
178 silent = content[u'silent']
178 silent = content[u'silent']
179 except:
179 except:
180 io.raw_print_err("Got bad msg: ")
180 io.raw_print_err("Got bad msg: ")
181 io.raw_print_err(Message(parent))
181 io.raw_print_err(Message(parent))
182 return
182 return
183
183
184 shell = self.shell # we'll need this a lot here
184 shell = self.shell # we'll need this a lot here
185
185
186 # Replace raw_input. Note that is not sufficient to replace
186 # Replace raw_input. Note that is not sufficient to replace
187 # raw_input in the user namespace.
187 # raw_input in the user namespace.
188 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
188 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
189 __builtin__.raw_input = raw_input
189 __builtin__.raw_input = raw_input
190
190
191 # Set the parent message of the display hook and out streams.
191 # Set the parent message of the display hook and out streams.
192 shell.displayhook.set_parent(parent)
192 shell.displayhook.set_parent(parent)
193 sys.stdout.set_parent(parent)
193 sys.stdout.set_parent(parent)
194 sys.stderr.set_parent(parent)
194 sys.stderr.set_parent(parent)
195
195
196 # Re-broadcast our input for the benefit of listening clients, and
196 # Re-broadcast our input for the benefit of listening clients, and
197 # start computing output
197 # start computing output
198 if not silent:
198 if not silent:
199 self._publish_pyin(code, parent)
199 self._publish_pyin(code, parent)
200
200
201 reply_content = {}
201 reply_content = {}
202 try:
202 try:
203 if silent:
203 if silent:
204 # runcode uses 'exec' mode, so no displayhook will fire, and it
204 # runcode uses 'exec' mode, so no displayhook will fire, and it
205 # doesn't call logging or history manipulations. Print
205 # doesn't call logging or history manipulations. Print
206 # statements in that code will obviously still execute.
206 # statements in that code will obviously still execute.
207 shell.runcode(code)
207 shell.runcode(code)
208 else:
208 else:
209 # FIXME: runlines calls the exception handler itself.
209 # FIXME: runlines calls the exception handler itself.
210 shell._reply_content = None
210 shell._reply_content = None
211
211
212 # For now leave this here until we're sure we can stop using it
212 # For now leave this here until we're sure we can stop using it
213 #shell.runlines(code)
213 #shell.runlines(code)
214
214
215 # Experimental: cell mode! Test more before turning into
215 # Experimental: cell mode! Test more before turning into
216 # default and removing the hacks around runlines.
216 # default and removing the hacks around runlines.
217 shell.run_cell(code)
217 shell.run_cell(code)
218 except:
218 except:
219 status = u'error'
219 status = u'error'
220 # FIXME: this code right now isn't being used yet by default,
220 # FIXME: this code right now isn't being used yet by default,
221 # because the runlines() call above directly fires off exception
221 # because the runlines() call above directly fires off exception
222 # reporting. This code, therefore, is only active in the scenario
222 # reporting. This code, therefore, is only active in the scenario
223 # where runlines itself has an unhandled exception. We need to
223 # where runlines itself has an unhandled exception. We need to
224 # uniformize this, for all exception construction to come from a
224 # uniformize this, for all exception construction to come from a
225 # single location in the codbase.
225 # single location in the codbase.
226 etype, evalue, tb = sys.exc_info()
226 etype, evalue, tb = sys.exc_info()
227 tb_list = traceback.format_exception(etype, evalue, tb)
227 tb_list = traceback.format_exception(etype, evalue, tb)
228 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
228 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
229 else:
229 else:
230 status = u'ok'
230 status = u'ok'
231
231
232 reply_content[u'status'] = status
232 reply_content[u'status'] = status
233 # Compute the execution counter so clients can display prompts
233 # Compute the execution counter so clients can display prompts
234 reply_content['execution_count'] = shell.displayhook.prompt_count
234 reply_content['execution_count'] = shell.displayhook.prompt_count
235
235
236 # FIXME - fish exception info out of shell, possibly left there by
236 # FIXME - fish exception info out of shell, possibly left there by
237 # runlines. We'll need to clean up this logic later.
237 # runlines. We'll need to clean up this logic later.
238 if shell._reply_content is not None:
238 if shell._reply_content is not None:
239 reply_content.update(shell._reply_content)
239 reply_content.update(shell._reply_content)
240
240
241 # At this point, we can tell whether the main code execution succeeded
241 # At this point, we can tell whether the main code execution succeeded
242 # or not. If it did, we proceed to evaluate user_variables/expressions
242 # or not. If it did, we proceed to evaluate user_variables/expressions
243 if reply_content['status'] == 'ok':
243 if reply_content['status'] == 'ok':
244 reply_content[u'user_variables'] = \
244 reply_content[u'user_variables'] = \
245 shell.get_user_variables(content[u'user_variables'])
245 shell.get_user_variables(content[u'user_variables'])
246 reply_content[u'user_expressions'] = \
246 reply_content[u'user_expressions'] = \
247 shell.eval_expressions(content[u'user_expressions'])
247 shell.eval_expressions(content[u'user_expressions'])
248 else:
248 else:
249 # If there was an error, don't even try to compute variables or
249 # If there was an error, don't even try to compute variables or
250 # expressions
250 # expressions
251 reply_content[u'user_variables'] = {}
251 reply_content[u'user_variables'] = {}
252 reply_content[u'user_expressions'] = {}
252 reply_content[u'user_expressions'] = {}
253
253
254 # Payloads should be retrieved regardless of outcome, so we can both
254 # Payloads should be retrieved regardless of outcome, so we can both
255 # recover partial output (that could have been generated early in a
255 # recover partial output (that could have been generated early in a
256 # block, before an error) and clear the payload system always.
256 # block, before an error) and clear the payload system always.
257 reply_content[u'payload'] = shell.payload_manager.read_payload()
257 reply_content[u'payload'] = shell.payload_manager.read_payload()
258 # Be agressive about clearing the payload because we don't want
258 # Be agressive about clearing the payload because we don't want
259 # it to sit in memory until the next execute_request comes in.
259 # it to sit in memory until the next execute_request comes in.
260 shell.payload_manager.clear_payload()
260 shell.payload_manager.clear_payload()
261
261
262 # Send the reply.
262 # Send the reply.
263 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
263 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
264 io.raw_print(reply_msg)
264 io.raw_print(reply_msg)
265
265
266 # Flush output before sending the reply.
266 # Flush output before sending the reply.
267 sys.stdout.flush()
267 sys.stdout.flush()
268 sys.stderr.flush()
268 sys.stderr.flush()
269 # FIXME: on rare occasions, the flush doesn't seem to make it to the
269 # FIXME: on rare occasions, the flush doesn't seem to make it to the
270 # clients... This seems to mitigate the problem, but we definitely need
270 # clients... This seems to mitigate the problem, but we definitely need
271 # to better understand what's going on.
271 # to better understand what's going on.
272 if self._execute_sleep:
272 if self._execute_sleep:
273 time.sleep(self._execute_sleep)
273 time.sleep(self._execute_sleep)
274
274
275 self.reply_socket.send(ident, zmq.SNDMORE)
275 self.reply_socket.send(ident, zmq.SNDMORE)
276 self.reply_socket.send_json(reply_msg)
276 self.reply_socket.send_json(reply_msg)
277 if reply_msg['content']['status'] == u'error':
277 if reply_msg['content']['status'] == u'error':
278 self._abort_queue()
278 self._abort_queue()
279
279
280 def complete_request(self, ident, parent):
280 def complete_request(self, ident, parent):
281 txt, matches = self._complete(parent)
281 txt, matches = self._complete(parent)
282 matches = {'matches' : matches,
282 matches = {'matches' : matches,
283 'matched_text' : txt,
283 'matched_text' : txt,
284 'status' : 'ok'}
284 'status' : 'ok'}
285 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
285 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
286 matches, parent, ident)
286 matches, parent, ident)
287 io.raw_print(completion_msg)
287 io.raw_print(completion_msg)
288
288
289 def object_info_request(self, ident, parent):
289 def object_info_request(self, ident, parent):
290 object_info = self.shell.object_inspect(parent['content']['oname'])
290 object_info = self.shell.object_inspect(parent['content']['oname'])
291 # Before we send this object over, we turn it into a dict and we scrub
291 # Before we send this object over, we turn it into a dict and we scrub
292 # it for JSON usage
292 # it for JSON usage
293 oinfo = json_clean(object_info._asdict())
293 oinfo = json_clean(object_info._asdict())
294 msg = self.session.send(self.reply_socket, 'object_info_reply',
294 msg = self.session.send(self.reply_socket, 'object_info_reply',
295 oinfo, parent, ident)
295 oinfo, parent, ident)
296 io.raw_print(msg)
296 io.raw_print(msg)
297
297
298 def history_request(self, ident, parent):
298 def history_request(self, ident, parent):
299 output = parent['content']['output']
299 output = parent['content']['output']
300 index = parent['content']['index']
300 index = parent['content']['index']
301 raw = parent['content']['raw']
301 raw = parent['content']['raw']
302 hist = self.shell.get_history(index=index, raw=raw, output=output)
302 hist = self.shell.get_history(index=index, raw=raw, output=output)
303 content = {'history' : hist}
303 content = {'history' : hist}
304 msg = self.session.send(self.reply_socket, 'history_reply',
304 msg = self.session.send(self.reply_socket, 'history_reply',
305 content, parent, ident)
305 content, parent, ident)
306 io.raw_print(msg)
306 io.raw_print(msg)
307
307
308 def connect_request(self, ident, parent):
308 def connect_request(self, ident, parent):
309 if self._recorded_ports is not None:
309 if self._recorded_ports is not None:
310 content = self._recorded_ports.copy()
310 content = self._recorded_ports.copy()
311 else:
311 else:
312 content = {}
312 content = {}
313 msg = self.session.send(self.reply_socket, 'connect_reply',
313 msg = self.session.send(self.reply_socket, 'connect_reply',
314 content, parent, ident)
314 content, parent, ident)
315 io.raw_print(msg)
315 io.raw_print(msg)
316
316
317 def shutdown_request(self, ident, parent):
317 def shutdown_request(self, ident, parent):
318 self.shell.exit_now = True
318 self.shell.exit_now = True
319 self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
319 self._shutdown_message = self.session.msg(u'shutdown_reply', {}, parent)
320 sys.exit(0)
320 sys.exit(0)
321
321
322 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
323 # Protected interface
323 # Protected interface
324 #---------------------------------------------------------------------------
324 #---------------------------------------------------------------------------
325
325
326 def _abort_queue(self):
326 def _abort_queue(self):
327 while True:
327 while True:
328 try:
328 try:
329 ident = self.reply_socket.recv(zmq.NOBLOCK)
329 ident = self.reply_socket.recv(zmq.NOBLOCK)
330 except zmq.ZMQError, e:
330 except zmq.ZMQError, e:
331 if e.errno == zmq.EAGAIN:
331 if e.errno == zmq.EAGAIN:
332 break
332 break
333 else:
333 else:
334 assert self.reply_socket.rcvmore(), \
334 assert self.reply_socket.rcvmore(), \
335 "Unexpected missing message part."
335 "Unexpected missing message part."
336 msg = self.reply_socket.recv_json()
336 msg = self.reply_socket.recv_json()
337 io.raw_print("Aborting:\n", Message(msg))
337 io.raw_print("Aborting:\n", Message(msg))
338 msg_type = msg['msg_type']
338 msg_type = msg['msg_type']
339 reply_type = msg_type.split('_')[0] + '_reply'
339 reply_type = msg_type.split('_')[0] + '_reply'
340 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
340 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
341 io.raw_print(reply_msg)
341 io.raw_print(reply_msg)
342 self.reply_socket.send(ident,zmq.SNDMORE)
342 self.reply_socket.send(ident,zmq.SNDMORE)
343 self.reply_socket.send_json(reply_msg)
343 self.reply_socket.send_json(reply_msg)
344 # We need to wait a bit for requests to come in. This can probably
344 # We need to wait a bit for requests to come in. This can probably
345 # be set shorter for true asynchronous clients.
345 # be set shorter for true asynchronous clients.
346 time.sleep(0.1)
346 time.sleep(0.1)
347
347
348 def _raw_input(self, prompt, ident, parent):
348 def _raw_input(self, prompt, ident, parent):
349 # Flush output before making the request.
349 # Flush output before making the request.
350 sys.stderr.flush()
350 sys.stderr.flush()
351 sys.stdout.flush()
351 sys.stdout.flush()
352
352
353 # Send the input request.
353 # Send the input request.
354 content = dict(prompt=prompt)
354 content = dict(prompt=prompt)
355 msg = self.session.msg(u'input_request', content, parent)
355 msg = self.session.msg(u'input_request', content, parent)
356 self.req_socket.send_json(msg)
356 self.req_socket.send_json(msg)
357
357
358 # Await a response.
358 # Await a response.
359 reply = self.req_socket.recv_json()
359 reply = self.req_socket.recv_json()
360 try:
360 try:
361 value = reply['content']['value']
361 value = reply['content']['value']
362 except:
362 except:
363 io.raw_print_err("Got bad raw_input reply: ")
363 io.raw_print_err("Got bad raw_input reply: ")
364 io.raw_print_err(Message(parent))
364 io.raw_print_err(Message(parent))
365 value = ''
365 value = ''
366 return value
366 return value
367
367
368 def _complete(self, msg):
368 def _complete(self, msg):
369 c = msg['content']
369 c = msg['content']
370 try:
370 try:
371 cpos = int(c['cursor_pos'])
371 cpos = int(c['cursor_pos'])
372 except:
372 except:
373 # If we don't get something that we can convert to an integer, at
373 # If we don't get something that we can convert to an integer, at
374 # least attempt the completion guessing the cursor is at the end of
374 # least attempt the completion guessing the cursor is at the end of
375 # the text, if there's any, and otherwise of the line
375 # the text, if there's any, and otherwise of the line
376 cpos = len(c['text'])
376 cpos = len(c['text'])
377 if cpos==0:
377 if cpos==0:
378 cpos = len(c['line'])
378 cpos = len(c['line'])
379 return self.shell.complete(c['text'], c['line'], cpos)
379 return self.shell.complete(c['text'], c['line'], cpos)
380
380
381 def _object_info(self, context):
381 def _object_info(self, context):
382 symbol, leftover = self._symbol_from_context(context)
382 symbol, leftover = self._symbol_from_context(context)
383 if symbol is not None and not leftover:
383 if symbol is not None and not leftover:
384 doc = getattr(symbol, '__doc__', '')
384 doc = getattr(symbol, '__doc__', '')
385 else:
385 else:
386 doc = ''
386 doc = ''
387 object_info = dict(docstring = doc)
387 object_info = dict(docstring = doc)
388 return object_info
388 return object_info
389
389
390 def _symbol_from_context(self, context):
390 def _symbol_from_context(self, context):
391 if not context:
391 if not context:
392 return None, context
392 return None, context
393
393
394 base_symbol_string = context[0]
394 base_symbol_string = context[0]
395 symbol = self.shell.user_ns.get(base_symbol_string, None)
395 symbol = self.shell.user_ns.get(base_symbol_string, None)
396 if symbol is None:
396 if symbol is None:
397 symbol = __builtin__.__dict__.get(base_symbol_string, None)
397 symbol = __builtin__.__dict__.get(base_symbol_string, None)
398 if symbol is None:
398 if symbol is None:
399 return None, context
399 return None, context
400
400
401 context = context[1:]
401 context = context[1:]
402 for i, name in enumerate(context):
402 for i, name in enumerate(context):
403 new_symbol = getattr(symbol, name, None)
403 new_symbol = getattr(symbol, name, None)
404 if new_symbol is None:
404 if new_symbol is None:
405 return symbol, context[i:]
405 return symbol, context[i:]
406 else:
406 else:
407 symbol = new_symbol
407 symbol = new_symbol
408
408
409 return symbol, []
409 return symbol, []
410
410
411 def _at_shutdown(self):
411 def _at_shutdown(self):
412 """Actions taken at shutdown by the kernel, called by python's atexit.
412 """Actions taken at shutdown by the kernel, called by python's atexit.
413 """
413 """
414 # io.rprint("Kernel at_shutdown") # dbg
414 # io.rprint("Kernel at_shutdown") # dbg
415 if self._shutdown_message is not None:
415 if self._shutdown_message is not None:
416 self.reply_socket.send_json(self._shutdown_message)
416 self.reply_socket.send_json(self._shutdown_message)
417 io.raw_print(self._shutdown_message)
417 io.raw_print(self._shutdown_message)
418 # A very short sleep to give zmq time to flush its message buffers
418 # A very short sleep to give zmq time to flush its message buffers
419 # before Python truly shuts down.
419 # before Python truly shuts down.
420 time.sleep(0.01)
420 time.sleep(0.01)
421
421
422
422
423 class QtKernel(Kernel):
423 class QtKernel(Kernel):
424 """A Kernel subclass with Qt support."""
424 """A Kernel subclass with Qt support."""
425
425
426 def start(self):
426 def start(self):
427 """Start a kernel with QtPy4 event loop integration."""
427 """Start a kernel with QtPy4 event loop integration."""
428
428
429 from PyQt4 import QtCore
429 from PyQt4 import QtCore
430 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
430 from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4
431
431
432 self.app = get_app_qt4([" "])
432 self.app = get_app_qt4([" "])
433 self.app.setQuitOnLastWindowClosed(False)
433 self.app.setQuitOnLastWindowClosed(False)
434 self.timer = QtCore.QTimer()
434 self.timer = QtCore.QTimer()
435 self.timer.timeout.connect(self.do_one_iteration)
435 self.timer.timeout.connect(self.do_one_iteration)
436 # Units for the timer are in milliseconds
436 # Units for the timer are in milliseconds
437 self.timer.start(1000*self._poll_interval)
437 self.timer.start(1000*self._poll_interval)
438 start_event_loop_qt4(self.app)
438 start_event_loop_qt4(self.app)
439
439
440
440
441 class WxKernel(Kernel):
441 class WxKernel(Kernel):
442 """A Kernel subclass with Wx support."""
442 """A Kernel subclass with Wx support."""
443
443
444 def start(self):
444 def start(self):
445 """Start a kernel with wx event loop support."""
445 """Start a kernel with wx event loop support."""
446
446
447 import wx
447 import wx
448 from IPython.lib.guisupport import start_event_loop_wx
448 from IPython.lib.guisupport import start_event_loop_wx
449
449
450 doi = self.do_one_iteration
450 doi = self.do_one_iteration
451 # Wx uses milliseconds
451 # Wx uses milliseconds
452 poll_interval = int(1000*self._poll_interval)
452 poll_interval = int(1000*self._poll_interval)
453
453
454 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
454 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
455 # We make the Frame hidden when we create it in the main app below.
455 # We make the Frame hidden when we create it in the main app below.
456 class TimerFrame(wx.Frame):
456 class TimerFrame(wx.Frame):
457 def __init__(self, func):
457 def __init__(self, func):
458 wx.Frame.__init__(self, None, -1)
458 wx.Frame.__init__(self, None, -1)
459 self.timer = wx.Timer(self)
459 self.timer = wx.Timer(self)
460 # Units for the timer are in milliseconds
460 # Units for the timer are in milliseconds
461 self.timer.Start(poll_interval)
461 self.timer.Start(poll_interval)
462 self.Bind(wx.EVT_TIMER, self.on_timer)
462 self.Bind(wx.EVT_TIMER, self.on_timer)
463 self.func = func
463 self.func = func
464
464
465 def on_timer(self, event):
465 def on_timer(self, event):
466 self.func()
466 self.func()
467
467
468 # We need a custom wx.App to create our Frame subclass that has the
468 # We need a custom wx.App to create our Frame subclass that has the
469 # wx.Timer to drive the ZMQ event loop.
469 # wx.Timer to drive the ZMQ event loop.
470 class IPWxApp(wx.App):
470 class IPWxApp(wx.App):
471 def OnInit(self):
471 def OnInit(self):
472 self.frame = TimerFrame(doi)
472 self.frame = TimerFrame(doi)
473 self.frame.Show(False)
473 self.frame.Show(False)
474 return True
474 return True
475
475
476 # The redirect=False here makes sure that wx doesn't replace
476 # The redirect=False here makes sure that wx doesn't replace
477 # sys.stdout/stderr with its own classes.
477 # sys.stdout/stderr with its own classes.
478 self.app = IPWxApp(redirect=False)
478 self.app = IPWxApp(redirect=False)
479 start_event_loop_wx(self.app)
479 start_event_loop_wx(self.app)
480
480
481
481
482 class TkKernel(Kernel):
482 class TkKernel(Kernel):
483 """A Kernel subclass with Tk support."""
483 """A Kernel subclass with Tk support."""
484
484
485 def start(self):
485 def start(self):
486 """Start a Tk enabled event loop."""
486 """Start a Tk enabled event loop."""
487
487
488 import Tkinter
488 import Tkinter
489 doi = self.do_one_iteration
489 doi = self.do_one_iteration
490 # Tk uses milliseconds
490 # Tk uses milliseconds
491 poll_interval = int(1000*self._poll_interval)
491 poll_interval = int(1000*self._poll_interval)
492 # For Tkinter, we create a Tk object and call its withdraw method.
492 # For Tkinter, we create a Tk object and call its withdraw method.
493 class Timer(object):
493 class Timer(object):
494 def __init__(self, func):
494 def __init__(self, func):
495 self.app = Tkinter.Tk()
495 self.app = Tkinter.Tk()
496 self.app.withdraw()
496 self.app.withdraw()
497 self.func = func
497 self.func = func
498
498
499 def on_timer(self):
499 def on_timer(self):
500 self.func()
500 self.func()
501 self.app.after(poll_interval, self.on_timer)
501 self.app.after(poll_interval, self.on_timer)
502
502
503 def start(self):
503 def start(self):
504 self.on_timer() # Call it once to get things going.
504 self.on_timer() # Call it once to get things going.
505 self.app.mainloop()
505 self.app.mainloop()
506
506
507 self.timer = Timer(doi)
507 self.timer = Timer(doi)
508 self.timer.start()
508 self.timer.start()
509
509
510
510
511 class GTKKernel(Kernel):
511 class GTKKernel(Kernel):
512 """A Kernel subclass with GTK support."""
512 """A Kernel subclass with GTK support."""
513
513
514 def start(self):
514 def start(self):
515 """Start the kernel, coordinating with the GTK event loop"""
515 """Start the kernel, coordinating with the GTK event loop"""
516 from .gui.gtkembed import GTKEmbed
516 from .gui.gtkembed import GTKEmbed
517
517
518 gtk_kernel = GTKEmbed(self)
518 gtk_kernel = GTKEmbed(self)
519 gtk_kernel.start()
519 gtk_kernel.start()
520
520
521
521
522 #-----------------------------------------------------------------------------
522 #-----------------------------------------------------------------------------
523 # Kernel main and launch functions
523 # Kernel main and launch functions
524 #-----------------------------------------------------------------------------
524 #-----------------------------------------------------------------------------
525
525
526 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,
526 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,
527 independent=False, pylab=False):
527 independent=False, pylab=False):
528 """Launches a localhost kernel, binding to the specified ports.
528 """Launches a localhost kernel, binding to the specified ports.
529
529
530 Parameters
530 Parameters
531 ----------
531 ----------
532 xrep_port : int, optional
532 xrep_port : int, optional
533 The port to use for XREP channel.
533 The port to use for XREP channel.
534
534
535 pub_port : int, optional
535 pub_port : int, optional
536 The port to use for the SUB channel.
536 The port to use for the SUB channel.
537
537
538 req_port : int, optional
538 req_port : int, optional
539 The port to use for the REQ (raw input) channel.
539 The port to use for the REQ (raw input) channel.
540
540
541 hb_port : int, optional
541 hb_port : int, optional
542 The port to use for the hearbeat REP channel.
542 The port to use for the hearbeat REP channel.
543
543
544 independent : bool, optional (default False)
544 independent : bool, optional (default False)
545 If set, the kernel process is guaranteed to survive if this process
545 If set, the kernel process is guaranteed to survive if this process
546 dies. If not set, an effort is made to ensure that the kernel is killed
546 dies. If not set, an effort is made to ensure that the kernel is killed
547 when this process dies. Note that in this case it is still good practice
547 when this process dies. Note that in this case it is still good practice
548 to kill kernels manually before exiting.
548 to kill kernels manually before exiting.
549
549
550 pylab : bool or string, optional (default False)
550 pylab : bool or string, optional (default False)
551 If not False, the kernel will be launched with pylab enabled. If a
551 If not False, the kernel will be launched with pylab enabled. If a
552 string is passed, matplotlib will use the specified backend. Otherwise,
552 string is passed, matplotlib will use the specified backend. Otherwise,
553 matplotlib's default backend will be used.
553 matplotlib's default backend will be used.
554
554
555 Returns
555 Returns
556 -------
556 -------
557 A tuple of form:
557 A tuple of form:
558 (kernel_process, xrep_port, pub_port, req_port)
558 (kernel_process, xrep_port, pub_port, req_port)
559 where kernel_process is a Popen object and the ports are integers.
559 where kernel_process is a Popen object and the ports are integers.
560 """
560 """
561 extra_arguments = []
561 extra_arguments = []
562 if pylab:
562 if pylab:
563 extra_arguments.append('--pylab')
563 extra_arguments.append('--pylab')
564 if isinstance(pylab, basestring):
564 if isinstance(pylab, basestring):
565 extra_arguments.append(pylab)
565 extra_arguments.append(pylab)
566 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
566 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
567 xrep_port, pub_port, req_port, hb_port,
567 xrep_port, pub_port, req_port, hb_port,
568 independent, extra_arguments)
568 independent, extra_arguments)
569
569
570
570
571 def main():
571 def main():
572 """ The IPython kernel main entry point.
572 """ The IPython kernel main entry point.
573 """
573 """
574 parser = make_argument_parser()
574 parser = make_argument_parser()
575 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
575 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
576 const='auto', help = \
576 const='auto', help = \
577 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
577 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
578 given, the GUI backend is matplotlib's, otherwise use one of: \
578 given, the GUI backend is matplotlib's, otherwise use one of: \
579 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
579 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
580 namespace = parser.parse_args()
580 namespace = parser.parse_args()
581
581
582 kernel_class = Kernel
582 kernel_class = Kernel
583
583
584 kernel_classes = {
584 kernel_classes = {
585 'qt' : QtKernel,
585 'qt' : QtKernel,
586 'qt4': QtKernel,
586 'qt4': QtKernel,
587 'inline': Kernel,
587 'inline': Kernel,
588 'wx' : WxKernel,
588 'wx' : WxKernel,
589 'tk' : TkKernel,
589 'tk' : TkKernel,
590 'gtk': GTKKernel,
590 'gtk': GTKKernel,
591 }
591 }
592 if namespace.pylab:
592 if namespace.pylab:
593 if namespace.pylab == 'auto':
593 if namespace.pylab == 'auto':
594 gui, backend = pylabtools.find_gui_and_backend()
594 gui, backend = pylabtools.find_gui_and_backend()
595 else:
595 else:
596 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
596 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
597 kernel_class = kernel_classes.get(gui)
597 kernel_class = kernel_classes.get(gui)
598 if kernel_class is None:
598 if kernel_class is None:
599 raise ValueError('GUI is not supported: %r' % gui)
599 raise ValueError('GUI is not supported: %r' % gui)
600 pylabtools.activate_matplotlib(backend)
600 pylabtools.activate_matplotlib(backend)
601
601
602 kernel = make_kernel(namespace, kernel_class, OutStream)
602 kernel = make_kernel(namespace, kernel_class, OutStream)
603
603
604 if namespace.pylab:
604 if namespace.pylab:
605 pylabtools.import_pylab(kernel.shell.user_ns, backend,
605 pylabtools.import_pylab(kernel.shell.user_ns, backend,
606 shell=kernel.shell)
606 shell=kernel.shell)
607
607
608 start_kernel(namespace, kernel)
608 start_kernel(namespace, kernel)
609
609
610
610
611 if __name__ == '__main__':
611 if __name__ == '__main__':
612 main()
612 main()
General Comments 0
You need to be logged in to leave comments. Login now