From 2b04cb38d98a54778777133fdb77adfb42b8ee69 Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Fri, 17 Apr 2015 16:18:23 +0100 Subject: [PATCH 1/3] Don't break prematurely when running a cell on an ipython kernel The kernel may go idle before it processes the next input, which break the while=True loop in run_cell() early. Wait for an acknowledgement of the input we've sent to the kernel before considering an idle message to mean that the cell has been parsed. --- wlauto/utils/ipython.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wlauto/utils/ipython.py b/wlauto/utils/ipython.py index 6ac4d323..68f5ab84 100644 --- a/wlauto/utils/ipython.py +++ b/wlauto/utils/ipython.py @@ -52,6 +52,7 @@ def run_cell(kernel_client, cell): """Run a cell of a notebook in an ipython kernel and return its output""" kernel_client.execute(cell.input) + input_acknowledged = False outs = [] while True: msg = kernel_client.get_iopub_msg() @@ -61,11 +62,12 @@ def run_cell(kernel_client, cell): out = NotebookNode(output_type=msg_type) if msg_type == "status": - if content["execution_state"] == "idle": + if content["execution_state"] == "idle" and input_acknowledged: break else: continue elif msg_type == "pyin": + input_acknowledged = True continue elif msg_type == "stream": out.stream = content["name"] From d12f5c65e1c5e184c7e6c1e21d1a72ffaf636822 Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Fri, 17 Apr 2015 18:50:31 +0100 Subject: [PATCH 2/3] Factor out the parsing of a valid cell run in the generic ipython implementation run_cell() becomes more complicated when we add ipython version 3 support which upsets pylint because there are "too many branches (15/12)". Factor out part of the function to make pylint happy. --- wlauto/utils/ipython.py | 58 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/wlauto/utils/ipython.py b/wlauto/utils/ipython.py index 68f5ab84..beacbb95 100644 --- a/wlauto/utils/ipython.py +++ b/wlauto/utils/ipython.py @@ -48,6 +48,32 @@ elif IPython: import_error_str = 'Unsupported IPython version {}'.format(IPython_ver_str) +def parse_valid_output(msg): + """Parse a valid result from an execution of a cell in an ipython kernel""" + msg_type = msg["msg_type"] + content = msg["content"] + out = NotebookNode(output_type=msg_type) + + if msg_type == "stream": + out.stream = content["name"] + out.text = content["data"] + elif msg_type in ("display_data", "pyout"): + for mime, data in content["data"].iteritems(): + if mime == "text/plain": + attr = "text" + else: + attr = mime.split("/")[-1] + setattr(out, attr, data) + elif msg_type == "pyerr": + out.ename = content["ename"] + out.evalue = content["evalue"] + out.traceback = content["traceback"] + else: + raise ValueError("Unknown msg_type {}".format(msg_type)) + + return out + + def run_cell(kernel_client, cell): """Run a cell of a notebook in an ipython kernel and return its output""" kernel_client.execute(cell.input) @@ -57,36 +83,14 @@ def run_cell(kernel_client, cell): while True: msg = kernel_client.get_iopub_msg() - msg_type = msg["msg_type"] - content = msg["content"] - out = NotebookNode(output_type=msg_type) - - if msg_type == "status": - if content["execution_state"] == "idle" and input_acknowledged: + if msg["msg_type"] == "status": + if msg["content"]["execution_state"] == "idle" and input_acknowledged: break - else: - continue - elif msg_type == "pyin": + elif msg["msg_type"] == "pyin": input_acknowledged = True - continue - elif msg_type == "stream": - out.stream = content["name"] - out.text = content["data"] - elif msg_type in ("display_data", "pyout"): - for mime, data in content["data"].iteritems(): - if mime == "text/plain": - attr = "text" - else: - attr = mime.split("/")[-1] - setattr(out, attr, data) - elif msg_type == "pyerr": - out.ename = content["ename"] - out.evalue = content["evalue"] - out.traceback = content["traceback"] else: - raise ValueError("Unknown msg_type {}".format(msg_type)) - - outs.append(out) + out = parse_valid_output(msg) + outs.append(out) return outs From e30386ce4a01c7b03a341850239b0d0c39b2b80e Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Thu, 16 Apr 2015 19:24:50 +0100 Subject: [PATCH 3/3] Add ipython version 3 support for the generic ipython support --- wlauto/utils/ipython.py | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/wlauto/utils/ipython.py b/wlauto/utils/ipython.py index beacbb95..dfe84f98 100644 --- a/wlauto/utils/ipython.py +++ b/wlauto/utils/ipython.py @@ -28,20 +28,37 @@ except ImportError as import_error: else: import_error_str = import_error.message +# The current code generates notebooks version 3 +NBFORMAT_VERSION = 3 + if IPython and (IPython.version_info[0] == 2): import IPython.kernel import IPython.nbformat.v3 def read_notebook(notebook_in): - return IPython.nbformat.v3.reads_json(notebook_in) + return IPython.nbformat.v3.reads_json(notebook_in) # pylint: disable=E1101 def write_notebook(notebook, fout): - IPython.nbformat.v3.nbjson.JSONWriter().write(notebook, fout) + IPython.nbformat.v3.nbjson.JSONWriter().write(notebook, fout) # pylint: disable=E1101 - NotebookNode = IPython.nbformat.v3.NotebookNode + NotebookNode = IPython.nbformat.v3.NotebookNode # pylint: disable=E1101 IPYTHON_NBCONVERT = ['ipython', 'nbconvert', '--to=latex', '--post=PDF'] +elif IPython and (IPython.version_info[0] == 3): + import IPython.kernel + import IPython.nbformat + + def read_notebook(notebook_in): + return IPython.nbformat.reads(notebook_in, NBFORMAT_VERSION) # pylint: disable=E1101 + + def write_notebook(notebook, fout): + IPython.nbformat.write(notebook, fout) # pylint: disable=E1101 + + NotebookNode = IPython.nbformat.NotebookNode # pylint: disable=E1101 + + IPYTHON_NBCONVERT = ['ipython', 'nbconvert', '--to=pdf'] + elif IPython: # Unsupported IPython version IPython_ver_str = ".".join([str(n) for n in IPython.version_info]) @@ -51,12 +68,20 @@ elif IPython: def parse_valid_output(msg): """Parse a valid result from an execution of a cell in an ipython kernel""" msg_type = msg["msg_type"] + if msg_type == 'error': + msg_type = 'pyerr' + elif msg_type == 'execute_result': + msg_type = 'pyout' + content = msg["content"] out = NotebookNode(output_type=msg_type) if msg_type == "stream": out.stream = content["name"] - out.text = content["data"] + try: + out.text = content['data'] + except KeyError: + out.text = content['text'] elif msg_type in ("display_data", "pyout"): for mime, data in content["data"].iteritems(): if mime == "text/plain": @@ -86,7 +111,7 @@ def run_cell(kernel_client, cell): if msg["msg_type"] == "status": if msg["content"]["execution_state"] == "idle" and input_acknowledged: break - elif msg["msg_type"] == "pyin": + elif msg["msg_type"] in ('pyin', 'execute_input'): input_acknowledged = True else: out = parse_valid_output(msg) @@ -111,7 +136,7 @@ def run_notebook(notebook): cell.outputs = run_cell(kernel_client, cell) cell.prompt_number = prompt_number - if cell.outputs: + if cell.outputs and cell.outputs[0]['output_type'] == 'pyout': cell.outputs[0]["prompt_number"] = prompt_number kernel_manager.shutdown_kernel()