diff --git a/IPython/kernel/inprocess/channels.py b/IPython/kernel/inprocess/channels.py index 25eb1a0..6e5fb9b 100644 --- a/IPython/kernel/inprocess/channels.py +++ b/IPython/kernel/inprocess/channels.py @@ -43,6 +43,9 @@ class InProcessChannel(object): """ raise NotImplementedError('call_handlers must be defined in a subclass.') + def flush(self, timeout=1.0): + pass + #-------------------------------------------------------------------------- # InProcessChannel interface #-------------------------------------------------------------------------- @@ -70,102 +73,14 @@ class InProcessShellChannel(InProcessChannel): # flag for whether execute requests should be allowed to call raw_input allow_stdin = True - proxy_methods = [ - 'execute', - 'complete', - 'inspect', - 'history', - 'shutdown', - 'kernel_info', - ] - - #-------------------------------------------------------------------------- - # ShellChannel interface - #-------------------------------------------------------------------------- - - def execute(self, code, silent=False, store_history=True, - 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_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, code, cursor_pos=None): - if cursor_pos is None: - cursor_pos = len(code) - content = dict(code=code, cursor_pos=cursor_pos) - msg = self.client.session.msg('complete_request', content) - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - def inspect(self, code, cursor_pos=None, detail_level=0): - if cursor_pos is None: - cursor_pos = len(code) - content = dict(code=code, cursor_pos=cursor_pos, - detail_level=detail_level, - ) - msg = self.client.session.msg('inspect_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') - - def kernel_info(self): - """Request kernel info.""" - msg = self.client.session.msg('kernel_info_request') - self._dispatch_to_kernel(msg) - return msg['header']['msg_id'] - - #-------------------------------------------------------------------------- - # 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): diff --git a/IPython/kernel/inprocess/client.py b/IPython/kernel/inprocess/client.py index 6484a47..16a0a0c 100644 --- a/IPython/kernel/inprocess/client.py +++ b/IPython/kernel/inprocess/client.py @@ -12,6 +12,7 @@ #----------------------------------------------------------------------------- # IPython imports +from IPython.kernel.inprocess.socket import DummySocket from IPython.utils.traitlets import Type, Instance from IPython.kernel.clientabc import KernelClientABC from IPython.kernel.client import KernelClient @@ -79,6 +80,76 @@ class InProcessKernelClient(KernelClient): self._hb_channel = self.hb_channel_class(self) return self._hb_channel + # Methods for sending specific messages + # ------------------------------------- + + def execute(self, code, silent=False, store_history=True, + 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_expressions=user_expressions, + allow_stdin=allow_stdin) + msg = self.session.msg('execute_request', content) + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def complete(self, code, cursor_pos=None): + if cursor_pos is None: + cursor_pos = len(code) + content = dict(code=code, cursor_pos=cursor_pos) + msg = self.session.msg('complete_request', content) + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def inspect(self, code, cursor_pos=None, detail_level=0): + if cursor_pos is None: + cursor_pos = len(code) + content = dict(code=code, cursor_pos=cursor_pos, + detail_level=detail_level, + ) + msg = self.session.msg('inspect_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.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') + + def kernel_info(self): + """Request kernel info.""" + msg = self.session.msg('kernel_info_request') + self._dispatch_to_kernel(msg) + return msg['header']['msg_id'] + + def input(self, string): + if self.kernel is None: + raise RuntimeError('Cannot send input reply. No kernel exists.') + self.kernel.raw_input_str = string + + + def _dispatch_to_kernel(self, msg): + """ Send a message to the kernel and handle a reply. + """ + kernel = self.kernel + if kernel is None: + raise RuntimeError('Cannot send request. No kernel exists.') + + stream = DummySocket() + self.session.send(stream, msg) + msg_parts = stream.recv_multipart() + kernel.dispatch_shell(stream, msg_parts) + + idents, reply_msg = self.session.recv(stream, copy=False) + self.shell_channel.call_handlers_later(reply_msg) + #----------------------------------------------------------------------------- # ABC Registration diff --git a/IPython/qt/inprocess.py b/IPython/qt/inprocess.py index 59bafb4..08e10dc 100644 --- a/IPython/qt/inprocess.py +++ b/IPython/qt/inprocess.py @@ -4,9 +4,9 @@ # Local imports. from IPython.external.qt import QtCore from IPython.kernel.inprocess import ( - InProcessShellChannel, InProcessIOPubChannel, InProcessStdInChannel, InProcessHBChannel, InProcessKernelClient, InProcessKernelManager, ) +from IPython.kernel.inprocess.channels import InProcessChannel from IPython.utils.traitlets import Type from .kernel_mixins import ( ChannelQObject, @@ -14,90 +14,8 @@ from .kernel_mixins import ( ChannelQObject, QtKernelManagerMixin, ) - -class QtInProcessShellChannel(ChannelQObject, InProcessShellChannel): - # Emitted when a reply has been received for the corresponding request type. - execute_reply = QtCore.Signal(object) - complete_reply = QtCore.Signal(object) - inspect_reply = QtCore.Signal(object) - history_reply = QtCore.Signal(object) - kernel_info_reply = QtCore.Signal(object) - - def call_handlers(self, msg): - """ Reimplemented to emit signals instead of making callbacks. - """ - # Emit the generic signal. - self.message_received.emit(msg) - - # Emit signals for specialized message types. - msg_type = msg['header']['msg_type'] - if msg_type == 'kernel_info_reply': - self._handle_kernel_info_reply(msg) - - signal = getattr(self, msg_type, None) - if signal: - signal.emit(msg) - -class QtInProcessIOPubChannel(ChannelQObject, InProcessIOPubChannel): - # Emitted when a message of type 'stream' is received. - stream_received = QtCore.Signal(object) - - # Emitted when a message of type 'execute_input' is received. - execute_input_received = QtCore.Signal(object) - - # Emitted when a message of type 'execute_result' is received. - execute_result_received = QtCore.Signal(object) - - # Emitted when a message of type 'error' is received. - error_received = QtCore.Signal(object) - - # Emitted when a message of type 'display_data' is received - display_data_received = QtCore.Signal(object) - - # Emitted when a crash report message is received from the kernel's - # last-resort sys.excepthook. - crash_received = QtCore.Signal(object) - - # Emitted when a shutdown is noticed. - shutdown_reply_received = QtCore.Signal(object) - - #--------------------------------------------------------------------------- - # 'IOPubChannel' interface - #--------------------------------------------------------------------------- - - def call_handlers(self, msg): - """ Reimplemented to emit signals instead of making callbacks. - """ - # Emit the generic signal. - self.message_received.emit(msg) - # Emit signals for specialized message types. - msg_type = msg['header']['msg_type'] - signal = getattr(self, msg_type + '_received', None) - if signal: - signal.emit(msg) - elif msg_type in ('stdout', 'stderr'): - self.stream_received.emit(msg) - - def flush(self): - """ Reimplemented to ensure that signals are dispatched immediately. - """ - super(QtInProcessIOPubChannel, self).flush() - QtCore.QCoreApplication.instance().processEvents() - -class QtInProcessStdInChannel(ChannelQObject, InProcessStdInChannel): - # Emitted when an input request is received. - input_requested = QtCore.Signal(object) - - def call_handlers(self, msg): - """ Reimplemented to emit signals instead of making callbacks. - """ - # Emit the generic signal. - self.message_received.emit(msg) - - # Emit signals for specialized message types. - msg_type = msg['header']['msg_type'] - if msg_type == 'input_request': - self.input_requested.emit(msg) +class QtInProcessChannel(ChannelQObject, InProcessChannel): + pass class QtInProcessHBChannel(QtHBChannelMixin, InProcessHBChannel): pass @@ -106,9 +24,9 @@ class QtInProcessKernelClient(QtKernelClientMixin, InProcessKernelClient): """ An in-process KernelManager with signals and slots. """ - iopub_channel_class = Type(QtInProcessIOPubChannel) - shell_channel_class = Type(QtInProcessShellChannel) - stdin_channel_class = Type(QtInProcessStdInChannel) + iopub_channel_class = Type(QtInProcessChannel) + shell_channel_class = Type(QtInProcessChannel) + stdin_channel_class = Type(QtInProcessChannel) hb_channel_class = Type(QtInProcessHBChannel) class QtInProcessKernelManager(QtKernelManagerMixin, InProcessKernelManager): diff --git a/IPython/qt/kernel_mixins.py b/IPython/qt/kernel_mixins.py index 8036cc3..df80345 100644 --- a/IPython/qt/kernel_mixins.py +++ b/IPython/qt/kernel_mixins.py @@ -20,10 +20,6 @@ class ChannelQObject(SuperQObject): # Emitted when any message is received. message_received = QtCore.Signal(object) - #--------------------------------------------------------------------------- - # Channel interface - #--------------------------------------------------------------------------- - def start(self): """ Reimplemented to emit signal. """ @@ -36,21 +32,26 @@ class ChannelQObject(SuperQObject): super(ChannelQObject, self).stop() self.stopped.emit() - #--------------------------------------------------------------------------- - # InProcessChannel interface - #--------------------------------------------------------------------------- - def call_handlers_later(self, *args, **kwds): """ Call the message handlers later. """ do_later = lambda: self.call_handlers(*args, **kwds) QtCore.QTimer.singleShot(0, do_later) + def call_handlers(self, msg): + self.message_received.emit(msg) + def process_events(self): """ Process any pending GUI events. """ QtCore.QCoreApplication.instance().processEvents() + def flush(self): + """ Reimplemented to ensure that signals are dispatched immediately. + """ + super(ChannelQObject, self).flush() + self.process_events() + class QtHBChannelMixin(ChannelQObject):