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