##// END OF EJS Templates
update execute preprocessor for msg spec 5
MinRK -
Show More
@@ -3,10 +3,6 b''
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 #-----------------------------------------------------------------------------
7 # Imports
8 #-----------------------------------------------------------------------------
9
10 6 import os
11 7 import sys
12 8
@@ -15,34 +11,60 b' try:'
15 11 except ImportError:
16 12 from Queue import Empty # Py 2
17 13
18 from IPython.kernel import KernelManager
19 from IPython.nbformat.current import reads, NotebookNode, writes
14 from IPython.utils.traitlets import List, Unicode
20 15
16 from IPython.nbformat.current import reads, NotebookNode, writes
21 17 from .base import Preprocessor
22 18
19 # default timeout for reply and output: 10s
20 TIMEOUT = 10
23 21
24 #-----------------------------------------------------------------------------
25 # Classes
26 #-----------------------------------------------------------------------------
27 22 class ExecutePreprocessor(Preprocessor):
28 23 """
29 24 Executes all the cells in a notebook
30 25 """
31 def __init__(self, extra_arguments=[], **kwargs):
32 """
33 Start an kernel to run the Python code
34 """
35 super(ExecutePreprocessor, self).__init__(**kwargs)
36 self.extra_arguments = []
26
27 # FIXME: to be removed with nbformat v4
28 # map msg_type to v3 output_type
29 msg_type_map = {
30 "error" : "pyerr",
31 "execute_result" : "pyout",
32 }
33
34 # FIXME: to be removed with nbformat v4
35 # map mime-type to v3 mime-type keys
36 mime_map = {
37 "text/plain" : "text",
38 "text/html" : "html",
39 "image/svg+xml" : "svg",
40 "image/png" : "png",
41 "image/jpeg" : "jpeg",
42 "text/latex" : "latex",
43 "application/json" : "json",
44 "application/javascript" : "javascript",
45 }
46
47 extra_arguments = List(Unicode)
37 48
38 49 def _create_client(self):
50 from IPython.kernel import KernelManager
39 51 self.km = KernelManager()
40 52 self.km.start_kernel(extra_arguments=self.extra_arguments, stderr=open(os.devnull, 'w'))
41 53 self.kc = self.km.client()
42 54 self.kc.start_channels()
55 self.log.debug('kc.start_channels: %s', self.kc.session.session)
43 56 self.iopub = self.kc.iopub_channel
44 57 self.shell = self.kc.shell_channel
45 58 self.shell.kernel_info()
59 try:
60 self.shell.get_msg(timeout=TIMEOUT)
61 except Empty:
62 self.log.error("Timeout waiting for kernel_info reply")
63 raise
64 try:
65 self.iopub.get_msg(timeout=TIMEOUT)
66 except Empty:
67 self.log.warn("Timeout waiting for IOPub on startup")
46 68
47 69 def _shutdown_client(self):
48 70 self.kc.stop_channels()
@@ -66,50 +88,70 b' class ExecutePreprocessor(Preprocessor):'
66 88 except Exception as e:
67 89 self.log.error("failed to run cell: " + repr(e))
68 90 self.log.error(str(cell.input))
69 sys.exit(1)
91 raise
70 92 cell.outputs = outputs
71 93 return cell, resources
72 94
73 @staticmethod
74 def run_cell(shell, iopub, cell):
75 # print cell.input
76 shell.execute(cell.input)
77 # wait for finish, maximum 20s
78 shell.get_msg(timeout=20)
95 def run_cell(self, shell, iopub, cell):
96 msg_id = shell.execute(cell.input)
97 self.log.debug("Executing cell:\n%s", cell.input)
98 # wait for finish, with timeout
99 while True:
100 try:
101 msg = shell.get_msg(timeout=TIMEOUT)
102 except Empty:
103 self.log.error("Timeout waiting for execute reply")
104 raise
105 if msg['parent_header'].get('msg_id') == msg_id:
106 break
107 else:
108 # not our reply
109 continue
110
79 111 outs = []
80 112
81 113 while True:
82 114 try:
83 msg = iopub.get_msg(timeout=0.2)
115 msg = iopub.get_msg(timeout=TIMEOUT)
84 116 except Empty:
117 self.log.warn("Timeout waiting for IOPub output")
85 118 break
119 if msg['parent_header'].get('msg_id') != msg_id:
120 # not an output from our execution
121 continue
86 122
87 123 msg_type = msg['msg_type']
124 self.log.debug("output: %s", msg_type)
88 125 content = msg['content']
89 out = NotebookNode(output_type=msg_type)
126 if msg_type == 'status':
127 if content['execution_state'] == 'idle':
128 break
129 else:
130 continue
131 elif msg_type in {'execute_input', 'pyin'}:
132 continue
133 elif msg_type == 'clear_output':
134 outs = []
135 continue
136
137 out = NotebookNode(output_type=self.msg_type_map.get(msg_type, msg_type))
90 138
91 139 # set the prompt number for the input and the output
92 140 if 'execution_count' in content:
93 141 cell['prompt_number'] = content['execution_count']
94 142 out.prompt_number = content['execution_count']
95 143
96 if msg_type in ('status', 'pyin'):
97 continue
98 elif msg_type == 'clear_output':
99 outs = []
100 continue
101
102 144 if msg_type == 'stream':
103 145 out.stream = content['name']
104 146 out.text = content['data']
105 elif msg_type in ('display_data', 'pyout'):
147 elif msg_type in ('display_data', 'execute_result'):
106 148 out['metadata'] = content['metadata']
107 for mime, data in content['data'].iteritems():
108 attr = mime.split('/')[-1].lower()
109 # this gets most right, but fix svg+html, plain
110 attr = attr.replace('+xml', '').replace('plain', 'text')
111 setattr(out, attr, data)
112 elif msg_type == 'pyerr':
149 for mime, data in content['data'].items():
150 # map mime-type keys to nbformat v3 keys
151 # this will be unnecessary in nbformat v4
152 key = self.mime_map.get(mime, mime)
153 out[key] = data
154 elif msg_type == 'error':
113 155 out.ename = content['ename']
114 156 out.evalue = content['evalue']
115 157 out.traceback = content['traceback']
@@ -19,29 +19,28 b' from IPython.nbconvert.filters import strip_ansi'
19 19
20 20 addr_pat = re.compile(r'0x[0-9a-f]{7,9}')
21 21
22
23 22 class TestExecute(PreprocessorTestsBase):
24 23 """Contains test functions for execute.py"""
25 24
26 25 @staticmethod
27 def normalize_cell(cell):
26 def normalize_output(output):
28 27 """
29 Normalizes cells for comparison.
28 Normalizes outputs for comparison.
30 29 """
31 cell = dict(cell)
32 if 'metadata' in cell:
33 del cell['metadata']
34 if 'text' in cell:
35 cell['text'] = re.sub(addr_pat, '<HEXADDR>', cell['text'])
36 if 'svg' in cell:
37 del cell['text']
38 if 'traceback' in cell:
30 output = dict(output)
31 if 'metadata' in output:
32 del output['metadata']
33 if 'text' in output:
34 output['text'] = re.sub(addr_pat, '<HEXADDR>', output['text'])
35 if 'svg' in output:
36 del output['text']
37 if 'traceback' in output:
39 38 tb = []
40 for line in cell['traceback']:
39 for line in output['traceback']:
41 40 tb.append(strip_ansi(line))
42 cell['traceback'] = tb
41 output['traceback'] = tb
43 42
44 return cell
43 return output
45 44
46 45
47 46 def assert_notebooks_equal(self, expected, actual):
@@ -52,8 +51,8 b' class TestExecute(PreprocessorTestsBase):'
52 51 for expected_cell, actual_cell in zip(expected_cells, actual_cells):
53 52 expected_outputs = expected_cell.get('outputs', [])
54 53 actual_outputs = actual_cell.get('outputs', [])
55 normalized_expected_outputs = list(map(self.normalize_cell, expected_outputs))
56 normalized_actual_outputs = list(map(self.normalize_cell, actual_outputs))
54 normalized_expected_outputs = list(map(self.normalize_output, expected_outputs))
55 normalized_actual_outputs = list(map(self.normalize_output, actual_outputs))
57 56 assert normalized_expected_outputs == normalized_actual_outputs
58 57
59 58
General Comments 0
You need to be logged in to leave comments. Login now