##// END OF EJS Templates
move multikernelmanager to IPython.kernel
MinRK -
Show More
@@ -0,0 +1,257 b''
1 """A kernel manager for multiple kernels
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2013 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 import os
20 import uuid
21
22 import zmq
23 from zmq.eventloop.zmqstream import ZMQStream
24
25 from IPython.config.configurable import LoggingConfigurable
26 from IPython.utils.importstring import import_item
27 from IPython.utils.traitlets import (
28 Instance, Dict, Unicode, Any, DottedObjectName,
29 )
30 #-----------------------------------------------------------------------------
31 # Classes
32 #-----------------------------------------------------------------------------
33
34 class DuplicateKernelError(Exception):
35 pass
36
37
38 class MultiKernelManager(LoggingConfigurable):
39 """A class for managing multiple kernels."""
40
41 kernel_manager_class = DottedObjectName(
42 "IPython.kernel.blockingkernelmanager.BlockingKernelManager", config=True,
43 help="""The kernel manager class. This is configurable to allow
44 subclassing of the KernelManager for customized behavior.
45 """
46 )
47 def _kernel_manager_class_changed(self, name, old, new):
48 self.kernel_manager_factory = import_item(new)
49
50 kernel_manager_factory = Any(help="this is kernel_manager_class after import")
51 def _kernel_manager_factory_default(self):
52 return import_item(self.kernel_manager_class)
53
54 context = Instance('zmq.Context')
55 def _context_default(self):
56 return zmq.Context.instance()
57
58 connection_dir = Unicode('')
59
60 _kernels = Dict()
61
62 def list_kernel_ids(self):
63 """Return a list of the kernel ids of the active kernels."""
64 # Create a copy so we can iterate over kernels in operations
65 # that delete keys.
66 return list(self._kernels.keys())
67
68 def __len__(self):
69 """Return the number of running kernels."""
70 return len(self.list_kernel_ids())
71
72 def __contains__(self, kernel_id):
73 return kernel_id in self._kernels
74
75 def start_kernel(self, **kwargs):
76 """Start a new kernel.
77
78 The caller can pick a kernel_id by passing one in as a keyword arg,
79 otherwise one will be picked using a uuid.
80
81 To silence the kernel's stdout/stderr, call this using::
82
83 km.start_kernel(stdout=PIPE, stderr=PIPE)
84
85 """
86 kernel_id = kwargs.pop('kernel_id', unicode(uuid.uuid4()))
87 if kernel_id in self:
88 raise DuplicateKernelError('Kernel already exists: %s' % kernel_id)
89 # kernel_manager_factory is the constructor for the KernelManager
90 # subclass we are using. It can be configured as any Configurable,
91 # including things like its transport and ip.
92 km = self.kernel_manager_factory(connection_file=os.path.join(
93 self.connection_dir, "kernel-%s.json" % kernel_id),
94 config=self.config,
95 )
96 km.start_kernel(**kwargs)
97 # start just the shell channel, needed for graceful restart
98 km.start_channels(shell=True, iopub=False, stdin=False, hb=False)
99 self._kernels[kernel_id] = km
100 return kernel_id
101
102 def shutdown_kernel(self, kernel_id, now=False):
103 """Shutdown a kernel by its kernel uuid.
104
105 Parameters
106 ==========
107 kernel_id : uuid
108 The id of the kernel to shutdown.
109 now : bool
110 Should the kernel be shutdown forcibly using a signal.
111 """
112 k = self.get_kernel(kernel_id)
113 k.shutdown_kernel(now=now)
114 k.shell_channel.stop()
115 del self._kernels[kernel_id]
116
117 def shutdown_all(self, now=False):
118 """Shutdown all kernels."""
119 for kid in self.list_kernel_ids():
120 self.shutdown_kernel(kid, now=now)
121
122 def interrupt_kernel(self, kernel_id):
123 """Interrupt (SIGINT) the kernel by its uuid.
124
125 Parameters
126 ==========
127 kernel_id : uuid
128 The id of the kernel to interrupt.
129 """
130 return self.get_kernel(kernel_id).interrupt_kernel()
131
132 def signal_kernel(self, kernel_id, signum):
133 """Sends a signal to the kernel by its uuid.
134
135 Note that since only SIGTERM is supported on Windows, this function
136 is only useful on Unix systems.
137
138 Parameters
139 ==========
140 kernel_id : uuid
141 The id of the kernel to signal.
142 """
143 return self.get_kernel(kernel_id).signal_kernel(signum)
144
145 def restart_kernel(self, kernel_id):
146 """Restart a kernel by its uuid, keeping the same ports.
147
148 Parameters
149 ==========
150 kernel_id : uuid
151 The id of the kernel to interrupt.
152 """
153 return self.get_kernel(kernel_id).restart_kernel()
154
155 def get_kernel(self, kernel_id):
156 """Get the single KernelManager object for a kernel by its uuid.
157
158 Parameters
159 ==========
160 kernel_id : uuid
161 The id of the kernel.
162 """
163 km = self._kernels.get(kernel_id)
164 if km is not None:
165 return km
166 else:
167 raise KeyError("Kernel with id not found: %s" % kernel_id)
168
169 def get_connection_info(self, kernel_id):
170 """Return a dictionary of connection data for a kernel.
171
172 Parameters
173 ==========
174 kernel_id : uuid
175 The id of the kernel.
176
177 Returns
178 =======
179 connection_dict : dict
180 A dict of the information needed to connect to a kernel.
181 This includes the ip address and the integer port
182 numbers of the different channels (stdin_port, iopub_port,
183 shell_port, hb_port).
184 """
185 km = self.get_kernel(kernel_id)
186 return dict(transport=km.transport,
187 ip=km.ip,
188 shell_port=km.shell_port,
189 iopub_port=km.iopub_port,
190 stdin_port=km.stdin_port,
191 hb_port=km.hb_port,
192 )
193
194 def _make_url(self, transport, ip, port):
195 """Make a ZeroMQ URL for a given transport, ip and port."""
196 if transport == 'tcp':
197 return "tcp://%s:%i" % (ip, port)
198 else:
199 return "%s://%s-%s" % (transport, ip, port)
200
201 def _create_connected_stream(self, kernel_id, socket_type, channel):
202 """Create a connected ZMQStream for a kernel."""
203 cinfo = self.get_connection_info(kernel_id)
204 url = self._make_url(cinfo['transport'], cinfo['ip'],
205 cinfo['%s_port' % channel]
206 )
207 sock = self.context.socket(socket_type)
208 self.log.info("Connecting to: %s" % url)
209 sock.connect(url)
210 return ZMQStream(sock)
211
212 def create_iopub_stream(self, kernel_id):
213 """Return a ZMQStream object connected to the iopub channel.
214
215 Parameters
216 ==========
217 kernel_id : uuid
218 The id of the kernel.
219
220 Returns
221 =======
222 stream : ZMQStream
223 """
224 iopub_stream = self._create_connected_stream(kernel_id, zmq.SUB, 'iopub')
225 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
226 return iopub_stream
227
228 def create_shell_stream(self, kernel_id):
229 """Return a ZMQStream object connected to the shell channel.
230
231 Parameters
232 ==========
233 kernel_id : uuid
234 The id of the kernel.
235
236 Returns
237 =======
238 stream : ZMQStream
239 """
240 shell_stream = self._create_connected_stream(kernel_id, zmq.DEALER, 'shell')
241 return shell_stream
242
243 def create_hb_stream(self, kernel_id):
244 """Return a ZMQStream object connected to the hb channel.
245
246 Parameters
247 ==========
248 kernel_id : uuid
249 The id of the kernel.
250
251 Returns
252 =======
253 stream : ZMQStream
254 """
255 hb_stream = self._create_connected_stream(kernel_id, zmq.REQ, 'hb')
256 return hb_stream
257
@@ -1,4 +1,4 b''
1 """A kernel manager for multiple kernels.
1 """A kernel manager relating notebooks and kernels
2
2
3 Authors:
3 Authors:
4
4
@@ -6,7 +6,7 b' Authors:'
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2013 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
@@ -16,247 +16,16 b' Authors:'
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import os
20 import uuid
21
22 import zmq
23 from zmq.eventloop.zmqstream import ZMQStream
24
25 from tornado import web
19 from tornado import web
26
20
27 from IPython.config.configurable import LoggingConfigurable
21 from IPython.kernel.multikernelmanager import MultiKernelManager
28 from IPython.utils.importstring import import_item
29 from IPython.utils.traitlets import (
22 from IPython.utils.traitlets import (
30 Instance, Dict, List, Unicode, Float, Integer, Any, DottedObjectName,
23 Dict, List, Unicode, Float, Integer,
31 )
24 )
32 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
33 # Classes
26 # Classes
34 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
35
28
36 class DuplicateKernelError(Exception):
37 pass
38
39
40 class MultiKernelManager(LoggingConfigurable):
41 """A class for managing multiple kernels."""
42
43 kernel_manager_class = DottedObjectName(
44 "IPython.kernel.blockingkernelmanager.BlockingKernelManager", config=True,
45 help="""The kernel manager class. This is configurable to allow
46 subclassing of the KernelManager for customized behavior.
47 """
48 )
49 def _kernel_manager_class_changed(self, name, old, new):
50 self.kernel_manager_factory = import_item(new)
51
52 kernel_manager_factory = Any(help="this is kernel_manager_class after import")
53 def _kernel_manager_factory_default(self):
54 return import_item(self.kernel_manager_class)
55
56 context = Instance('zmq.Context')
57 def _context_default(self):
58 return zmq.Context.instance()
59
60 connection_dir = Unicode('')
61
62 _kernels = Dict()
63
64 def list_kernel_ids(self):
65 """Return a list of the kernel ids of the active kernels."""
66 # Create a copy so we can iterate over kernels in operations
67 # that delete keys.
68 return list(self._kernels.keys())
69
70 def __len__(self):
71 """Return the number of running kernels."""
72 return len(self.list_kernel_ids())
73
74 def __contains__(self, kernel_id):
75 return kernel_id in self._kernels
76
77 def start_kernel(self, **kwargs):
78 """Start a new kernel.
79
80 The caller can pick a kernel_id by passing one in as a keyword arg,
81 otherwise one will be picked using a uuid.
82
83 To silence the kernel's stdout/stderr, call this using::
84
85 km.start_kernel(stdout=PIPE, stderr=PIPE)
86
87 """
88 kernel_id = kwargs.pop('kernel_id', unicode(uuid.uuid4()))
89 if kernel_id in self:
90 raise DuplicateKernelError('Kernel already exists: %s' % kernel_id)
91 # kernel_manager_factory is the constructor for the KernelManager
92 # subclass we are using. It can be configured as any Configurable,
93 # including things like its transport and ip.
94 km = self.kernel_manager_factory(connection_file=os.path.join(
95 self.connection_dir, "kernel-%s.json" % kernel_id),
96 config=self.config,
97 )
98 km.start_kernel(**kwargs)
99 # start just the shell channel, needed for graceful restart
100 km.start_channels(shell=True, iopub=False, stdin=False, hb=False)
101 self._kernels[kernel_id] = km
102 return kernel_id
103
104 def shutdown_kernel(self, kernel_id, now=False):
105 """Shutdown a kernel by its kernel uuid.
106
107 Parameters
108 ==========
109 kernel_id : uuid
110 The id of the kernel to shutdown.
111 now : bool
112 Should the kernel be shutdown forcibly using a signal.
113 """
114 k = self.get_kernel(kernel_id)
115 k.shutdown_kernel(now=now)
116 k.shell_channel.stop()
117 del self._kernels[kernel_id]
118
119 def shutdown_all(self, now=False):
120 """Shutdown all kernels."""
121 for kid in self.list_kernel_ids():
122 self.shutdown_kernel(kid, now=now)
123
124 def interrupt_kernel(self, kernel_id):
125 """Interrupt (SIGINT) the kernel by its uuid.
126
127 Parameters
128 ==========
129 kernel_id : uuid
130 The id of the kernel to interrupt.
131 """
132 return self.get_kernel(kernel_id).interrupt_kernel()
133
134 def signal_kernel(self, kernel_id, signum):
135 """Sends a signal to the kernel by its uuid.
136
137 Note that since only SIGTERM is supported on Windows, this function
138 is only useful on Unix systems.
139
140 Parameters
141 ==========
142 kernel_id : uuid
143 The id of the kernel to signal.
144 """
145 return self.get_kernel(kernel_id).signal_kernel(signum)
146
147 def restart_kernel(self, kernel_id):
148 """Restart a kernel by its uuid, keeping the same ports.
149
150 Parameters
151 ==========
152 kernel_id : uuid
153 The id of the kernel to interrupt.
154 """
155 return self.get_kernel(kernel_id).restart_kernel()
156
157 def get_kernel(self, kernel_id):
158 """Get the single KernelManager object for a kernel by its uuid.
159
160 Parameters
161 ==========
162 kernel_id : uuid
163 The id of the kernel.
164 """
165 km = self._kernels.get(kernel_id)
166 if km is not None:
167 return km
168 else:
169 raise KeyError("Kernel with id not found: %s" % kernel_id)
170
171 def get_connection_info(self, kernel_id):
172 """Return a dictionary of connection data for a kernel.
173
174 Parameters
175 ==========
176 kernel_id : uuid
177 The id of the kernel.
178
179 Returns
180 =======
181 connection_dict : dict
182 A dict of the information needed to connect to a kernel.
183 This includes the ip address and the integer port
184 numbers of the different channels (stdin_port, iopub_port,
185 shell_port, hb_port).
186 """
187 km = self.get_kernel(kernel_id)
188 return dict(transport=km.transport,
189 ip=km.ip,
190 shell_port=km.shell_port,
191 iopub_port=km.iopub_port,
192 stdin_port=km.stdin_port,
193 hb_port=km.hb_port,
194 )
195
196 def _make_url(self, transport, ip, port):
197 """Make a ZeroMQ URL for a given transport, ip and port."""
198 if transport == 'tcp':
199 return "tcp://%s:%i" % (ip, port)
200 else:
201 return "%s://%s-%s" % (transport, ip, port)
202
203 def _create_connected_stream(self, kernel_id, socket_type, channel):
204 """Create a connected ZMQStream for a kernel."""
205 cinfo = self.get_connection_info(kernel_id)
206 url = self._make_url(cinfo['transport'], cinfo['ip'],
207 cinfo['%s_port' % channel]
208 )
209 sock = self.context.socket(socket_type)
210 self.log.info("Connecting to: %s" % url)
211 sock.connect(url)
212 return ZMQStream(sock)
213
214 def create_iopub_stream(self, kernel_id):
215 """Return a ZMQStream object connected to the iopub channel.
216
217 Parameters
218 ==========
219 kernel_id : uuid
220 The id of the kernel.
221
222 Returns
223 =======
224 stream : ZMQStream
225 """
226 iopub_stream = self._create_connected_stream(kernel_id, zmq.SUB, 'iopub')
227 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
228 return iopub_stream
229
230 def create_shell_stream(self, kernel_id):
231 """Return a ZMQStream object connected to the shell channel.
232
233 Parameters
234 ==========
235 kernel_id : uuid
236 The id of the kernel.
237
238 Returns
239 =======
240 stream : ZMQStream
241 """
242 shell_stream = self._create_connected_stream(kernel_id, zmq.DEALER, 'shell')
243 return shell_stream
244
245 def create_hb_stream(self, kernel_id):
246 """Return a ZMQStream object connected to the hb channel.
247
248 Parameters
249 ==========
250 kernel_id : uuid
251 The id of the kernel.
252
253 Returns
254 =======
255 stream : ZMQStream
256 """
257 hb_stream = self._create_connected_stream(kernel_id, zmq.REQ, 'hb')
258 return hb_stream
259
260
29
261 class MappingKernelManager(MultiKernelManager):
30 class MappingKernelManager(MultiKernelManager):
262 """A KernelManager that handles notebok mapping and HTTP error handling"""
31 """A KernelManager that handles notebok mapping and HTTP error handling"""
@@ -16,7 +16,7 b' Useful for test suites and blocking terminal interfaces.'
16 import Queue
16 import Queue
17
17
18 from IPython.utils.traitlets import Type
18 from IPython.utils.traitlets import Type
19 from kernelmanager import KernelManager, IOPubChannel, HBChannel, \
19 from .kernelmanager import KernelManager, IOPubChannel, HBChannel, \
20 ShellChannel, StdInChannel
20 ShellChannel, StdInChannel
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
@@ -7,9 +7,9 b' from unittest import TestCase'
7 from IPython.testing import decorators as dec
7 from IPython.testing import decorators as dec
8
8
9 from IPython.config.loader import Config
9 from IPython.config.loader import Config
10 from IPython.frontend.html.notebook.kernelmanager import MultiKernelManager
11 from IPython.utils.localinterfaces import LOCALHOST
10 from IPython.utils.localinterfaces import LOCALHOST
12 from IPython.kernel.kernelmanager import KernelManager
11 from IPython.kernel.kernelmanager import KernelManager
12 from IPython.kernel.multikernelmanager import MultiKernelManager
13
13
14 class TestKernelManager(TestCase):
14 class TestKernelManager(TestCase):
15
15
@@ -45,7 +45,5 b" def check_for_zmq(minimum_version, module='IPython.zmq'):"
45 check_for_zmq('2.1.11')
45 check_for_zmq('2.1.11')
46 patch_pyzmq()
46 patch_pyzmq()
47
47
48 from IPython.kernel.blockingkernelmanager import BlockingKernelManager
49 from IPython.kernel.kernelmanager import *
50 from .session import Session
48 from .session import Session
51
49
General Comments 0
You need to be logged in to leave comments. Login now