diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 56aea6d..783bd5e 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -523,7 +523,6 @@ class InteractiveShell(SingletonConfigurable): self.init_pdb() self.init_extension_manager() self.init_payload() - self.init_comms() self.hooks.late_startup_hook() self.events.trigger('shell_initialized', self) atexit.register(self.atexit_operations) @@ -2419,14 +2418,6 @@ class InteractiveShell(SingletonConfigurable): self.configurables.append(self.payload_manager) #------------------------------------------------------------------------- - # Things related to widgets - #------------------------------------------------------------------------- - - def init_comms(self): - # not implemented in the base class - pass - - #------------------------------------------------------------------------- # Things related to the prefilter #------------------------------------------------------------------------- diff --git a/IPython/html/widgets/tests/test_interaction.py b/IPython/html/widgets/tests/test_interaction.py index 6f04bee..e891c96 100644 --- a/IPython/html/widgets/tests/test_interaction.py +++ b/IPython/html/widgets/tests/test_interaction.py @@ -22,6 +22,9 @@ from IPython.utils.py3compat import annotate class DummyComm(Comm): comm_id = 'a-b-c-d' + def open(self, *args, **kwargs): + pass + def send(self, *args, **kwargs): pass diff --git a/IPython/kernel/comm/comm.py b/IPython/kernel/comm/comm.py index 59bee03..87371d3 100644 --- a/IPython/kernel/comm/comm.py +++ b/IPython/kernel/comm/comm.py @@ -6,7 +6,7 @@ import uuid from IPython.config import LoggingConfigurable -from IPython.core.getipython import get_ipython +from IPython.kernel.zmq.kernelbase import Kernel from IPython.utils.jsonutil import json_clean from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any @@ -14,18 +14,21 @@ from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any class Comm(LoggingConfigurable): - shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') - def _shell_default(self): - return get_ipython() + # If this is instantiated by a non-IPython kernel, shell will be None + shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', + allow_none=True) + kernel = Instance('IPython.kernel.zmq.kernelbase.Kernel') + def _kernel_default(self): + if Kernel.initialized(): + return Kernel.instance() iopub_socket = Any() def _iopub_socket_default(self): - return self.shell.kernel.iopub_socket + return self.kernel.iopub_socket session = Instance('IPython.kernel.zmq.session.Session') def _session_default(self): - if self.shell is None or not hasattr(self.shell, 'kernel'): - return - return self.shell.kernel.session + if self.kernel is not None: + return self.kernel.session target_name = Unicode('comm') @@ -56,16 +59,15 @@ class Comm(LoggingConfigurable): def _publish_msg(self, msg_type, data=None, metadata=None, **keys): """Helper for sending a comm message on IOPub""" - if self.session is not None: - data = {} if data is None else data - metadata = {} if metadata is None else metadata - content = json_clean(dict(data=data, comm_id=self.comm_id, **keys)) - self.session.send(self.iopub_socket, msg_type, - content, - metadata=json_clean(metadata), - parent=self.shell.get_parent(), - ident=self.topic, - ) + data = {} if data is None else data + metadata = {} if metadata is None else metadata + content = json_clean(dict(data=data, comm_id=self.comm_id, **keys)) + self.session.send(self.iopub_socket, msg_type, + content, + metadata=json_clean(metadata), + parent=self.kernel._parent_header, + ident=self.topic, + ) def __del__(self): """trigger close on gc""" @@ -77,10 +79,13 @@ class Comm(LoggingConfigurable): """Open the frontend-side version of this comm""" if data is None: data = self._open_data + comm_manager = getattr(self.kernel, 'comm_manager', None) + if comm_manager is None: + raise RuntimeError("Comms cannot be opened without a kernel " + "and a comm_manager attached to that kernel.") + + comm_manager.register_comm(self) self._closed = False - ip = get_ipython() - if hasattr(ip, 'comm_manager'): - ip.comm_manager.register_comm(self) self._publish_msg('comm_open', data, metadata, target_name=self.target_name) def close(self, data=None, metadata=None): @@ -91,9 +96,7 @@ class Comm(LoggingConfigurable): if data is None: data = self._close_data self._publish_msg('comm_close', data, metadata) - ip = get_ipython() - if hasattr(ip, 'comm_manager'): - ip.comm_manager.unregister_comm(self) + self.kernel.comm_manager.unregister_comm(self) self._closed = True def send(self, data=None, metadata=None): @@ -132,9 +135,11 @@ class Comm(LoggingConfigurable): """Handle a comm_msg message""" self.log.debug("handle_msg[%s](%s)", self.comm_id, msg) if self._msg_callback: - self.shell.events.trigger('pre_execute') + if self.shell: + self.shell.events.trigger('pre_execute') self._msg_callback(msg) - self.shell.events.trigger('post_execute') + if self.shell: + self.shell.events.trigger('post_execute') __all__ = ['Comm'] diff --git a/IPython/kernel/comm/manager.py b/IPython/kernel/comm/manager.py index b1c2332..fef3699 100644 --- a/IPython/kernel/comm/manager.py +++ b/IPython/kernel/comm/manager.py @@ -28,17 +28,17 @@ def lazy_keys(dikt): class CommManager(LoggingConfigurable): """Manager for Comms in the Kernel""" - shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') - def _shell_default(self): - return get_ipython() + # If this is instantiated by a non-IPython kernel, shell will be None + shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', + allow_none=True) + kernel = Instance('IPython.kernel.zmq.kernelbase.Kernel') + iopub_socket = Any() def _iopub_socket_default(self): - return self.shell.kernel.iopub_socket + return self.kernel.iopub_socket session = Instance('IPython.kernel.zmq.session.Session') def _session_default(self): - if self.shell is None: - return - return self.shell.kernel.session + return self.kernel.session comms = Dict() targets = Dict() @@ -68,6 +68,7 @@ class CommManager(LoggingConfigurable): """Register a new comm""" comm_id = comm.comm_id comm.shell = self.shell + comm.kernel = self.kernel comm.iopub_socket = self.iopub_socket self.comms[comm_id] = comm return comm_id @@ -102,6 +103,7 @@ class CommManager(LoggingConfigurable): f = self.targets.get(target_name, None) comm = Comm(comm_id=comm_id, shell=self.shell, + kernel=self.kernel, iopub_socket=self.iopub_socket, primary=False, ) diff --git a/IPython/kernel/zmq/ipkernel.py b/IPython/kernel/zmq/ipkernel.py index 93915b5..7354e65 100644 --- a/IPython/kernel/zmq/ipkernel.py +++ b/IPython/kernel/zmq/ipkernel.py @@ -10,6 +10,7 @@ from IPython.utils.tokenutil import token_at_cursor from IPython.utils.traitlets import Instance, Type, Any from IPython.utils.decorators import undoc +from ..comm import CommManager from .kernelbase import Kernel as KernelBase from .serialize import serialize_object, unpack_apply_message from .zmqshell import ZMQInteractiveShell @@ -55,10 +56,12 @@ class IPythonKernel(KernelBase): # TMP - hack while developing self.shell._reply_content = None + self.comm_manager = CommManager(shell=self.shell, parent=self, + kernel=self) + self.shell.configurables.append(self.comm_manager) comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ] - comm_manager = self.shell.comm_manager for msg_type in comm_msg_types: - self.shell_handlers[msg_type] = getattr(comm_manager, msg_type) + self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type) # Kernel info fields implementation = 'ipython' diff --git a/IPython/kernel/zmq/kernelapp.py b/IPython/kernel/zmq/kernelapp.py index 190a3e6..c47368a 100644 --- a/IPython/kernel/zmq/kernelapp.py +++ b/IPython/kernel/zmq/kernelapp.py @@ -302,7 +302,7 @@ class IPKernelApp(BaseIPythonApplication, InteractiveShellApp, shell_stream = ZMQStream(self.shell_socket) control_stream = ZMQStream(self.control_socket) - kernel_factory = self.kernel_class + kernel_factory = self.kernel_class.instance kernel = kernel_factory(parent=self, session=self.session, shell_streams=[shell_stream, control_stream], diff --git a/IPython/kernel/zmq/kernelbase.py b/IPython/kernel/zmq/kernelbase.py index 2fa4740..30677ca 100755 --- a/IPython/kernel/zmq/kernelbase.py +++ b/IPython/kernel/zmq/kernelbase.py @@ -19,7 +19,7 @@ import zmq from zmq.eventloop import ioloop from zmq.eventloop.zmqstream import ZMQStream -from IPython.config.configurable import Configurable +from IPython.config.configurable import SingletonConfigurable from IPython.core.error import StdinNotImplementedError from IPython.core import release from IPython.utils import py3compat @@ -32,7 +32,7 @@ from IPython.utils.traitlets import ( from .session import Session -class Kernel(Configurable): +class Kernel(SingletonConfigurable): #--------------------------------------------------------------------------- # Kernel interface diff --git a/IPython/kernel/zmq/zmqshell.py b/IPython/kernel/zmq/zmqshell.py index 189edcc..3a4effd 100644 --- a/IPython/kernel/zmq/zmqshell.py +++ b/IPython/kernel/zmq/zmqshell.py @@ -49,7 +49,6 @@ from IPython.utils.warn import error from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook from IPython.kernel.zmq.datapub import ZMQDataPublisher from IPython.kernel.zmq.session import extract_header -from IPython.kernel.comm import CommManager from .session import Session #----------------------------------------------------------------------------- @@ -563,10 +562,6 @@ class ZMQInteractiveShell(InteractiveShell): super(ZMQInteractiveShell, self).init_magics() self.register_magics(KernelMagics) self.magics_manager.register_alias('ed', 'edit') - - def init_comms(self): - self.comm_manager = CommManager(shell=self, parent=self) - self.configurables.append(self.comm_manager) InteractiveShellABC.register(ZMQInteractiveShell)