diff --git a/IPython/kernel/channels.py b/IPython/kernel/channels.py index 24c8b3f..c228bab 100644 --- a/IPython/kernel/channels.py +++ b/IPython/kernel/channels.py @@ -194,6 +194,7 @@ class ShellChannel(ZMQSocketChannel): 'history', 'kernel_info', 'shutdown', + 'is_complete', ] def __init__(self, context, session, address): @@ -396,6 +397,10 @@ class ShellChannel(ZMQSocketChannel): self._queue_send(msg) return msg['header']['msg_id'] + def is_complete(self, code): + msg = self.session.msg('is_complete_request', {'code': code}) + self._queue_send(msg) + return msg['header']['msg_id'] class IOPubChannel(ZMQSocketChannel): diff --git a/IPython/kernel/tests/test_message_spec.py b/IPython/kernel/tests/test_message_spec.py index e1080e9..57e4743 100644 --- a/IPython/kernel/tests/test_message_spec.py +++ b/IPython/kernel/tests/test_message_spec.py @@ -160,6 +160,10 @@ class KernelInfoReply(Reference): banner = Unicode() +class IsCompleteReply(Reference): + complete = Bool() + + # IOPub messages class ExecuteInput(Reference): @@ -189,6 +193,7 @@ references = { 'status' : Status(), 'complete_reply' : CompleteReply(), 'kernel_info_reply': KernelInfoReply(), + 'is_complete_reply': IsCompleteReply(), 'execute_input' : ExecuteInput(), 'execute_result' : ExecuteResult(), 'error' : Error(), @@ -382,6 +387,12 @@ def test_single_payload(): next_input_pls = [pl for pl in payload if pl["source"] == "set_next_input"] nt.assert_equal(len(next_input_pls), 1) +def test_is_complete(): + flush_channels() + + msg_id = KC.is_complete("a = 1") + reply = KC.get_shell_msg(timeout=TIMEOUT) + validate_message(reply, 'is_complete_reply', msg_id) # IOPub channel diff --git a/IPython/kernel/zmq/kernelbase.py b/IPython/kernel/zmq/kernelbase.py index 6c60822..9b8511b 100755 --- a/IPython/kernel/zmq/kernelbase.py +++ b/IPython/kernel/zmq/kernelbase.py @@ -114,7 +114,7 @@ class Kernel(Configurable): 'inspect_request', 'history_request', 'kernel_info_request', 'connect_request', 'shutdown_request', - 'apply_request', + 'apply_request', 'is_complete_request', ] self.shell_handlers = {} for msg_type in msg_types: @@ -479,6 +479,22 @@ class Kernel(Configurable): kernel. """ return {'status': 'ok', 'restart': restart} + + def is_complete_request(self, stream, ident, parent): + content = parent['content'] + code = content['code'] + + reply_content = self.do_is_complete(code) + reply_content = json_clean(reply_content) + reply_msg = self.session.send(stream, 'is_complete_reply', + reply_content, parent, ident) + self.log.debug("%s", reply_msg) + + def do_is_complete(self, code): + """Override in subclasses to find completions. + """ + return {'complete' : True, + } #--------------------------------------------------------------------------- # Engine methods