From 49d3c39a6f6510692ae4b825d06c4a197040a1f0 2013-04-24 04:47:46 From: MinRK Date: 2013-04-24 04:47:46 Subject: [PATCH] update inprocess kernel to new layout including Qt mixins --- diff --git a/IPython/frontend/qt/inprocess_kernelmanager.py b/IPython/frontend/qt/inprocess.py similarity index 73% rename from IPython/frontend/qt/inprocess_kernelmanager.py rename to IPython/frontend/qt/inprocess.py index 326a5e1..26e25a9 100644 --- a/IPython/frontend/qt/inprocess_kernelmanager.py +++ b/IPython/frontend/qt/inprocess.py @@ -2,12 +2,14 @@ """ # Local imports. -from IPython.kernel.inprocess.kernelmanager import \ - InProcessShellChannel, InProcessIOPubChannel, InProcessStdInChannel, \ - InProcessHBChannel, InProcessKernelManager +from IPython.kernel.inprocess import ( + InProcessShellChannel, InProcessIOPubChannel, InProcessStdInChannel, + InProcessHBChannel, InProcessKernelClient +) + from IPython.utils.traitlets import Type -from base_kernelmanager import QtShellChannelMixin, QtIOPubChannelMixin, \ - QtStdInChannelMixin, QtHBChannelMixin, QtKernelManagerMixin +from kernel_mixins import QtShellChannelMixin, QtIOPubChannelMixin, \ + QtStdInChannelMixin, QtHBChannelMixin, QtKernelClientMixin class QtInProcessShellChannel(QtShellChannelMixin, InProcessShellChannel): @@ -22,8 +24,7 @@ class QtInProcessStdInChannel(QtStdInChannelMixin, InProcessStdInChannel): class QtInProcessHBChannel(QtHBChannelMixin, InProcessHBChannel): pass - -class QtInProcessKernelManager(QtKernelManagerMixin, InProcessKernelManager): +class QtInProcessKernelClient(QtKernelClientMixin, InProcessKernelClient): """ An in-process KernelManager with signals and slots. """ diff --git a/IPython/kernel/inprocess/__init__.py b/IPython/kernel/inprocess/__init__.py index e69de29..278666b 100644 --- a/IPython/kernel/inprocess/__init__.py +++ b/IPython/kernel/inprocess/__init__.py @@ -0,0 +1,8 @@ +from .channels import ( + InProcessShellChannel, + InProcessIOPubChannel, + InProcessStdInChannel, + InProcessHBChannel, +) +from .client import InProcessKernelClient +from .manager import InProcessKernelManager \ No newline at end of file diff --git a/IPython/kernel/inprocess/blockingkernelmanager.py b/IPython/kernel/inprocess/blocking.py similarity index 78% rename from IPython/kernel/inprocess/blockingkernelmanager.py rename to IPython/kernel/inprocess/blocking.py index e001073..91042c9 100644 --- a/IPython/kernel/inprocess/blockingkernelmanager.py +++ b/IPython/kernel/inprocess/blocking.py @@ -1,4 +1,4 @@ -""" Implements a fully blocking kernel manager. +""" Implements a fully blocking kernel client. Useful for test suites and blocking terminal interfaces. """ @@ -12,15 +12,19 @@ Useful for test suites and blocking terminal interfaces. #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- -from __future__ import print_function -# Local imports. +# IPython imports from IPython.utils.io import raw_print from IPython.utils.traitlets import Type -from kernelmanager import InProcessKernelManager, InProcessShellChannel, \ - InProcessIOPubChannel, InProcessStdInChannel -from IPython.kernel.blockingkernelmanager import BlockingChannelMixin +from IPython.kernel.blocking.channels import BlockingChannelMixin +# Local imports +from .channels import ( + InProcessShellChannel, + InProcessIOPubChannel, + InProcessStdInChannel, +) +from .client import InProcessKernelClient #----------------------------------------------------------------------------- # Blocking kernel manager @@ -33,7 +37,7 @@ class BlockingInProcessIOPubChannel(BlockingChannelMixin, InProcessIOPubChannel) pass class BlockingInProcessStdInChannel(BlockingChannelMixin, InProcessStdInChannel): - + def call_handlers(self, msg): """ Overridden for the in-process channel. @@ -41,12 +45,12 @@ class BlockingInProcessStdInChannel(BlockingChannelMixin, InProcessStdInChannel) """ msg_type = msg['header']['msg_type'] if msg_type == 'input_request': - _raw_input = self.manager.kernel._sys_raw_input + _raw_input = self.client.kernel._sys_raw_input prompt = msg['content']['prompt'] raw_print(prompt, end='') self.input(_raw_input()) -class BlockingInProcessKernelManager(InProcessKernelManager): +class BlockingInProcessKernelClient(InProcessKernelClient): # The classes to use for the various channels. shell_channel_class = Type(BlockingInProcessShellChannel) diff --git a/IPython/kernel/inprocess/channels.py b/IPython/kernel/inprocess/channels.py new file mode 100644 index 0000000..348bfbe --- /dev/null +++ b/IPython/kernel/inprocess/channels.py @@ -0,0 +1,194 @@ +""" A kernel client for in-process kernels. """ + +#----------------------------------------------------------------------------- +# Copyright (C) 2012 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# IPython imports +from IPython.kernel.channelabc import ( + ShellChannelABC, IOPubChannelABC, + HBChannelABC, StdInChannelABC, +) + +# Local imports +from .socket import DummySocket + +#----------------------------------------------------------------------------- +# Channel classes +#----------------------------------------------------------------------------- + +class InProcessChannel(object): + """Base class for in-process channels.""" + proxy_methods = [] + + def __init__(self, client): + super(InProcessChannel, self).__init__() + self.client = client + self._is_alive = False + + #-------------------------------------------------------------------------- + # Channel interface + #-------------------------------------------------------------------------- + + def is_alive(self): + return self._is_alive + + def start(self): + self._is_alive = True + + def stop(self): + self._is_alive = False + + def call_handlers(self, msg): + """ This method is called in the main thread when a message arrives. + + Subclasses should override this method to handle incoming messages. + """ + raise NotImplementedError('call_handlers must be defined in a subclass.') + + #-------------------------------------------------------------------------- + # InProcessChannel interface + #-------------------------------------------------------------------------- + + def call_handlers_later(self, *args, **kwds): + """ Call the message handlers later. + + The default implementation just calls the handlers immediately, but this + method exists so that GUI toolkits can defer calling the handlers until + after the event loop has run, as expected by GUI frontends. + """ + self.call_handlers(*args, **kwds) + + def process_events(self): + """ Process any pending GUI events. + + This method will be never be called from a frontend without an event + loop (e.g., a terminal frontend). + """ + raise NotImplementedError + + +class InProcessShellChannel(InProcessChannel): + """See `IPython.kernel.channels.ShellChannel` for docstrings.""" + + # flag for whether execute requests should be allowed to call raw_input + allow_stdin = True + proxy_methods = [ + 'execute', + 'complete', + 'object_info', + 'history', + 'shutdown', + ] + + #-------------------------------------------------------------------------- + # ShellChannel interface + #-------------------------------------------------------------------------- + + def execute(self, code, silent=False, store_history=True, + user_variables=[], user_expressions={}, allow_stdin=None): + if allow_stdin is None: + allow_stdin = self.allow_stdin + content = dict(code=code, silent=silent, store_history=store_history, + user_variables=user_variables, + user_expressions=user_expressions, + allow_stdin=allow_stdin) + msg = self.client.session.msg('execute_request', content) + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def complete(self, text, line, cursor_pos, block=None): + content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos) + msg = self.client.session.msg('complete_request', content) + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def object_info(self, oname, detail_level=0): + content = dict(oname=oname, detail_level=detail_level) + msg = self.client.session.msg('object_info_request', content) + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def history(self, raw=True, output=False, hist_access_type='range', **kwds): + content = dict(raw=raw, output=output, + hist_access_type=hist_access_type, **kwds) + msg = self.client.session.msg('history_request', content) + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def shutdown(self, restart=False): + # FIXME: What to do here? + raise NotImplementedError('Cannot shutdown in-process kernel') + + #-------------------------------------------------------------------------- + # Protected interface + #-------------------------------------------------------------------------- + + def _dispatch_to_kernel(self, msg): + """ Send a message to the kernel and handle a reply. + """ + kernel = self.client.kernel + if kernel is None: + raise RuntimeError('Cannot send request. No kernel exists.') + + stream = DummySocket() + self.client.session.send(stream, msg) + msg_parts = stream.recv_multipart() + kernel.dispatch_shell(stream, msg_parts) + + idents, reply_msg = self.client.session.recv(stream, copy=False) + self.call_handlers_later(reply_msg) + + +class InProcessIOPubChannel(InProcessChannel): + """See `IPython.kernel.channels.IOPubChannel` for docstrings.""" + + def flush(self, timeout=1.0): + pass + + +class InProcessStdInChannel(InProcessChannel): + """See `IPython.kernel.channels.StdInChannel` for docstrings.""" + + proxy_methods = ['input'] + + def input(self, string): + kernel = self.client.kernel + if kernel is None: + raise RuntimeError('Cannot send input reply. No kernel exists.') + kernel.raw_input_str = string + + +class InProcessHBChannel(InProcessChannel): + """See `IPython.kernel.channels.HBChannel` for docstrings.""" + + time_to_dead = 3.0 + + def __init__(self, *args, **kwds): + super(InProcessHBChannel, self).__init__(*args, **kwds) + self._pause = True + + def pause(self): + self._pause = True + + def unpause(self): + self._pause = False + + def is_beating(self): + return not self._pause + +#----------------------------------------------------------------------------- +# ABC Registration +#----------------------------------------------------------------------------- + +ShellChannelABC.register(InProcessShellChannel) +IOPubChannelABC.register(InProcessIOPubChannel) +HBChannelABC.register(InProcessHBChannel) +StdInChannelABC.register(InProcessStdInChannel) diff --git a/IPython/kernel/inprocess/client.py b/IPython/kernel/inprocess/client.py index 4b33a4a..2ec276e 100644 --- a/IPython/kernel/inprocess/client.py +++ b/IPython/kernel/inprocess/client.py @@ -1,4 +1,4 @@ -""" A kernel manager for in-process kernels. """ +"""A client for in-process kernels.""" #----------------------------------------------------------------------------- # Copyright (C) 2012 The IPython Development Team @@ -11,238 +11,49 @@ # Imports #----------------------------------------------------------------------------- -# Local imports. -from IPython.config.configurable import Configurable -from IPython.utils.traitlets import Any, Instance, Type -from IPython.kernel.kernelmanagerabc import ( - ShellChannelABC, IOPubChannelABC, - HBChannelABC, StdInChannelABC, - KernelManagerABC -) - -from .socket import DummySocket - -#----------------------------------------------------------------------------- -# Channel classes -#----------------------------------------------------------------------------- - -class InProcessChannel(object): - """Base class for in-process channels.""" - - def __init__(self, manager): - super(InProcessChannel, self).__init__() - self.manager = manager - self._is_alive = False - - #-------------------------------------------------------------------------- - # Channel interface - #-------------------------------------------------------------------------- - - def is_alive(self): - return self._is_alive - - def start(self): - self._is_alive = True - - def stop(self): - self._is_alive = False - - def call_handlers(self, msg): - """ This method is called in the main thread when a message arrives. - - Subclasses should override this method to handle incoming messages. - """ - raise NotImplementedError('call_handlers must be defined in a subclass.') - - #-------------------------------------------------------------------------- - # InProcessChannel interface - #-------------------------------------------------------------------------- - - def call_handlers_later(self, *args, **kwds): - """ Call the message handlers later. - - The default implementation just calls the handlers immediately, but this - method exists so that GUI toolkits can defer calling the handlers until - after the event loop has run, as expected by GUI frontends. - """ - self.call_handlers(*args, **kwds) - - def process_events(self): - """ Process any pending GUI events. - - This method will be never be called from a frontend without an event - loop (e.g., a terminal frontend). - """ - raise NotImplementedError - - -class InProcessShellChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.ShellChannel` for docstrings.""" - - # flag for whether execute requests should be allowed to call raw_input - allow_stdin = True - - #-------------------------------------------------------------------------- - # ShellChannel interface - #-------------------------------------------------------------------------- - - def execute(self, code, silent=False, store_history=True, - user_variables=[], user_expressions={}, allow_stdin=None): - if allow_stdin is None: - allow_stdin = self.allow_stdin - content = dict(code=code, silent=silent, store_history=store_history, - user_variables=user_variables, - user_expressions=user_expressions, - allow_stdin=allow_stdin) - msg = self.manager.session.msg('execute_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def complete(self, text, line, cursor_pos, block=None): - content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos) - msg = self.manager.session.msg('complete_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def object_info(self, oname, detail_level=0): - content = dict(oname=oname, detail_level=detail_level) - msg = self.manager.session.msg('object_info_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def history(self, raw=True, output=False, hist_access_type='range', **kwds): - content = dict(raw=raw, output=output, - hist_access_type=hist_access_type, **kwds) - msg = self.manager.session.msg('history_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def shutdown(self, restart=False): - # FIXME: What to do here? - raise NotImplementedError('Cannot shutdown in-process kernel') - - #-------------------------------------------------------------------------- - # Protected interface - #-------------------------------------------------------------------------- +# IPython imports +from IPython.utils.traitlets import Type, Instance +from IPython.kernel.clientabc import KernelClientABC +from IPython.kernel.client import KernelClient - def _dispatch_to_kernel(self, msg): - """ Send a message to the kernel and handle a reply. - """ - kernel = self.manager.kernel - if kernel is None: - raise RuntimeError('Cannot send request. No kernel exists.') - - stream = DummySocket() - self.manager.session.send(stream, msg) - msg_parts = stream.recv_multipart() - kernel.dispatch_shell(stream, msg_parts) - - idents, reply_msg = self.manager.session.recv(stream, copy=False) - self.call_handlers_later(reply_msg) - - -class InProcessIOPubChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.IOPubChannel` for docstrings.""" - - def flush(self, timeout=1.0): - pass - - -class InProcessStdInChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.StdInChannel` for docstrings.""" - - def input(self, string): - kernel = self.manager.kernel - if kernel is None: - raise RuntimeError('Cannot send input reply. No kernel exists.') - kernel.raw_input_str = string - - -class InProcessHBChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.HBChannel` for docstrings.""" - - time_to_dead = 3.0 - - def __init__(self, *args, **kwds): - super(InProcessHBChannel, self).__init__(*args, **kwds) - self._pause = True - - def pause(self): - self._pause = True - - def unpause(self): - self._pause = False - - def is_beating(self): - return not self._pause +# Local imports +from .channels import ( + InProcessShellChannel, + InProcessIOPubChannel, + InProcessHBChannel, + InProcessStdInChannel, +) #----------------------------------------------------------------------------- -# Main kernel manager class +# Main kernel Client class #----------------------------------------------------------------------------- -class InProcessKernelManager(KernelManager): - """A manager for an in-process kernel. +class InProcessKernelClient(KernelClient): + """A client for an in-process kernel. This class implements the interface of - `IPython.kernel.kernelmanagerabc.KernelManagerABC` and allows + `IPython.kernel.clientabc.KernelClientABC` and allows (asynchronous) frontends to be used seamlessly with an in-process kernel. - See `IPython.kernel.kernelmanager.KernelManager` for docstrings. + See `IPython.kernel.client.KernelClient` for docstrings. """ - # The Session to use for building messages. - session = Instance('IPython.kernel.zmq.session.Session') - def _session_default(self): - from IPython.kernel.zmq.session import Session - return Session(config=self.config) - - # The kernel process with which the KernelManager is communicating. - kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel') - # The classes to use for the various channels. shell_channel_class = Type(InProcessShellChannel) iopub_channel_class = Type(InProcessIOPubChannel) stdin_channel_class = Type(InProcessStdInChannel) hb_channel_class = Type(InProcessHBChannel) - # Protected traits. - _shell_channel = Any - _iopub_channel = Any - _stdin_channel = Any - _hb_channel = Any + kernel = Instance('IPython.kernel.inprocess.ipkernel.Kernel') #-------------------------------------------------------------------------- - # Channel management methods. + # Channel management methods #-------------------------------------------------------------------------- - def start_channels(self, shell=True, iopub=True, stdin=True, hb=True): - if shell: - self.shell_channel.start() - if iopub: - self.iopub_channel.start() - if stdin: - self.stdin_channel.start() - self.shell_channel.allow_stdin = True - else: - self.shell_channel.allow_stdin = False - if hb: - self.hb_channel.start() - - def stop_channels(self): - if self.shell_channel.is_alive(): - self.shell_channel.stop() - if self.iopub_channel.is_alive(): - self.iopub_channel.stop() - if self.stdin_channel.is_alive(): - self.stdin_channel.stop() - if self.hb_channel.is_alive(): - self.hb_channel.stop() - - @property - def channels_running(self): - return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or - self.stdin_channel.is_alive() or self.hb_channel.is_alive()) + def start_channels(self, *args, **kwargs): + super(InProcessKernelClient, self).start_channels(self) + self.kernel.frontends.append(self) @property def shell_channel(self): @@ -268,46 +79,9 @@ class InProcessKernelManager(KernelManager): self._hb_channel = self.hb_channel_class(self) return self._hb_channel - #-------------------------------------------------------------------------- - # Kernel management methods: - #-------------------------------------------------------------------------- - - def start_kernel(self, **kwds): - from IPython.kernel.inprocess.ipkernel import InProcessKernel - self.kernel = InProcessKernel() - self.kernel.frontends.append(self) - - def shutdown_kernel(self): - self._kill_kernel() - - def restart_kernel(self, now=False, **kwds): - self.shutdown_kernel() - self.start_kernel(**kwds) - - @property - def has_kernel(self): - return self.kernel is not None - - def _kill_kernel(self): - self.kernel.frontends.remove(self) - self.kernel = None - - def interrupt_kernel(self): - raise NotImplementedError("Cannot interrupt in-process kernel.") - - def signal_kernel(self, signum): - raise NotImplementedError("Cannot signal in-process kernel.") - - def is_alive(self): - return True - #----------------------------------------------------------------------------- # ABC Registration #----------------------------------------------------------------------------- -ShellChannelABC.register(InProcessShellChannel) -IOPubChannelABC.register(InProcessIOPubChannel) -HBChannelABC.register(InProcessHBChannel) -StdInChannelABC.register(InProcessStdInChannel) -KernelManagerABC.register(InProcessKernelManager) +KernelClientABC.register(InProcessKernelClient) diff --git a/IPython/kernel/inprocess/ipkernel.py b/IPython/kernel/inprocess/ipkernel.py index 33b3cc5..c367fd4 100644 --- a/IPython/kernel/inprocess/ipkernel.py +++ b/IPython/kernel/inprocess/ipkernel.py @@ -37,7 +37,8 @@ class InProcessKernel(Kernel): # The frontends connected to this kernel. frontends = List( - Instance('IPython.kernel.inprocess.kernelmanager.InProcessKernelManager')) + Instance('IPython.kernel.inprocess.client.InProcessKernelClient') + ) # The GUI environment that the kernel is running under. This need not be # specified for the normal operation for the kernel, but is required for diff --git a/IPython/kernel/inprocess/manager.py b/IPython/kernel/inprocess/manager.py index 16d49c5..4a015fc 100644 --- a/IPython/kernel/inprocess/manager.py +++ b/IPython/kernel/inprocess/manager.py @@ -1,7 +1,7 @@ -""" A kernel manager for in-process kernels. """ +"""A kernel manager for in-process kernels.""" #----------------------------------------------------------------------------- -# Copyright (C) 2012 The IPython Development Team +# Copyright (C) 2013 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. @@ -11,177 +11,15 @@ # Imports #----------------------------------------------------------------------------- -# Local imports. -from IPython.config.configurable import Configurable -from IPython.utils.traitlets import Any, Instance, Type -from IPython.kernel.kernelmanagerabc import ( - ShellChannelABC, IOPubChannelABC, - HBChannelABC, StdInChannelABC, - KernelManagerABC -) - -from .socket import DummySocket - -#----------------------------------------------------------------------------- -# Channel classes -#----------------------------------------------------------------------------- - -class InProcessChannel(object): - """Base class for in-process channels.""" - - def __init__(self, manager): - super(InProcessChannel, self).__init__() - self.manager = manager - self._is_alive = False - - #-------------------------------------------------------------------------- - # Channel interface - #-------------------------------------------------------------------------- - - def is_alive(self): - return self._is_alive - - def start(self): - self._is_alive = True - - def stop(self): - self._is_alive = False - - def call_handlers(self, msg): - """ This method is called in the main thread when a message arrives. - - Subclasses should override this method to handle incoming messages. - """ - raise NotImplementedError('call_handlers must be defined in a subclass.') - - #-------------------------------------------------------------------------- - # InProcessChannel interface - #-------------------------------------------------------------------------- - - def call_handlers_later(self, *args, **kwds): - """ Call the message handlers later. - - The default implementation just calls the handlers immediately, but this - method exists so that GUI toolkits can defer calling the handlers until - after the event loop has run, as expected by GUI frontends. - """ - self.call_handlers(*args, **kwds) - - def process_events(self): - """ Process any pending GUI events. - - This method will be never be called from a frontend without an event - loop (e.g., a terminal frontend). - """ - raise NotImplementedError - - -class InProcessShellChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.ShellChannel` for docstrings.""" - - # flag for whether execute requests should be allowed to call raw_input - allow_stdin = True - - #-------------------------------------------------------------------------- - # ShellChannel interface - #-------------------------------------------------------------------------- - - def execute(self, code, silent=False, store_history=True, - user_variables=[], user_expressions={}, allow_stdin=None): - if allow_stdin is None: - allow_stdin = self.allow_stdin - content = dict(code=code, silent=silent, store_history=store_history, - user_variables=user_variables, - user_expressions=user_expressions, - allow_stdin=allow_stdin) - msg = self.manager.session.msg('execute_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def complete(self, text, line, cursor_pos, block=None): - content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos) - msg = self.manager.session.msg('complete_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def object_info(self, oname, detail_level=0): - content = dict(oname=oname, detail_level=detail_level) - msg = self.manager.session.msg('object_info_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def history(self, raw=True, output=False, hist_access_type='range', **kwds): - content = dict(raw=raw, output=output, - hist_access_type=hist_access_type, **kwds) - msg = self.manager.session.msg('history_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def shutdown(self, restart=False): - # FIXME: What to do here? - raise NotImplementedError('Cannot shutdown in-process kernel') - - #-------------------------------------------------------------------------- - # Protected interface - #-------------------------------------------------------------------------- - - def _dispatch_to_kernel(self, msg): - """ Send a message to the kernel and handle a reply. - """ - kernel = self.manager.kernel - if kernel is None: - raise RuntimeError('Cannot send request. No kernel exists.') - - stream = DummySocket() - self.manager.session.send(stream, msg) - msg_parts = stream.recv_multipart() - kernel.dispatch_shell(stream, msg_parts) - - idents, reply_msg = self.manager.session.recv(stream, copy=False) - self.call_handlers_later(reply_msg) - - -class InProcessIOPubChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.IOPubChannel` for docstrings.""" - - def flush(self, timeout=1.0): - pass - - -class InProcessStdInChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.StdInChannel` for docstrings.""" - - def input(self, string): - kernel = self.manager.kernel - if kernel is None: - raise RuntimeError('Cannot send input reply. No kernel exists.') - kernel.raw_input_str = string - - -class InProcessHBChannel(InProcessChannel): - """See `IPython.kernel.kernelmanager.HBChannel` for docstrings.""" - - time_to_dead = 3.0 - - def __init__(self, *args, **kwds): - super(InProcessHBChannel, self).__init__(*args, **kwds) - self._pause = True - - def pause(self): - self._pause = True - - def unpause(self): - self._pause = False - - def is_beating(self): - return not self._pause - +from IPython.utils.traitlets import Instance +from IPython.kernel.managerabc import KernelManagerABC +from IPython.kernel.manager import KernelManager #----------------------------------------------------------------------------- # Main kernel manager class #----------------------------------------------------------------------------- -class InProcessKernelManager(Configurable): +class InProcessKernelManager(KernelManager): """A manager for an in-process kernel. This class implements the interface of @@ -191,91 +29,16 @@ class InProcessKernelManager(Configurable): See `IPython.kernel.kernelmanager.KernelManager` for docstrings. """ - # The Session to use for building messages. - session = Instance('IPython.kernel.zmq.session.Session') - def _session_default(self): - from IPython.kernel.zmq.session import Session - return Session(config=self.config) - # The kernel process with which the KernelManager is communicating. kernel = Instance('IPython.kernel.inprocess.ipkernel.InProcessKernel') - # The classes to use for the various channels. - shell_channel_class = Type(InProcessShellChannel) - iopub_channel_class = Type(InProcessIOPubChannel) - stdin_channel_class = Type(InProcessStdInChannel) - hb_channel_class = Type(InProcessHBChannel) - - # Protected traits. - _shell_channel = Any - _iopub_channel = Any - _stdin_channel = Any - _hb_channel = Any - - #-------------------------------------------------------------------------- - # Channel management methods. - #-------------------------------------------------------------------------- - - def start_channels(self, shell=True, iopub=True, stdin=True, hb=True): - if shell: - self.shell_channel.start() - if iopub: - self.iopub_channel.start() - if stdin: - self.stdin_channel.start() - self.shell_channel.allow_stdin = True - else: - self.shell_channel.allow_stdin = False - if hb: - self.hb_channel.start() - - def stop_channels(self): - if self.shell_channel.is_alive(): - self.shell_channel.stop() - if self.iopub_channel.is_alive(): - self.iopub_channel.stop() - if self.stdin_channel.is_alive(): - self.stdin_channel.stop() - if self.hb_channel.is_alive(): - self.hb_channel.stop() - - @property - def channels_running(self): - return (self.shell_channel.is_alive() or self.iopub_channel.is_alive() or - self.stdin_channel.is_alive() or self.hb_channel.is_alive()) - - @property - def shell_channel(self): - if self._shell_channel is None: - self._shell_channel = self.shell_channel_class(self) - return self._shell_channel - - @property - def iopub_channel(self): - if self._iopub_channel is None: - self._iopub_channel = self.iopub_channel_class(self) - return self._iopub_channel - - @property - def stdin_channel(self): - if self._stdin_channel is None: - self._stdin_channel = self.stdin_channel_class(self) - return self._stdin_channel - - @property - def hb_channel(self): - if self._hb_channel is None: - self._hb_channel = self.hb_channel_class(self) - return self._hb_channel - #-------------------------------------------------------------------------- - # Kernel management methods: + # Kernel management methods #-------------------------------------------------------------------------- def start_kernel(self, **kwds): from IPython.kernel.inprocess.ipkernel import InProcessKernel self.kernel = InProcessKernel() - self.kernel.frontends.append(self) def shutdown_kernel(self): self._kill_kernel() @@ -289,7 +52,6 @@ class InProcessKernelManager(Configurable): return self.kernel is not None def _kill_kernel(self): - self.kernel.frontends.remove(self) self.kernel = None def interrupt_kernel(self): @@ -306,8 +68,4 @@ class InProcessKernelManager(Configurable): # ABC Registration #----------------------------------------------------------------------------- -ShellChannelABC.register(InProcessShellChannel) -IOPubChannelABC.register(InProcessIOPubChannel) -HBChannelABC.register(InProcessHBChannel) -StdInChannelABC.register(InProcessStdInChannel) KernelManagerABC.register(InProcessKernelManager) diff --git a/IPython/kernel/inprocess/tests/test_kernel.py b/IPython/kernel/inprocess/tests/test_kernel.py index bc0657f..a5ec8c1 100644 --- a/IPython/kernel/inprocess/tests/test_kernel.py +++ b/IPython/kernel/inprocess/tests/test_kernel.py @@ -16,8 +16,8 @@ import sys import unittest # Local imports -from IPython.kernel.inprocess.blockingkernelmanager import \ - BlockingInProcessKernelManager +from IPython.kernel.inprocess.blocking import BlockingInProcessKernelClient +from IPython.kernel.inprocess.manager import InProcessKernelManager from IPython.kernel.inprocess.ipkernel import InProcessKernel from IPython.testing.decorators import skipif_not_matplotlib from IPython.utils.io import capture_output @@ -29,33 +29,35 @@ from IPython.utils import py3compat class InProcessKernelTestCase(unittest.TestCase): + def setUp(self): + self.km = InProcessKernelManager() + self.km.start_kernel() + self.kc = BlockingInProcessKernelClient(kernel=self.km.kernel) + self.kc.start_channels() + @skipif_not_matplotlib def test_pylab(self): """ Does pylab work in the in-process kernel? """ - km = BlockingInProcessKernelManager() - km.start_kernel() - km.shell_channel.execute('%pylab') - msg = get_stream_message(km) + kc = self.kc + kc.execute('%pylab') + msg = get_stream_message(kc) self.assert_('Welcome to pylab' in msg['content']['data']) def test_raw_input(self): """ Does the in-process kernel handle raw_input correctly? """ - km = BlockingInProcessKernelManager() - km.start_kernel() - io = StringIO('foobar\n') sys_stdin = sys.stdin sys.stdin = io try: if py3compat.PY3: - km.shell_channel.execute('x = input()') + self.kc.execute('x = input()') else: - km.shell_channel.execute('x = raw_input()') + self.kc.execute('x = raw_input()') finally: sys.stdin = sys_stdin - self.assertEqual(km.kernel.shell.user_ns.get('x'), 'foobar') + self.assertEqual(self.km.kernel.shell.user_ns.get('x'), 'foobar') def test_stdout(self): """ Does the in-process kernel correctly capture IO? @@ -66,21 +68,21 @@ class InProcessKernelTestCase(unittest.TestCase): kernel.shell.run_cell('print("foo")') self.assertEqual(io.stdout, 'foo\n') - km = BlockingInProcessKernelManager(kernel=kernel) - kernel.frontends.append(km) - km.shell_channel.execute('print("bar")') - msg = get_stream_message(km) + kc = BlockingInProcessKernelClient(kernel=kernel) + kernel.frontends.append(kc) + kc.shell_channel.execute('print("bar")') + msg = get_stream_message(kc) self.assertEqual(msg['content']['data'], 'bar\n') #----------------------------------------------------------------------------- # Utility functions #----------------------------------------------------------------------------- -def get_stream_message(kernel_manager, timeout=5): +def get_stream_message(kernel_client, timeout=5): """ Gets a single stream message synchronously from the sub channel. """ while True: - msg = kernel_manager.iopub_channel.get_msg(timeout=timeout) + msg = kernel_client.get_iopub_msg(timeout=timeout) if msg['header']['msg_type'] == 'stream': return msg diff --git a/IPython/kernel/inprocess/tests/test_kernelmanager.py b/IPython/kernel/inprocess/tests/test_kernelmanager.py index df1ad24..f6cb4bd 100644 --- a/IPython/kernel/inprocess/tests/test_kernelmanager.py +++ b/IPython/kernel/inprocess/tests/test_kernelmanager.py @@ -14,9 +14,9 @@ from __future__ import print_function import unittest # Local imports -from IPython.kernel.inprocess.blockingkernelmanager import \ - BlockingInProcessKernelManager +from IPython.kernel.inprocess.blocking import BlockingInProcessKernelClient from IPython.kernel.inprocess.ipkernel import InProcessKernel +from IPython.kernel.inprocess.manager import InProcessKernelManager #----------------------------------------------------------------------------- # Test case @@ -24,20 +24,22 @@ from IPython.kernel.inprocess.ipkernel import InProcessKernel class InProcessKernelManagerTestCase(unittest.TestCase): - def test_inteface(self): + def test_interface(self): """ Does the in-process kernel manager implement the basic KM interface? """ - km = BlockingInProcessKernelManager() - self.assert_(not km.channels_running) + km = InProcessKernelManager() self.assert_(not km.has_kernel) - km.start_channels() - self.assert_(km.channels_running) - km.start_kernel() self.assert_(km.has_kernel) self.assert_(km.kernel is not None) + kc = BlockingInProcessKernelClient(kernel=km.kernel) + self.assert_(not kc.channels_running) + + kc.start_channels() + self.assert_(kc.channels_running) + old_kernel = km.kernel km.restart_kernel() self.assert_(km.kernel is not None) @@ -49,37 +51,43 @@ class InProcessKernelManagerTestCase(unittest.TestCase): self.assertRaises(NotImplementedError, km.interrupt_kernel) self.assertRaises(NotImplementedError, km.signal_kernel, 9) - km.stop_channels() - self.assert_(not km.channels_running) + kc.stop_channels() + self.assert_(not kc.channels_running) def test_execute(self): """ Does executing code in an in-process kernel work? """ - km = BlockingInProcessKernelManager() + km = InProcessKernelManager() km.start_kernel() - km.shell_channel.execute('foo = 1') + kc = BlockingInProcessKernelClient(kernel=km.kernel) + kc.start_channels() + kc.execute('foo = 1') self.assertEquals(km.kernel.shell.user_ns['foo'], 1) def test_complete(self): """ Does requesting completion from an in-process kernel work? """ - km = BlockingInProcessKernelManager() + km = InProcessKernelManager() km.start_kernel() + kc = BlockingInProcessKernelClient(kernel=km.kernel) + kc.start_channels() km.kernel.shell.push({'my_bar': 0, 'my_baz': 1}) - km.shell_channel.complete('my_ba', 'my_ba', 5) - msg = km.shell_channel.get_msg() - self.assertEquals(msg['header']['msg_type'], 'complete_reply') - self.assertEquals(sorted(msg['content']['matches']), + kc.complete('my_ba', 'my_ba', 5) + msg = kc.get_shell_msg() + self.assertEqual(msg['header']['msg_type'], 'complete_reply') + self.assertEqual(sorted(msg['content']['matches']), ['my_bar', 'my_baz']) def test_object_info(self): """ Does requesting object information from an in-process kernel work? """ - km = BlockingInProcessKernelManager() + km = InProcessKernelManager() km.start_kernel() + kc = BlockingInProcessKernelClient(kernel=km.kernel) + kc.start_channels() km.kernel.shell.user_ns['foo'] = 1 - km.shell_channel.object_info('foo') - msg = km.shell_channel.get_msg() + kc.object_info('foo') + msg = kc.get_shell_msg() self.assertEquals(msg['header']['msg_type'], 'object_info_reply') self.assertEquals(msg['content']['name'], 'foo') self.assertEquals(msg['content']['type_name'], 'int') @@ -87,11 +95,13 @@ class InProcessKernelManagerTestCase(unittest.TestCase): def test_history(self): """ Does requesting history from an in-process kernel work? """ - km = BlockingInProcessKernelManager() + km = InProcessKernelManager() km.start_kernel() - km.shell_channel.execute('%who') - km.shell_channel.history(hist_access_type='tail', n=1) - msg = km.shell_channel.get_msgs()[-1] + kc = BlockingInProcessKernelClient(kernel=km.kernel) + kc.start_channels() + kc.execute('%who') + kc.history(hist_access_type='tail', n=1) + msg = kc.shell_channel.get_msgs()[-1] self.assertEquals(msg['header']['msg_type'], 'history_reply') history = msg['content']['history'] self.assertEquals(len(history), 1)