Skip to content

Commit b9faf64

Browse files
author
Golf Player
committed
First stab at getting hooks to work
1 parent d8e3ab0 commit b9faf64

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

nbclient/client.py

+38-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
CellExecutionComplete,
2525
CellExecutionError
2626
)
27-
from .util import run_sync, ensure_async
27+
from .util import run_sync, ensure_async, run_hook
2828
from .output_widget import OutputWidget
2929

3030

@@ -223,6 +223,35 @@ class NotebookClient(LoggingConfigurable):
223223

224224
kernel_manager_class = Type(config=True, help='The kernel manager class to use.')
225225

226+
on_kernel_create = Any(
227+
default_value=None,
228+
allow_none=True,
229+
help="""A callable which executes when the kernel is created.""",
230+
).tag(config=True)
231+
232+
on_cell_start = Any(
233+
default_value=None,
234+
allow_none=True,
235+
help="""A callable which executes before a cell is executed.""",
236+
).tag(config=True)
237+
238+
on_cell_complete = Any(
239+
default_value=None,
240+
allow_none=True,
241+
help=dedent(
242+
"""
243+
A callable which executes after a cell execution is complete. It is
244+
called even when a cell results in a failure.
245+
"""
246+
),
247+
).tag(config=True)
248+
249+
on_cell_error = Any(
250+
default_value=None,
251+
allow_none=True,
252+
help="""A callable which executes when a cell execution results in an error.""",
253+
).tag(config=True)
254+
226255
@default('kernel_manager_class')
227256
def _kernel_manager_class_default(self):
228257
"""Use a dynamic default to avoid importing jupyter_client at startup"""
@@ -378,6 +407,7 @@ async def async_start_new_kernel_client(self, **kwargs):
378407

379408
kernel_id = await ensure_async(self.km.start_kernel(extra_arguments=self.extra_arguments,
380409
**kwargs))
410+
run_hook(self.on_kernel_create, kernel_id)
381411

382412
# if self.km is not a KernelManager, it's probably a MultiKernelManager
383413
try:
@@ -661,14 +691,15 @@ def _passed_deadline(self, deadline):
661691
return True
662692
return False
663693

664-
def _check_raise_for_error(self, cell, exec_reply):
694+
def _check_raise_for_error(self, cell, cell_index, exec_reply):
665695
cell_allows_errors = self.allow_errors or "raises-exception" in cell.metadata.get(
666696
"tags", []
667697
)
668698

669-
if self.force_raise_errors or not cell_allows_errors:
670-
if (exec_reply is not None) and exec_reply['content']['status'] == 'error':
671-
raise CellExecutionError.from_cell_and_msg(cell, exec_reply['content'])
699+
if (exec_reply is not None) and exec_reply['content']['status'] == 'error':
700+
run_hook(self.on_cell_error, cell, cell_index)
701+
if self.force_raise_errors or not cell_allows_errors:
702+
raise CellExecutionError.from_cell_and_msg(cell, exec_reply['content'])
672703

673704
async def async_execute_cell(self, cell, cell_index, execution_count=None, store_history=True):
674705
"""
@@ -712,6 +743,7 @@ async def async_execute_cell(self, cell, cell_index, execution_count=None, store
712743
cell['metadata']['execution'] = {}
713744

714745
self.log.debug("Executing cell:\n%s", cell.source)
746+
run_hook(self.on_cell_start, cell, cell_index)
715747
parent_msg_id = await ensure_async(
716748
self.kc.execute(
717749
cell.source,
@@ -744,7 +776,7 @@ async def async_execute_cell(self, cell, cell_index, execution_count=None, store
744776

745777
if execution_count:
746778
cell['execution_count'] = execution_count
747-
self._check_raise_for_error(cell, exec_reply)
779+
self._check_raise_for_error(cell, cell_index, exec_reply)
748780
self.nb['cells'][cell_index] = cell
749781
return cell
750782

nbclient/util.py

+7
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,10 @@ async def ensure_async(obj):
8989
return result
9090
# obj doesn't need to be awaited
9191
return obj
92+
93+
94+
def run_hook(hook, *args):
95+
if hook is None:
96+
return
97+
loop = asyncio.get_event_loop()
98+
loop.call_soon(hook, *args)

0 commit comments

Comments
 (0)