33
44# Copyright (c) IPython Development Team.
55# Distributed under the terms of the Modified BSD License.
6+ from typing import Optional
7+ from nbformat import NotebookNode
68from nbclient import NotebookClient , execute as _execute
9+ from nbclient .util import run_sync
710# Backwards compatability for imported name
811from nbclient .exceptions import CellExecutionError
912
@@ -31,12 +34,27 @@ def __init__(self, **kw):
3134 Preprocessor .__init__ (self , nb = nb , ** kw )
3235 NotebookClient .__init__ (self , nb , ** kw )
3336
37+ def _check_assign_resources (self , resources ):
38+ if resources or not hasattr (self , 'resources' ):
39+ self .resources = resources
40+
3441 def preprocess (self , nb , resources = None , km = None ):
3542 """
3643 Preprocess notebook executing each code cell.
3744
3845 The input argument *nb* is modified in-place.
3946
47+ Note that this function recalls NotebookClient.__init__, which may look wrong.
48+ However since the preprocess call acts line an init on exeuction state it's expected.
49+ Therefore, we need to capture it here again to properly reset because traitlet
50+ assignments are not passed. There is a risk if traitlets apply any side effects for
51+ dual init.
52+ The risk should be manageable, and this approach minimizes side-effects relative
53+ to other alternatives.
54+
55+ One alternative but rejected implementation would be to copy the client's init internals
56+ which has already gotten out of sync with nbclient 0.5 release before nbcovnert 6.0 released.
57+
4058 Parameters
4159 ----------
4260 nb : NotebookNode
@@ -56,11 +74,73 @@ def preprocess(self, nb, resources=None, km=None):
5674 resources : dictionary
5775 Additional resources used in the conversion process.
5876 """
59- # Copied from NotebookClient init :/
60- self .nb = nb
61- self .km = km
62- if resources :
63- self .resources = resources
64- self .reset_execution_trackers ()
77+ NotebookClient .__init__ (self , nb , km )
78+ self ._check_assign_resources (resources )
6579 self .execute ()
66- return nb , resources
80+ return self .nb , self .resources
81+
82+ async def async_execute_cell (
83+ self ,
84+ cell : NotebookNode ,
85+ cell_index : int ,
86+ execution_count : Optional [int ] = None ,
87+ store_history : bool = False ) -> NotebookNode :
88+ """
89+ Executes a single code cell.
90+
91+ Overwrites NotebookClient's version of this method to allow for preprocess_cell calls.
92+
93+ Parameters
94+ ----------
95+ cell : nbformat.NotebookNode
96+ The cell which is currently being processed.
97+ cell_index : int
98+ The position of the cell within the notebook object.
99+ execution_count : int
100+ The execution count to be assigned to the cell (default: Use kernel response)
101+ store_history : bool
102+ Determines if history should be stored in the kernel (default: False).
103+ Specific to ipython kernels, which can store command histories.
104+
105+ Returns
106+ -------
107+ output : dict
108+ The execution output payload (or None for no output).
109+
110+ Raises
111+ ------
112+ CellExecutionError
113+ If execution failed and should raise an exception, this will be raised
114+ with defaults about the failure.
115+
116+ Returns
117+ -------
118+ cell : NotebookNode
119+ The cell which was just processed.
120+ """
121+ # Copied and intercepted to allow for custom preprocess_cell contracts to be fullfilled
122+ self .store_history = store_history
123+ cell , resources = self .preprocess_cell (cell , self .resources , cell_index )
124+ if execution_count :
125+ cell ['execution_count' ] = execution_count
126+ return cell , resources
127+
128+ def preprocess_cell (self , cell , resources , index , ** kwargs ):
129+ """
130+ Override if you want to apply some preprocessing to each cell.
131+ Must return modified cell and resource dictionary.
132+
133+ Parameters
134+ ----------
135+ cell : NotebookNode cell
136+ Notebook cell being processed
137+ resources : dictionary
138+ Additional resources used in the conversion process. Allows
139+ preprocessors to pass variables into the Jinja engine.
140+ index : int
141+ Index of the cell being processed
142+ """
143+ self ._check_assign_resources (resources )
144+ # Because nbclient is an async library, we need to wrap the parent async call to generate a syncronous version.
145+ cell = run_sync (NotebookClient .async_execute_cell )(self , cell , index , store_history = self .store_history )
146+ return cell , self .resources
0 commit comments