kernelmanager.py
135 lines
| 5.2 KiB
| text/x-python
|
PythonLexer
MinRK
|
r9371 | """A kernel manager relating notebooks and kernels | ||
Brian E. Granger
|
r4609 | |||
Authors: | ||||
* Brian Granger | ||||
""" | ||||
Brian E. Granger
|
r4343 | |||
Brian E. Granger
|
r4344 | #----------------------------------------------------------------------------- | ||
MinRK
|
r9371 | # Copyright (C) 2013 The IPython Development Team | ||
Brian E. Granger
|
r4348 | # | ||
# Distributed under the terms of the BSD License. The full license is in | ||||
Brian E. Granger
|
r4609 | # the file COPYING, distributed as part of this software. | ||
Brian E. Granger
|
r4348 | #----------------------------------------------------------------------------- | ||
#----------------------------------------------------------------------------- | ||||
Brian E. Granger
|
r4344 | # Imports | ||
#----------------------------------------------------------------------------- | ||||
MinRK
|
r15420 | import os | ||
Brian E. Granger
|
r4494 | from tornado import web | ||
MinRK
|
r9371 | from IPython.kernel.multikernelmanager import MultiKernelManager | ||
Spencer Nelson
|
r16525 | from IPython.utils.traitlets import List, Unicode, TraitError | ||
Brian E. Granger
|
r10273 | |||
MinRK
|
r15420 | from IPython.html.utils import to_os_path | ||
from IPython.utils.py3compat import getcwd | ||||
Brian E. Granger
|
r4344 | #----------------------------------------------------------------------------- | ||
# Classes | ||||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r4297 | |||
Brian E. Granger
|
r4545 | |||
MinRK
|
r4960 | class MappingKernelManager(MultiKernelManager): | ||
MinRK
|
r10355 | """A KernelManager that handles notebook mapping and HTTP error handling""" | ||
Brian E. Granger
|
r4494 | |||
MinRK
|
r10295 | def _kernel_manager_class_default(self): | ||
return "IPython.kernel.ioloop.IOLoopKernelManager" | ||||
Brian E. Granger
|
r4494 | kernel_argv = List(Unicode) | ||
Dale Jung
|
r16052 | |||
MinRK
|
r15420 | root_dir = Unicode(getcwd(), config=True) | ||
def _root_dir_changed(self, name, old, new): | ||||
"""Do a bit of validation of the root dir.""" | ||||
if not os.path.isabs(new): | ||||
# If we receive a non-absolute path, make it absolute. | ||||
self.root_dir = os.path.abspath(new) | ||||
return | ||||
if not os.path.exists(new) or not os.path.isdir(new): | ||||
raise TraitError("kernel root dir %r is not a directory" % new) | ||||
Brian E. Granger
|
r4494 | |||
#------------------------------------------------------------------------- | ||||
# Methods for managing kernels and sessions | ||||
#------------------------------------------------------------------------- | ||||
MinRK
|
r10321 | def _handle_kernel_died(self, kernel_id): | ||
"""notice that a kernel died""" | ||||
self.log.warn("Kernel %s died, removing from map.", kernel_id) | ||||
Thomas Kluyver
|
r11074 | self.remove_kernel(kernel_id) | ||
Dale Jung
|
r16052 | |||
MinRK
|
r15420 | def cwd_for_path(self, path): | ||
"""Turn API path into absolute OS path.""" | ||||
Dale Jung
|
r16052 | # short circuit for NotebookManagers that pass in absolute paths | ||
if os.path.exists(path): | ||||
return path | ||||
MinRK
|
r15420 | os_path = to_os_path(path, self.root_dir) | ||
# in the case of notebooks and kernels not being on the same filesystem, | ||||
# walk up to root_dir if the paths don't exist | ||||
while not os.path.exists(os_path) and os_path != self.root_dir: | ||||
os_path = os.path.dirname(os_path) | ||||
return os_path | ||||
Thomas Kluyver
|
r17221 | def start_kernel(self, kernel_id=None, path=None, kernel_name='python', **kwargs): | ||
"""Start a kernel for a session and return its kernel_id. | ||||
Brian E. Granger
|
r4495 | |||
Parameters | ||||
---------- | ||||
Zachary Sailer
|
r13035 | kernel_id : uuid | ||
The uuid to associate the new kernel with. If this | ||||
Dale Jung
|
r16052 | is not None, this kernel will be persistent whenever it is | ||
Zachary Sailer
|
r13035 | requested. | ||
MinRK
|
r15420 | path : API path | ||
The API path (unicode, '/' delimited) for the cwd. | ||||
Will be transformed to an OS path relative to root_dir. | ||||
Thomas Kluyver
|
r17221 | kernel_name : str | ||
The name identifying which kernel spec to launch. This is ignored if | ||||
an existing kernel is returned, but it may be checked in the future. | ||||
Brian E. Granger
|
r4495 | """ | ||
Brian E. Granger
|
r4494 | if kernel_id is None: | ||
kwargs['extra_arguments'] = self.kernel_argv | ||||
MinRK
|
r15420 | if path is not None: | ||
kwargs['cwd'] = self.cwd_for_path(path) | ||||
Thomas Kluyver
|
r17221 | kernel_id = super(MappingKernelManager, self).start_kernel( | ||
kernel_name=kernel_name, **kwargs) | ||||
Brian E. Granger
|
r4495 | self.log.info("Kernel started: %s" % kernel_id) | ||
Brian E. Granger
|
r4494 | self.log.debug("Kernel args: %r" % kwargs) | ||
MinRK
|
r10321 | # register callback for failed auto-restart | ||
self.add_restart_callback(kernel_id, | ||||
lambda : self._handle_kernel_died(kernel_id), | ||||
'dead', | ||||
) | ||||
Brian E. Granger
|
r4494 | else: | ||
Zachary Sailer
|
r13058 | self._check_kernel_id(kernel_id) | ||
Brian E. Granger
|
r4494 | self.log.info("Using existing kernel: %s" % kernel_id) | ||
return kernel_id | ||||
MinRK
|
r10330 | def shutdown_kernel(self, kernel_id, now=False): | ||
"""Shutdown a kernel by kernel_id""" | ||||
Zachary Sailer
|
r13058 | self._check_kernel_id(kernel_id) | ||
MinRK
|
r10330 | super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now) | ||
Zachary Sailer
|
r12983 | |||
MinRK
|
r15400 | def kernel_model(self, kernel_id): | ||
Zachary Sailer
|
r13037 | """Return a dictionary of kernel information described in the | ||
JSON standard model.""" | ||||
Zachary Sailer
|
r13058 | self._check_kernel_id(kernel_id) | ||
Thomas Kluyver
|
r17221 | model = {"id":kernel_id, | ||
"name": self._kernels[kernel_id].kernel_name} | ||||
Zachary Sailer
|
r12983 | return model | ||
MinRK
|
r15400 | def list_kernels(self): | ||
Zachary Sailer
|
r13037 | """Returns a list of kernel_id's of kernels running.""" | ||
Zachary Sailer
|
r13052 | kernels = [] | ||
kernel_ids = super(MappingKernelManager, self).list_kernel_ids() | ||||
for kernel_id in kernel_ids: | ||||
MinRK
|
r15400 | model = self.kernel_model(kernel_id) | ||
Zachary Sailer
|
r13052 | kernels.append(model) | ||
return kernels | ||||
MinRK
|
r10330 | |||
MinRK
|
r10295 | # override _check_kernel_id to raise 404 instead of KeyError | ||
Brian E. Granger
|
r4676 | def _check_kernel_id(self, kernel_id): | ||
"""Check a that a kernel_id exists and raise 404 if not.""" | ||||
if kernel_id not in self: | ||||
raise web.HTTPError(404, u'Kernel does not exist: %s' % kernel_id) | ||||