##// END OF EJS Templates
make execute preprocessor timeout configurable
MinRK -
Show More
@@ -1,162 +1,165 b''
1 1 """Module containing a preprocessor that removes the outputs from code cells"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import os
7 7 import sys
8 8
9 9 try:
10 10 from queue import Empty # Py 3
11 11 except ImportError:
12 12 from Queue import Empty # Py 2
13 13
14 14 from IPython.utils.traitlets import List, Unicode
15 15
16 16 from IPython.nbformat.current import reads, NotebookNode, writes
17 17 from .base import Preprocessor
18
19 # default timeout for reply and output: 10s
20 TIMEOUT = 10
18 from IPython.utils.traitlets import Integer
21 19
22 20 class ExecutePreprocessor(Preprocessor):
23 21 """
24 22 Executes all the cells in a notebook
25 23 """
26 24
25 timeout = Integer(30, config=True,
26 help="The time to wait (in seconds) for output from executions."
27 )
27 28 # FIXME: to be removed with nbformat v4
28 29 # map msg_type to v3 output_type
29 30 msg_type_map = {
30 31 "error" : "pyerr",
31 32 "execute_result" : "pyout",
32 33 }
33 34
34 35 # FIXME: to be removed with nbformat v4
35 36 # map mime-type to v3 mime-type keys
36 37 mime_map = {
37 38 "text/plain" : "text",
38 39 "text/html" : "html",
39 40 "image/svg+xml" : "svg",
40 41 "image/png" : "png",
41 42 "image/jpeg" : "jpeg",
42 43 "text/latex" : "latex",
43 44 "application/json" : "json",
44 45 "application/javascript" : "javascript",
45 46 }
46 47
47 48 extra_arguments = List(Unicode)
48 49
49 50 def _create_client(self):
50 51 from IPython.kernel import KernelManager
51 52 self.km = KernelManager()
52 self.km.start_kernel(extra_arguments=self.extra_arguments, stderr=open(os.devnull, 'w'))
53 self.km.write_connection_file()
53 54 self.kc = self.km.client()
54 55 self.kc.start_channels()
55 self.log.debug('kc.start_channels: %s', self.kc.session.session)
56 self.km.start_kernel(extra_arguments=self.extra_arguments, stderr=open(os.devnull, 'w'))
56 57 self.iopub = self.kc.iopub_channel
57 58 self.shell = self.kc.shell_channel
58 59 self.shell.kernel_info()
59 60 try:
60 self.shell.get_msg(timeout=TIMEOUT)
61 self.shell.get_msg(timeout=self.timeout)
61 62 except Empty:
62 63 self.log.error("Timeout waiting for kernel_info reply")
63 64 raise
64 try:
65 self.iopub.get_msg(timeout=TIMEOUT)
66 except Empty:
67 self.log.warn("Timeout waiting for IOPub on startup")
65 # flush IOPub
66 while True:
67 try:
68 self.iopub.get_msg(block=True, timeout=0.25)
69 except Empty:
70 break
68 71
69 72 def _shutdown_client(self):
70 73 self.kc.stop_channels()
71 74 self.km.shutdown_kernel()
72 75 del self.km
73 76
74 77 def preprocess(self, nb, resources):
75 78 self._create_client()
76 79 nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources)
77 80 self._shutdown_client()
78 81 return nb, resources
79 82
80 83 def preprocess_cell(self, cell, resources, cell_index):
81 84 """
82 85 Apply a transformation on each code cell. See base.py for details.
83 86 """
84 87 if cell.cell_type != 'code':
85 88 return cell, resources
86 89 try:
87 90 outputs = self.run_cell(self.shell, self.iopub, cell)
88 91 except Exception as e:
89 92 self.log.error("failed to run cell: " + repr(e))
90 93 self.log.error(str(cell.input))
91 94 raise
92 95 cell.outputs = outputs
93 96 return cell, resources
94 97
95 98 def run_cell(self, shell, iopub, cell):
96 99 msg_id = shell.execute(cell.input)
97 100 self.log.debug("Executing cell:\n%s", cell.input)
98 101 # wait for finish, with timeout
99 102 while True:
100 103 try:
101 msg = shell.get_msg(timeout=TIMEOUT)
104 msg = shell.get_msg(timeout=self.timeout)
102 105 except Empty:
103 106 self.log.error("Timeout waiting for execute reply")
104 107 raise
105 108 if msg['parent_header'].get('msg_id') == msg_id:
106 109 break
107 110 else:
108 111 # not our reply
109 112 continue
110 113
111 114 outs = []
112 115
113 116 while True:
114 117 try:
115 msg = iopub.get_msg(timeout=TIMEOUT)
118 msg = iopub.get_msg(timeout=self.timeout)
116 119 except Empty:
117 120 self.log.warn("Timeout waiting for IOPub output")
118 121 break
119 122 if msg['parent_header'].get('msg_id') != msg_id:
120 123 # not an output from our execution
121 124 continue
122 125
123 126 msg_type = msg['msg_type']
124 127 self.log.debug("output: %s", msg_type)
125 128 content = msg['content']
126 129 if msg_type == 'status':
127 130 if content['execution_state'] == 'idle':
128 131 break
129 132 else:
130 133 continue
131 134 elif msg_type in {'execute_input', 'pyin'}:
132 135 continue
133 136 elif msg_type == 'clear_output':
134 137 outs = []
135 138 continue
136 139
137 140 out = NotebookNode(output_type=self.msg_type_map.get(msg_type, msg_type))
138 141
139 142 # set the prompt number for the input and the output
140 143 if 'execution_count' in content:
141 144 cell['prompt_number'] = content['execution_count']
142 145 out.prompt_number = content['execution_count']
143 146
144 147 if msg_type == 'stream':
145 148 out.stream = content['name']
146 149 out.text = content['data']
147 150 elif msg_type in ('display_data', 'execute_result'):
148 151 out['metadata'] = content['metadata']
149 152 for mime, data in content['data'].items():
150 153 # map mime-type keys to nbformat v3 keys
151 154 # this will be unnecessary in nbformat v4
152 155 key = self.mime_map.get(mime, mime)
153 156 out[key] = data
154 157 elif msg_type == 'error':
155 158 out.ename = content['ename']
156 159 out.evalue = content['evalue']
157 160 out.traceback = content['traceback']
158 161 else:
159 162 self.log.error("unhandled iopub msg: " + msg_type)
160 163
161 164 outs.append(out)
162 165 return outs
General Comments 0
You need to be logged in to leave comments. Login now