15
15
from jupyter_client .client import KernelClient
16
16
from nbformat import NotebookNode
17
17
from nbformat .v4 import output_from_msg
18
- from traitlets import Any , Bool , Dict , Enum , Integer , List , Type , Unicode , default
18
+ from traitlets import (
19
+ Any ,
20
+ Bool ,
21
+ Callable ,
22
+ Dict ,
23
+ Enum ,
24
+ Integer ,
25
+ List ,
26
+ Type ,
27
+ Unicode ,
28
+ default ,
29
+ )
19
30
from traitlets .config .configurable import LoggingConfigurable
20
31
21
32
from .exceptions import (
26
37
DeadKernelError ,
27
38
)
28
39
from .output_widget import OutputWidget
29
- from .util import ensure_async , run_sync , run_hook
40
+ from .util import ensure_async , run_hook , run_sync
30
41
31
42
32
43
def timestamp (msg : Optional [Dict ] = None ) -> str :
@@ -261,43 +272,85 @@ class NotebookClient(LoggingConfigurable):
261
272
262
273
kernel_manager_class : KernelManager = Type (config = True , help = 'The kernel manager class to use.' )
263
274
264
- on_execution_start : t .Optional [t .Callable ] = Any (
275
+ on_notebook_start : t .Optional [t .Callable ] = Callable (
265
276
default_value = None ,
266
277
allow_none = True ,
267
- help = dedent ("""
268
- Called after the kernel manager and kernel client are setup, and cells
269
- are about to execute.
270
- Called with kwargs `kernel_id`.
271
- """ ),
278
+ help = dedent (
279
+ """
280
+ Called after the kernel manager and kernel client are setup, and cells
281
+ are about to execute.
282
+ Called with kwargs `notebook`.
283
+ """
284
+ ),
272
285
).tag (config = True )
273
286
274
- on_cell_start : t .Optional [t .Callable ] = Any (
287
+ on_notebook_complete : t .Optional [t .Callable ] = Callable (
275
288
default_value = None ,
276
289
allow_none = True ,
277
- help = dedent ("""
278
- A callable which executes before a cell is executed.
279
- Called with kwargs `cell`, and `cell_index`.
280
- """ ),
290
+ help = dedent (
291
+ """
292
+ Called after kernel is cleaned up.
293
+ Called with kwargs `notebook`.
294
+ """
295
+ ),
281
296
).tag (config = True )
282
297
283
- on_cell_complete : t .Optional [t .Callable ] = Any (
298
+ on_notebook_error : t .Optional [t .Callable ] = Callable (
284
299
default_value = None ,
285
300
allow_none = True ,
286
- help = dedent ("""
287
- A callable which executes after a cell execution is complete. It is
288
- called even when a cell results in a failure.
289
- Called with kwargs `cell`, and `cell_index`.
290
- """ ),
301
+ help = dedent (
302
+ """
303
+ Called when the notebook encountered an error.
304
+ Called with kwargs `notebook`.
305
+ """
306
+ ),
291
307
).tag (config = True )
292
308
293
- on_cell_error : t .Optional [t .Callable ] = Any (
309
+ on_cell_start : t .Optional [t .Callable ] = Callable (
294
310
default_value = None ,
295
311
allow_none = True ,
296
- help = dedent ("""
297
- A callable which executes when a cell execution results in an error.
298
- This is executed even if errors are suppressed with `cell_allows_errors`.
299
- Called with kwargs `cell`, and `cell_index`.
300
- """ ),
312
+ help = dedent (
313
+ """
314
+ A callable which executes before a cell is executed and before non-executing cells
315
+ are skipped.
316
+ Called with kwargs `cell` and `cell_index`.
317
+ """
318
+ ),
319
+ ).tag (config = True )
320
+
321
+ on_cell_execute : t .Optional [t .Callable ] = Callable (
322
+ default_value = None ,
323
+ allow_none = True ,
324
+ help = dedent (
325
+ """
326
+ A callable which executes just before a code cell is executed.
327
+ Called with kwargs `cell` and `cell_index`.
328
+ """
329
+ ),
330
+ ).tag (config = True )
331
+
332
+ on_cell_complete : t .Optional [t .Callable ] = Callable (
333
+ default_value = None ,
334
+ allow_none = True ,
335
+ help = dedent (
336
+ """
337
+ A callable which executes after a cell execution is complete. It is
338
+ called even when a cell results in a failure.
339
+ Called with kwargs `cell` and `cell_index`.
340
+ """
341
+ ),
342
+ ).tag (config = True )
343
+
344
+ on_cell_error : t .Optional [t .Callable ] = Callable (
345
+ default_value = None ,
346
+ allow_none = True ,
347
+ help = dedent (
348
+ """
349
+ A callable which executes when a cell execution results in an error.
350
+ This is executed even if errors are suppressed with `cell_allows_errors`.
351
+ Called with kwargs `cell` and `cell_index`.
352
+ """
353
+ ),
301
354
).tag (config = True )
302
355
303
356
@default ('kernel_manager_class' )
@@ -481,7 +534,7 @@ async def async_start_new_kernel_client(self) -> KernelClient:
481
534
await self ._async_cleanup_kernel ()
482
535
raise
483
536
self .kc .allow_stdin = False
484
- run_hook (sself . on_execution_start )
537
+ await run_hook (self . on_notebook_start , notebook = self . nb )
485
538
return self .kc
486
539
487
540
start_new_kernel_client = run_sync (async_start_new_kernel_client )
@@ -553,10 +606,13 @@ def on_signal():
553
606
await self .async_start_new_kernel_client ()
554
607
try :
555
608
yield
609
+ except RuntimeError as e :
610
+ await run_hook (self .on_notebook_error , notebook = self .nb )
611
+ raise e
556
612
finally :
557
613
if cleanup_kc :
558
614
await self ._async_cleanup_kernel ()
559
-
615
+ await run_hook ( self . on_notebook_complete , notebook = self . nb )
560
616
atexit .unregister (self ._cleanup_kernel )
561
617
try :
562
618
loop .remove_signal_handler (signal .SIGINT )
@@ -785,11 +841,9 @@ def _passed_deadline(self, deadline: int) -> bool:
785
841
return True
786
842
return False
787
843
788
- def _check_raise_for_error (
789
- self ,
790
- cell : NotebookNode ,
791
- cell_index : int ,
792
- exec_reply : t .Optional [t .Dict ]) -> None :
844
+ async def _check_raise_for_error (
845
+ self , cell : NotebookNode , cell_index : int , exec_reply : t .Optional [t .Dict ]
846
+ ) -> None :
793
847
794
848
if exec_reply is None :
795
849
return None
@@ -803,11 +857,9 @@ def _check_raise_for_error(
803
857
or exec_reply_content .get ('ename' ) in self .allow_error_names
804
858
or "raises-exception" in cell .metadata .get ("tags" , [])
805
859
)
806
-
807
- if (exec_reply is not None ) and exec_reply ['content' ]['status' ] == 'error' :
808
- run_hook (self .on_cell_error , cell = cell , cell_index = cell_index )
809
- if self .force_raise_errors or not cell_allows_errors :
810
- raise CellExecutionError .from_cell_and_msg (cell , exec_reply ['content' ])
860
+ await run_hook (self .on_cell_error , cell = cell , cell_index = cell_index )
861
+ if not cell_allows_errors :
862
+ raise CellExecutionError .from_cell_and_msg (cell , exec_reply_content )
811
863
812
864
async def async_execute_cell (
813
865
self ,
@@ -850,6 +902,9 @@ async def async_execute_cell(
850
902
The cell which was just processed.
851
903
"""
852
904
assert self .kc is not None
905
+
906
+ await run_hook (self .on_cell_start , cell = cell , cell_index = cell_index )
907
+
853
908
if cell .cell_type != 'code' or not cell .source .strip ():
854
909
self .log .debug ("Skipping non-executing cell %s" , cell_index )
855
910
return cell
@@ -867,13 +922,13 @@ async def async_execute_cell(
867
922
self .allow_errors or "raises-exception" in cell .metadata .get ("tags" , [])
868
923
)
869
924
870
- run_hook (self .on_cell_start , cell = cell , cell_index = cell_index )
925
+ await run_hook (self .on_cell_execute , cell = cell , cell_index = cell_index )
871
926
parent_msg_id = await ensure_async (
872
927
self .kc .execute (
873
928
cell .source , store_history = store_history , stop_on_error = not cell_allows_errors
874
929
)
875
930
)
876
- run_hook (self .on_cell_complete , cell = cell , cell_index = cell_index )
931
+ await run_hook (self .on_cell_complete , cell = cell , cell_index = cell_index )
877
932
# We launched a code cell to execute
878
933
self .code_cells_executed += 1
879
934
exec_timeout = self ._get_timeout (cell )
@@ -907,7 +962,7 @@ async def async_execute_cell(
907
962
908
963
if execution_count :
909
964
cell ['execution_count' ] = execution_count
910
- self ._check_raise_for_error (cell , cell_index , exec_reply )
965
+ await self ._check_raise_for_error (cell , cell_index , exec_reply )
911
966
self .nb ['cells' ][cell_index ] = cell
912
967
return cell
913
968
0 commit comments