From 07e6acdfe9804f871ac288d788d5de10ae51974f 2014-06-26 23:24:26 From: MinRK Date: 2014-06-26 23:24:26 Subject: [PATCH] send idle/busy on all shell messages Instead of just those that execute code. This means that kernel_info_request triggers busy/idle, allowing clients to check IOPub channel status without executing code. --- diff --git a/IPython/kernel/comm/manager.py b/IPython/kernel/comm/manager.py index 8817256..fdc7ba6 100644 --- a/IPython/kernel/comm/manager.py +++ b/IPython/kernel/comm/manager.py @@ -1,15 +1,7 @@ """Base class to manage comms""" -#----------------------------------------------------------------------------- -# 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. import sys @@ -23,9 +15,6 @@ from IPython.utils.traitlets import Instance, Unicode, Dict, Any from .comm import Comm -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- def lazy_keys(dikt): """Return lazy-evaluated string representation of a dictionary's keys @@ -36,27 +25,6 @@ def lazy_keys(dikt): return LazyEvaluate(lambda d: list(d.keys())) -def with_output(method): - """method decorator for ensuring output is handled properly in a message handler - - - sets parent header before entering the method - - publishes busy/idle - - flushes stdout/stderr after - """ - def method_with_output(self, stream, ident, msg): - parent = msg['header'] - self.shell.set_parent(parent) - self.shell.kernel._publish_status('busy', parent) - try: - return method(self, stream, ident, msg) - finally: - sys.stdout.flush() - sys.stderr.flush() - self.shell.kernel._publish_status('idle', parent) - - return method_with_output - - class CommManager(LoggingConfigurable): """Manager for Comms in the Kernel""" @@ -127,7 +95,6 @@ class CommManager(LoggingConfigurable): return comm # Message handlers - @with_output def comm_open(self, stream, ident, msg): """Handler for comm_open messages""" content = msg['content'] @@ -151,7 +118,6 @@ class CommManager(LoggingConfigurable): comm.close() self.unregister_comm(comm_id) - @with_output def comm_msg(self, stream, ident, msg): """Handler for comm_msg messages""" content = msg['content'] @@ -165,7 +131,6 @@ class CommManager(LoggingConfigurable): except Exception: self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True) - @with_output def comm_close(self, stream, ident, msg): """Handler for comm_close messages""" content = msg['content'] diff --git a/IPython/kernel/zmq/kernelbase.py b/IPython/kernel/zmq/kernelbase.py index dfdcd96..822768f 100755 --- a/IPython/kernel/zmq/kernelbase.py +++ b/IPython/kernel/zmq/kernelbase.py @@ -125,7 +125,7 @@ class Kernel(Configurable): for msg_type in control_msg_types: self.control_handlers[msg_type] = getattr(self, msg_type) - + def dispatch_control(self, msg): """dispatch control requests""" idents,msg = self.session.feed_identities(msg, copy=False) @@ -162,6 +162,10 @@ class Kernel(Configurable): self.log.error("Invalid Message", exc_info=True) return + # Set the parent message for side effects. + self.set_parent(idents, msg) + self._publish_status(u'busy') + header = msg['header'] msg_id = header['msg_id'] msg_type = msg['header']['msg_type'] @@ -196,6 +200,10 @@ class Kernel(Configurable): self.log.error("Exception in message handler:", exc_info=True) finally: signal(SIGINT, sig) + + sys.stdout.flush() + sys.stderr.flush() + self._publish_status(u'idle') def enter_eventloop(self): """enter eventloop""" @@ -281,7 +289,7 @@ class Kernel(Configurable): self.session.send(self.iopub_socket, u'status', {u'execution_state': status}, - parent=parent, + parent=parent or self._parent_header, ident=self._topic('status'), ) @@ -313,8 +321,6 @@ class Kernel(Configurable): def execute_request(self, stream, ident, parent): """handle an execute_request""" - self._publish_status(u'busy', parent) - try: content = parent[u'content'] code = py3compat.cast_unicode_py2(content[u'code']) @@ -329,9 +335,6 @@ class Kernel(Configurable): md = self._make_metadata(parent['metadata']) - # Set the parent message of the display hook and out streams. - self.set_parent(ident, parent) - # Re-broadcast our input for the benefit of listening clients, and # start computing output if not silent: @@ -367,8 +370,6 @@ class Kernel(Configurable): if not silent and reply_msg['content']['status'] == u'error': self._abort_queues() - self._publish_status(u'idle', parent) - def do_execute(self, code, silent, store_history=True, user_experssions=None, allow_stdin=False): """Execute user code. Must be overridden by subclasses. @@ -484,11 +485,6 @@ class Kernel(Configurable): self.log.error("Got bad msg: %s", parent, exc_info=True) return - self._publish_status(u'busy', parent) - - # Set the parent message of the display hook and out streams. - self.set_parent(ident, parent) - md = self._make_metadata(parent['metadata']) reply_content, result_buf = self.do_apply(content, bufs, msg_id, md) @@ -503,8 +499,6 @@ class Kernel(Configurable): self.session.send(stream, u'apply_reply', reply_content, parent=parent, ident=ident,buffers=result_buf, metadata=md) - self._publish_status(u'idle', parent) - def do_apply(self, content, bufs, msg_id, reply_metadata): """Override in subclasses to support the IPython parallel framework. """ diff --git a/docs/source/development/messaging.rst b/docs/source/development/messaging.rst index 7d95e05..39ca444 100644 --- a/docs/source/development/messaging.rst +++ b/docs/source/development/messaging.rst @@ -886,12 +886,17 @@ This message type is used by frontends to monitor the status of the kernel. Message type: ``status``:: content = { - # When the kernel starts to execute code, it will enter the 'busy' + # When the kernel starts to handle a message, it will enter the 'busy' # state and when it finishes, it will enter the 'idle' state. # The kernel will publish state 'starting' exactly once at process startup. execution_state : ('busy', 'idle', 'starting') } +.. versionchanged:: 5.0 + + Busy and idle messages should be sent before/after handling every shell message, + not just execution. + Clear output ------------