##// END OF EJS Templates
remove kernels in MKM.shutdown_all
Min RK -
Show More
@@ -1,318 +1,319 b''
1 1 """A kernel manager for multiple kernels"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from __future__ import absolute_import
7 7
8 8 import os
9 9 import uuid
10 10
11 11 import zmq
12 12
13 13 from IPython.config.configurable import LoggingConfigurable
14 14 from IPython.utils.importstring import import_item
15 15 from IPython.utils.traitlets import (
16 16 Instance, Dict, List, Unicode, Any, DottedObjectName
17 17 )
18 18 from IPython.utils.py3compat import unicode_type
19 19
20 20 from .kernelspec import NATIVE_KERNEL_NAME
21 21
22 22 class DuplicateKernelError(Exception):
23 23 pass
24 24
25 25
26 26 def kernel_method(f):
27 27 """decorator for proxying MKM.method(kernel_id) to individual KMs by ID"""
28 28 def wrapped(self, kernel_id, *args, **kwargs):
29 29 # get the kernel
30 30 km = self.get_kernel(kernel_id)
31 31 method = getattr(km, f.__name__)
32 32 # call the kernel's method
33 33 r = method(*args, **kwargs)
34 34 # last thing, call anything defined in the actual class method
35 35 # such as logging messages
36 36 f(self, kernel_id, *args, **kwargs)
37 37 # return the method result
38 38 return r
39 39 return wrapped
40 40
41 41
42 42 class MultiKernelManager(LoggingConfigurable):
43 43 """A class for managing multiple kernels."""
44 44
45 45 ipython_kernel_argv = List(Unicode)
46 46
47 47 default_kernel_name = Unicode(NATIVE_KERNEL_NAME, config=True,
48 48 help="The name of the default kernel to start"
49 49 )
50 50
51 51 kernel_manager_class = DottedObjectName(
52 52 "IPython.kernel.ioloop.IOLoopKernelManager", config=True,
53 53 help="""The kernel manager class. This is configurable to allow
54 54 subclassing of the KernelManager for customized behavior.
55 55 """
56 56 )
57 57 def _kernel_manager_class_changed(self, name, old, new):
58 58 self.kernel_manager_factory = import_item(new)
59 59
60 60 kernel_manager_factory = Any(help="this is kernel_manager_class after import")
61 61 def _kernel_manager_factory_default(self):
62 62 return import_item(self.kernel_manager_class)
63 63
64 64 context = Instance('zmq.Context')
65 65 def _context_default(self):
66 66 return zmq.Context.instance()
67 67
68 68 connection_dir = Unicode('')
69 69
70 70 _kernels = Dict()
71 71
72 72 def list_kernel_ids(self):
73 73 """Return a list of the kernel ids of the active kernels."""
74 74 # Create a copy so we can iterate over kernels in operations
75 75 # that delete keys.
76 76 return list(self._kernels.keys())
77 77
78 78 def __len__(self):
79 79 """Return the number of running kernels."""
80 80 return len(self.list_kernel_ids())
81 81
82 82 def __contains__(self, kernel_id):
83 83 return kernel_id in self._kernels
84 84
85 85 def start_kernel(self, kernel_name=None, **kwargs):
86 86 """Start a new kernel.
87 87
88 88 The caller can pick a kernel_id by passing one in as a keyword arg,
89 89 otherwise one will be picked using a uuid.
90 90
91 91 To silence the kernel's stdout/stderr, call this using::
92 92
93 93 km.start_kernel(stdout=PIPE, stderr=PIPE)
94 94
95 95 """
96 96 kernel_id = kwargs.pop('kernel_id', unicode_type(uuid.uuid4()))
97 97 if kernel_id in self:
98 98 raise DuplicateKernelError('Kernel already exists: %s' % kernel_id)
99 99
100 100 if kernel_name is None:
101 101 kernel_name = self.default_kernel_name
102 102 # kernel_manager_factory is the constructor for the KernelManager
103 103 # subclass we are using. It can be configured as any Configurable,
104 104 # including things like its transport and ip.
105 105 km = self.kernel_manager_factory(connection_file=os.path.join(
106 106 self.connection_dir, "kernel-%s.json" % kernel_id),
107 107 parent=self, autorestart=True, log=self.log, kernel_name=kernel_name,
108 108 )
109 109 # FIXME: remove special treatment of IPython kernels
110 110 if km.ipython_kernel:
111 111 kwargs.setdefault('extra_arguments', self.ipython_kernel_argv)
112 112 km.start_kernel(**kwargs)
113 113 self._kernels[kernel_id] = km
114 114 return kernel_id
115 115
116 116 @kernel_method
117 117 def shutdown_kernel(self, kernel_id, now=False, restart=False):
118 118 """Shutdown a kernel by its kernel uuid.
119 119
120 120 Parameters
121 121 ==========
122 122 kernel_id : uuid
123 123 The id of the kernel to shutdown.
124 124 now : bool
125 125 Should the kernel be shutdown forcibly using a signal.
126 126 restart : bool
127 127 Will the kernel be restarted?
128 128 """
129 129 self.log.info("Kernel shutdown: %s" % kernel_id)
130 130 self.remove_kernel(kernel_id)
131 131
132 132 @kernel_method
133 133 def request_shutdown(self, kernel_id, restart=False):
134 134 """Ask a kernel to shut down by its kernel uuid"""
135 135
136 136 @kernel_method
137 137 def finish_shutdown(self, kernel_id, waittime=1, pollinterval=0.1):
138 138 """Wait for a kernel to finish shutting down, and kill it if it doesn't
139 139 """
140 140 self.log.info("Kernel shutdown: %s" % kernel_id)
141 141
142 142 @kernel_method
143 143 def cleanup(self, kernel_id, connection_file=True):
144 144 """Clean up a kernel's resources"""
145 145
146 146 def remove_kernel(self, kernel_id):
147 147 """remove a kernel from our mapping.
148 148
149 149 Mainly so that a kernel can be removed if it is already dead,
150 150 without having to call shutdown_kernel.
151 151
152 152 The kernel object is returned.
153 153 """
154 154 return self._kernels.pop(kernel_id)
155 155
156 156 def shutdown_all(self, now=False):
157 157 """Shutdown all kernels."""
158 158 kids = self.list_kernel_ids()
159 159 for kid in kids:
160 160 self.request_shutdown(kid)
161 161 for kid in kids:
162 162 self.finish_shutdown(kid)
163 163 self.cleanup(kid)
164 self.remove_kernel(kid)
164 165
165 166 @kernel_method
166 167 def interrupt_kernel(self, kernel_id):
167 168 """Interrupt (SIGINT) the kernel by its uuid.
168 169
169 170 Parameters
170 171 ==========
171 172 kernel_id : uuid
172 173 The id of the kernel to interrupt.
173 174 """
174 175 self.log.info("Kernel interrupted: %s" % kernel_id)
175 176
176 177 @kernel_method
177 178 def signal_kernel(self, kernel_id, signum):
178 179 """Sends a signal to the kernel by its uuid.
179 180
180 181 Note that since only SIGTERM is supported on Windows, this function
181 182 is only useful on Unix systems.
182 183
183 184 Parameters
184 185 ==========
185 186 kernel_id : uuid
186 187 The id of the kernel to signal.
187 188 """
188 189 self.log.info("Signaled Kernel %s with %s" % (kernel_id, signum))
189 190
190 191 @kernel_method
191 192 def restart_kernel(self, kernel_id, now=False):
192 193 """Restart a kernel by its uuid, keeping the same ports.
193 194
194 195 Parameters
195 196 ==========
196 197 kernel_id : uuid
197 198 The id of the kernel to interrupt.
198 199 """
199 200 self.log.info("Kernel restarted: %s" % kernel_id)
200 201
201 202 @kernel_method
202 203 def is_alive(self, kernel_id):
203 204 """Is the kernel alive.
204 205
205 206 This calls KernelManager.is_alive() which calls Popen.poll on the
206 207 actual kernel subprocess.
207 208
208 209 Parameters
209 210 ==========
210 211 kernel_id : uuid
211 212 The id of the kernel.
212 213 """
213 214
214 215 def _check_kernel_id(self, kernel_id):
215 216 """check that a kernel id is valid"""
216 217 if kernel_id not in self:
217 218 raise KeyError("Kernel with id not found: %s" % kernel_id)
218 219
219 220 def get_kernel(self, kernel_id):
220 221 """Get the single KernelManager object for a kernel by its uuid.
221 222
222 223 Parameters
223 224 ==========
224 225 kernel_id : uuid
225 226 The id of the kernel.
226 227 """
227 228 self._check_kernel_id(kernel_id)
228 229 return self._kernels[kernel_id]
229 230
230 231 @kernel_method
231 232 def add_restart_callback(self, kernel_id, callback, event='restart'):
232 233 """add a callback for the KernelRestarter"""
233 234
234 235 @kernel_method
235 236 def remove_restart_callback(self, kernel_id, callback, event='restart'):
236 237 """remove a callback for the KernelRestarter"""
237 238
238 239 @kernel_method
239 240 def get_connection_info(self, kernel_id):
240 241 """Return a dictionary of connection data for a kernel.
241 242
242 243 Parameters
243 244 ==========
244 245 kernel_id : uuid
245 246 The id of the kernel.
246 247
247 248 Returns
248 249 =======
249 250 connection_dict : dict
250 251 A dict of the information needed to connect to a kernel.
251 252 This includes the ip address and the integer port
252 253 numbers of the different channels (stdin_port, iopub_port,
253 254 shell_port, hb_port).
254 255 """
255 256
256 257 @kernel_method
257 258 def connect_iopub(self, kernel_id, identity=None):
258 259 """Return a zmq Socket connected to the iopub channel.
259 260
260 261 Parameters
261 262 ==========
262 263 kernel_id : uuid
263 264 The id of the kernel
264 265 identity : bytes (optional)
265 266 The zmq identity of the socket
266 267
267 268 Returns
268 269 =======
269 270 stream : zmq Socket or ZMQStream
270 271 """
271 272
272 273 @kernel_method
273 274 def connect_shell(self, kernel_id, identity=None):
274 275 """Return a zmq Socket connected to the shell channel.
275 276
276 277 Parameters
277 278 ==========
278 279 kernel_id : uuid
279 280 The id of the kernel
280 281 identity : bytes (optional)
281 282 The zmq identity of the socket
282 283
283 284 Returns
284 285 =======
285 286 stream : zmq Socket or ZMQStream
286 287 """
287 288
288 289 @kernel_method
289 290 def connect_stdin(self, kernel_id, identity=None):
290 291 """Return a zmq Socket connected to the stdin channel.
291 292
292 293 Parameters
293 294 ==========
294 295 kernel_id : uuid
295 296 The id of the kernel
296 297 identity : bytes (optional)
297 298 The zmq identity of the socket
298 299
299 300 Returns
300 301 =======
301 302 stream : zmq Socket or ZMQStream
302 303 """
303 304
304 305 @kernel_method
305 306 def connect_hb(self, kernel_id, identity=None):
306 307 """Return a zmq Socket connected to the hb channel.
307 308
308 309 Parameters
309 310 ==========
310 311 kernel_id : uuid
311 312 The id of the kernel
312 313 identity : bytes (optional)
313 314 The zmq identity of the socket
314 315
315 316 Returns
316 317 =======
317 318 stream : zmq Socket or ZMQStream
318 319 """
General Comments 0
You need to be logged in to leave comments. Login now