/
execute.py
133 lines (100 loc) · 4.7 KB
/
execute.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#############################################################################
# Copyright (c) 2018, Voilà Contributors #
# Copyright (c) 2018, QuantStack #
# #
# Distributed under the terms of the BSD 3-Clause License. #
# #
# The full license is in the file LICENSE, distributed with this software. #
#############################################################################
from nbconvert.preprocessors import ClearOutputPreprocessor
from nbclient.exceptions import CellExecutionError
from nbclient import NotebookClient
from traitlets import Unicode
def strip_code_cell_warnings(cell):
"""Strip any warning outputs and traceback from a code cell."""
if cell['cell_type'] != 'code':
return cell
outputs = cell['outputs']
cell['outputs'] = [
output for output in outputs
if output['output_type'] != 'stream' or output['name'] != 'stderr'
]
return cell
class VoilaExecutor(NotebookClient):
"""Execute, but respect the output widget behaviour"""
cell_error_instruction = Unicode(
'Please run Voilà with --debug to see the error message.',
config=True,
help=(
'instruction given to user to debug cell errors'
)
)
cell_timeout_instruction = Unicode(
'Please run Voilà with --VoilaExecutor.interrupt_on_timeout=True to continue executing the rest of the notebook.',
config=True,
help=(
'instruction given to user to continue execution on timeout'
)
)
def execute(self, nb, resources, km=None):
try:
result = super(VoilaExecutor, self).execute()
except CellExecutionError as e:
self.log.error(e)
result = (nb, resources)
# Strip errors and traceback if not in debug mode
if self.should_strip_error():
self.strip_notebook_errors(nb)
return result
async def execute_cell(self, cell, resources, cell_index, store_history=True):
try:
result = await self.async_execute_cell(cell, cell_index, store_history)
except TimeoutError as e:
self.log.error(e)
self.show_code_cell_timeout(cell)
raise e
# Strip errors and traceback if not in debug mode
if self.should_strip_error():
strip_code_cell_warnings(cell)
self.strip_code_cell_errors(cell)
return result
def should_strip_error(self):
"""Return True if errors should be stripped from the Notebook, False otherwise, depending on the current config."""
return 'Voila' not in self.config or not self.config['Voila'].get('show_tracebacks', False)
def strip_notebook_errors(self, nb):
"""Strip error messages and traceback from a Notebook."""
cells = nb['cells']
code_cells = [cell for cell in cells if cell['cell_type'] == 'code']
for cell in code_cells:
strip_code_cell_warnings(cell)
self.strip_code_cell_errors(cell)
return nb
def strip_code_cell_errors(self, cell):
"""Strip any error outputs and traceback from a code cell."""
# There is no 'outputs' key for markdown cells
if cell['cell_type'] != 'code':
return cell
outputs = cell['outputs']
error_outputs = [output for output in outputs if output['output_type'] == 'error']
error_message = 'There was an error when executing cell [{}]. {}'.format(cell['execution_count'], self.cell_error_instruction)
for output in error_outputs:
output['ename'] = 'ExecutionError'
output['evalue'] = 'Execution error'
output['traceback'] = [error_message]
return cell
def show_code_cell_timeout(self, cell):
"""Show a timeout error output in a code cell."""
timeout_message = 'Cell execution timed out, aborting notebook execution. {}'.format(self.cell_timeout_instruction)
output = {'output_type': 'error',
'ename': 'TimeoutError',
'evalue': 'Timeout error',
'traceback': [timeout_message]}
cell['outputs'] = [output]
def executenb(nb, cwd=None, km=None, **kwargs):
resources = {}
if cwd is not None:
resources['metadata'] = {'path': cwd} # pragma: no cover
# Clear any stale output, in case of exception
nb, resources = ClearOutputPreprocessor().preprocess(nb, resources)
executor = VoilaExecutor(nb, km=km, **kwargs)
return executor.execute(nb, resources, km=km)