##// END OF EJS Templates
BUG: Allow %magic argument filenames with spaces to be specified with quotes under win32.
BUG: Allow %magic argument filenames with spaces to be specified with quotes under win32.

File last commit:

r4676:a6875a65
r4688:de1bf8aa
Show More
kernelmanager.py
326 lines | 11.3 KiB | text/x-python | PythonLexer
Brian E. Granger
More review changes....
r4609 """A kernel manager for multiple kernels.
Authors:
* Brian Granger
"""
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343
Brian E. Granger
Refactoring the notebook app to support the new config system.
r4344 #-----------------------------------------------------------------------------
Brian E. Granger
More review changes....
r4609 # Copyright (C) 2008-2011 The IPython Development Team
Brian E. Granger
Updating the notebook to work with the latex master....
r4348 #
# Distributed under the terms of the BSD License. The full license is in
Brian E. Granger
More review changes....
r4609 # the file COPYING, distributed as part of this software.
Brian E. Granger
Updating the notebook to work with the latex master....
r4348 #-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
Brian E. Granger
Refactoring the notebook app to support the new config system.
r4344 # Imports
#-----------------------------------------------------------------------------
Brian Granger
Work on the server side of the html notebook.
r4297 import signal
import sys
Brian Granger
Different clients now share a single zmq session....
r4306 import uuid
Brian Granger
Work on the server side of the html notebook.
r4297
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 import zmq
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 from zmq.eventloop.zmqstream import ZMQStream
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343
Brian E. Granger
Adding kernel/notebook associations.
r4494 from tornado import web
Brian E. Granger
Notebook app debugging....
r4345 from IPython.config.configurable import LoggingConfigurable
Brian Granger
Work on the server side of the html notebook.
r4297 from IPython.zmq.ipkernel import launch_kernel
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 from IPython.utils.traitlets import Instance, Dict, List, Unicode, Float, Int
Brian Granger
Work on the server side of the html notebook.
r4297
Brian E. Granger
Refactoring the notebook app to support the new config system.
r4344 #-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
Brian Granger
Work on the server side of the html notebook.
r4297
Brian Granger
Basic server for htmlnotebook working.
r4298 class DuplicateKernelError(Exception):
pass
Brian E. Granger
Notebook app debugging....
r4345 class KernelManager(LoggingConfigurable):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """A class for managing multiple kernels."""
context = Instance('zmq.Context')
def _context_default(self):
return zmq.Context.instance()
Brian Granger
Work on the server side of the html notebook.
r4297
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 _kernels = Dict()
Brian Granger
Work on the server side of the html notebook.
r4297
@property
def kernel_ids(self):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """Return a list of the kernel ids of the active kernels."""
Brian Granger
Work on the server side of the html notebook.
r4297 return self._kernels.keys()
def __len__(self):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """Return the number of running kernels."""
Brian Granger
Work on the server side of the html notebook.
r4297 return len(self.kernel_ids)
def __contains__(self, kernel_id):
if kernel_id in self.kernel_ids:
return True
else:
return False
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 def start_kernel(self, **kwargs):
"""Start a new kernel."""
Brian E. Granger
Adding kernel/notebook associations.
r4494 kernel_id = unicode(uuid.uuid4())
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(**kwargs)
# Store the information for contacting the kernel. This assumes the kernel is
# running on localhost.
Brian Granger
Work on the server side of the html notebook.
r4297 d = dict(
process = process,
stdin_port = stdin_port,
iopub_port = iopub_port,
shell_port = shell_port,
hb_port = hb_port,
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 ip = '127.0.0.1'
Brian Granger
Work on the server side of the html notebook.
r4297 )
Brian Granger
Basic server for htmlnotebook working.
r4298 self._kernels[kernel_id] = d
return kernel_id
Brian Granger
Work on the server side of the html notebook.
r4297
def kill_kernel(self, kernel_id):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """Kill a kernel by its kernel uuid.
Parameters
==========
kernel_id : uuid
The id of the kernel to kill.
"""
Brian Granger
Work on the server side of the html notebook.
r4297 kernel_process = self.get_kernel_process(kernel_id)
if kernel_process is not None:
# Attempt to kill the kernel.
try:
kernel_process.kill()
except OSError, e:
# In Windows, we will get an Access Denied error if the process
# has already terminated. Ignore it.
if not (sys.platform == 'win32' and e.winerror == 5):
raise
del self._kernels[kernel_id]
def interrupt_kernel(self, kernel_id):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """Interrupt (SIGINT) the kernel by its uuid.
Parameters
==========
kernel_id : uuid
The id of the kernel to interrupt.
"""
Brian Granger
Work on the server side of the html notebook.
r4297 kernel_process = self.get_kernel_process(kernel_id)
if kernel_process is not None:
if sys.platform == 'win32':
from parentpoller import ParentPollerWindows as Poller
Poller.send_interrupt(kernel_process.win32_interrupt_event)
else:
kernel_process.send_signal(signal.SIGINT)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545
Brian Granger
Work on the server side of the html notebook.
r4297 def signal_kernel(self, kernel_id, signum):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """ Sends a signal to the kernel by its uuid.
Note that since only SIGTERM is supported on Windows, this function
is only useful on Unix systems.
Parameters
==========
kernel_id : uuid
The id of the kernel to signal.
Brian Granger
Work on the server side of the html notebook.
r4297 """
kernel_process = self.get_kernel_process(kernel_id)
if kernel_process is not None:
kernel_process.send_signal(signum)
def get_kernel_process(self, kernel_id):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """Get the process object for a kernel by its uuid.
Parameters
==========
kernel_id : uuid
The id of the kernel.
"""
Brian Granger
Work on the server side of the html notebook.
r4297 d = self._kernels.get(kernel_id)
if d is not None:
return d['process']
else:
raise KeyError("Kernel with id not found: %s" % kernel_id)
def get_kernel_ports(self, kernel_id):
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 """Return a dictionary of ports for a kernel.
Parameters
==========
kernel_id : uuid
The id of the kernel.
Returns
=======
port_dict : dict
A dict of key, value pairs where the keys are the names
(stdin_port,iopub_port,shell_port) and the values are the
integer port numbers for those channels.
"""
Brian Granger
Work on the server side of the html notebook.
r4297 d = self._kernels.get(kernel_id)
if d is not None:
dcopy = d.copy()
dcopy.pop('process')
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 dcopy.pop('ip')
Brian Granger
Work on the server side of the html notebook.
r4297 return dcopy
else:
raise KeyError("Kernel with id not found: %s" % kernel_id)
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 def get_kernel_ip(self, kernel_id):
"""Return ip address for a kernel.
Parameters
==========
kernel_id : uuid
The id of the kernel.
Returns
=======
ip : str
The ip address of the kernel.
"""
Brian Granger
Work on the server side of the html notebook.
r4297 d = self._kernels.get(kernel_id)
if d is not None:
Brian E. Granger
Refactored htmlnotebook session and kernel manager....
r4343 return d['ip']
Brian Granger
Work on the server side of the html notebook.
r4297 else:
raise KeyError("Kernel with id not found: %s" % kernel_id)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 def create_connected_stream(self, ip, port, socket_type):
sock = self.context.socket(socket_type)
addr = "tcp://%s:%i" % (ip, port)
self.log.info("Connecting to: %s" % addr)
sock.connect(addr)
return ZMQStream(sock)
def create_iopub_stream(self, kernel_id):
ip = self.get_kernel_ip(kernel_id)
ports = self.get_kernel_ports(kernel_id)
iopub_stream = self.create_connected_stream(ip, ports['iopub_port'], zmq.SUB)
iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
return iopub_stream
Brian Granger
Work on the server side of the html notebook.
r4297
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 def create_shell_stream(self, kernel_id):
ip = self.get_kernel_ip(kernel_id)
ports = self.get_kernel_ports(kernel_id)
shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.XREQ)
return shell_stream
Brian E. Granger
Adding kernel/notebook associations.
r4494
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 def create_hb_stream(self, kernel_id):
ip = self.get_kernel_ip(kernel_id)
ports = self.get_kernel_ports(kernel_id)
hb_stream = self.create_connected_stream(ip, ports['hb_port'], zmq.REQ)
return hb_stream
class MappingKernelManager(KernelManager):
"""A KernelManager that handles notebok mapping and HTTP error handling"""
Brian E. Granger
Adding kernel/notebook associations.
r4494
kernel_argv = List(Unicode)
kernel_manager = Instance(KernelManager)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 time_to_dead = Float(3.0, config=True, help="""Kernel heartbeat interval in seconds.""")
max_msg_size = Int(65536, config=True, help="""
The max raw message size accepted from the browser
over a WebSocket connection.
""")
Brian E. Granger
Adding kernel/notebook associations.
r4494
_notebook_mapping = Dict()
#-------------------------------------------------------------------------
# Methods for managing kernels and sessions
#-------------------------------------------------------------------------
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 def kernel_for_notebook(self, notebook_id):
"""Return the kernel_id for a notebook_id or None."""
return self._notebook_mapping.get(notebook_id)
def set_kernel_for_notebook(self, notebook_id, kernel_id):
"""Associate a notebook with a kernel."""
if notebook_id is not None:
self._notebook_mapping[notebook_id] = kernel_id
Brian E. Granger
Adding kernel/notebook associations.
r4494 def notebook_for_kernel(self, kernel_id):
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 """Return the notebook_id for a kernel_id or None."""
Brian E. Granger
Adding kernel/notebook associations.
r4494 notebook_ids = [k for k, v in self._notebook_mapping.iteritems() if v == kernel_id]
if len(notebook_ids) == 1:
return notebook_ids[0]
else:
return None
def delete_mapping_for_kernel(self, kernel_id):
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 """Remove the kernel/notebook mapping for kernel_id."""
Brian E. Granger
Adding kernel/notebook associations.
r4494 notebook_id = self.notebook_for_kernel(kernel_id)
if notebook_id is not None:
del self._notebook_mapping[notebook_id]
def start_kernel(self, notebook_id=None):
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 """Start a kernel for a notebok an return its kernel_id.
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495
Parameters
----------
notebook_id : uuid
The uuid of the notebook to associate the new kernel with. If this
is not None, this kernel will be persistent whenever the notebook
requests a kernel.
"""
kernel_id = self.kernel_for_notebook(notebook_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494 if kernel_id is None:
kwargs = dict()
kwargs['extra_arguments'] = self.kernel_argv
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 kernel_id = super(MappingKernelManager, self).start_kernel(**kwargs)
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 self.set_kernel_for_notebook(notebook_id, kernel_id)
self.log.info("Kernel started: %s" % kernel_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494 self.log.debug("Kernel args: %r" % kwargs)
else:
self.log.info("Using existing kernel: %s" % kernel_id)
return kernel_id
def kill_kernel(self, kernel_id):
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 """Kill a kernel and remove its notebook association."""
Brian E. Granger
Adding messages to HTTPError raising....
r4676 self._check_kernel_id(kernel_id)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 super(MappingKernelManager, self).kill_kernel(kernel_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494 self.delete_mapping_for_kernel(kernel_id)
self.log.info("Kernel killed: %s" % kernel_id)
def interrupt_kernel(self, kernel_id):
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 """Interrupt a kernel."""
Brian E. Granger
Adding messages to HTTPError raising....
r4676 self._check_kernel_id(kernel_id)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 super(MappingKernelManager, self).interrupt_kernel(kernel_id)
self.log.info("Kernel interrupted: %s" % kernel_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494
def restart_kernel(self, kernel_id):
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 """Restart a kernel while keeping clients connected."""
Brian E. Granger
Adding messages to HTTPError raising....
r4676 self._check_kernel_id(kernel_id)
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 # Get the notebook_id to preserve the kernel/notebook association.
Brian E. Granger
Adding kernel/notebook associations.
r4494 notebook_id = self.notebook_for_kernel(kernel_id)
# Create the new kernel first so we can move the clients over.
new_kernel_id = self.start_kernel()
Brian E. Granger
Major refactor of kernel connection management in the notebook....
r4545 # Now kill the old kernel.
Brian E. Granger
Adding kernel/notebook associations.
r4494 self.kill_kernel(kernel_id)
# Now save the new kernel/notebook association. We have to save it
# after the old kernel is killed as that will delete the mapping.
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495 self.set_kernel_for_notebook(notebook_id, new_kernel_id)
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 self.log.info("Kernel restarted: %s" % new_kernel_id)
Brian E. Granger
Adding kernel/notebook associations.
r4494 return new_kernel_id
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 def create_iopub_stream(self, kernel_id):
Brian E. Granger
Adding messages to HTTPError raising....
r4676 """Create a new iopub stream."""
self._check_kernel_id(kernel_id)
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 return super(MappingKernelManager, self).create_iopub_stream(kernel_id)
def create_shell_stream(self, kernel_id):
Brian E. Granger
Adding messages to HTTPError raising....
r4676 """Create a new shell stream."""
self._check_kernel_id(kernel_id)
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 return super(MappingKernelManager, self).create_shell_stream(kernel_id)
def create_hb_stream(self, kernel_id):
Brian E. Granger
Adding messages to HTTPError raising....
r4676 """Create a new hb stream."""
self._check_kernel_id(kernel_id)
Brian E. Granger
WebSocket url is now passed to browser when a kernel is started.
r4572 return super(MappingKernelManager, self).create_hb_stream(kernel_id)
Brian E. Granger
Fixed subtle bug in kernel restarting....
r4495
Brian E. Granger
Adding messages to HTTPError raising....
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)