2828
2929 locals().update(inputs)
3030"""
31+ YAML_IMPORT = """import yaml"""
32+ INPUTS_DISPLAY = """print(yaml.dump(inputs))"""
33+
3134INPUTS_CODE_CELL = dedent (INPUTS_CODE_CELL )
3235
3336# Save notebook outputs
4346 with shelve.open(out_path_db) as notebook_db:
4447 notebook_db['outputs'] = output
4548"""
49+ OUTPUTS_DISPLAY = """print(yaml.dump(output))"""
50+
4651OUTPUTS_CODE_CELL = dedent (OUTPUTS_CODE_CELL )
4752
4853
4954def run_notebook (path , inputs = None , outputs = None , inputs_pos = 1 , working_dir = './' , execute_kwargs = None ,
5055 out_path_db = None , out_path_ipynb = None , out_path_html = None , remove_db = 'always' , add_timestamp = True ,
51- hide_code_cells = False , display_links = True , raise_exception = False , return_notebook = False ):
56+ hide_code_cells = False , mask_extra_code = True , display_links = True ,
57+ raise_exception = False , return_notebook = False ):
5258 """ Execute a Jupyter Notebook programmatically.
5359 Heavily inspired by https://github.com/tritemio/nbrun.
5460
@@ -110,6 +116,9 @@ def run_notebook(path, inputs=None, outputs=None, inputs_pos=1, working_dir = '.
110116 Whether to add a cell with execution information at the beginning of the saved notebook.
111117 hide_code_cells : bool, optional
112118 Whether to hide the code cells in the saved notebook.
119+ mask_extra_code : bool, optional
120+ Whether to mask database reading and dumping code.
121+ For more, see :func:`~.mask_inputs_reading` and :func`~.mask_outputs_dumping` docstrings.
113122 display_links : bool, optional
114123 Whether to display links to the executed notebook and html at execution.
115124 raise_exception : bool, optional
@@ -182,6 +191,9 @@ def run_notebook(path, inputs=None, outputs=None, inputs_pos=1, working_dir = '.
182191 notebook_db .update (inputs )
183192
184193 code = CELL_INSERT_COMMENT + DB_CONNECT_CODE_CELL .format (repr (out_path_db )) + INPUTS_CODE_CELL
194+ if mask_extra_code :
195+ code += YAML_IMPORT + '\n ' + INPUTS_DISPLAY
196+
185197 notebook ['cells' ].insert (inputs_pos , nbformat .v4 .new_code_cell (code ))
186198
187199 if outputs is not None :
@@ -191,6 +203,12 @@ def run_notebook(path, inputs=None, outputs=None, inputs_pos=1, working_dir = '.
191203 code = CELL_INSERT_COMMENT + \
192204 (DB_CONNECT_CODE_CELL .format (repr (out_path_db )) if not inputs else "" ) + \
193205 OUTPUTS_CODE_CELL .format (outputs )
206+
207+ if mask_extra_code :
208+ if inputs is None :
209+ code = YAML_IMPORT + '\n ' + code
210+ code += OUTPUTS_DISPLAY
211+
194212 output_cell = nbformat .v4 .new_code_cell (code )
195213 notebook ['cells' ].append (output_cell )
196214
@@ -240,13 +258,23 @@ def run_notebook(path, inputs=None, outputs=None, inputs_pos=1, working_dir = '.
240258 if outputs is not None :
241259 exec_res ['outputs' ] = outputs_values
242260
261+ # Notebook postprocessing: add timestamp, mask db reading/dumping code
243262 if add_timestamp :
244263 timestamp = (f"**Executed:** { time .ctime (start_time )} <br>"
245264 f"**Duration:** { time .strftime ('%H:%M:%S' , time .gmtime (time .time () - start_time ))} <br>"
246265 f"**Autogenerated from:** [{ path } ]\n \n ---" )
247266 timestamp_cell = nbformat .v4 .new_markdown_cell (timestamp )
248267 notebook ['cells' ].insert (0 , timestamp_cell )
249268
269+ if mask_extra_code :
270+ if inputs is not None :
271+ pos = inputs_pos + 1 if add_timestamp else inputs_pos
272+ mask_inputs_reading (notebook = notebook , pos = pos )
273+
274+ if outputs is not None :
275+ pos = len (notebook ['cells' ]) - 1
276+ mask_outputs_dumping (notebook = notebook , pos = pos )
277+
250278 # Save the executed notebook/HTML to disk
251279 if out_path_ipynb is not None :
252280 save_notebook (notebook = notebook , out_path_ipynb = out_path_ipynb , display_link = display_links )
@@ -257,6 +285,63 @@ def run_notebook(path, inputs=None, outputs=None, inputs_pos=1, working_dir = '.
257285 exec_res ['notebook' ] = notebook
258286 return exec_res
259287
288+ # Mask functions for database operations cells
289+ def mask_inputs_reading (notebook , pos ):
290+ """ Replace database reading by variables initialization.
291+
292+ Result is a code cell with the following view:
293+ .. code-block:: python
294+
295+ varible_name_1 = varible_value_1
296+ varible_name_2 = varible_value_2
297+ ...
298+ """
299+ import nbformat
300+
301+ execution_count = notebook ['cells' ][pos ]['execution_count' ]
302+
303+ code_mask = str (notebook ['cells' ][pos ]['outputs' ][0 ]['text' ]).split ('\n ' )
304+ code_mask = [variable .replace (':' , ' =' , 1 ) for variable in code_mask ]
305+ code_mask = '\n ' .join (code_mask )[:- 2 ]
306+
307+ cell_mask = nbformat .v4 .new_code_cell (source = code_mask , execution_count = execution_count )
308+ notebook ['cells' ][pos ] = cell_mask
309+
310+ def mask_outputs_dumping (notebook , pos ):
311+ """Replace database dumping by printing outputs.
312+
313+ Result is a code cell with the following view and corresponding output:
314+ .. code-block:: python
315+
316+ print(varible_name_1)
317+ print(varible_name_2)
318+ ...
319+ """
320+ import nbformat
321+
322+ execution_count = notebook ['cells' ][pos ]['execution_count' ]
323+ outputs_variables = str (notebook ['cells' ][pos ]['outputs' ][0 ]['text' ]).split ('\n ' )
324+
325+ code_mask = ''
326+ text_mask = ''
327+
328+ for variable in outputs_variables :
329+ separator_pos = int (variable .find (':' ))
330+
331+ if separator_pos != - 1 :
332+ variable_name = variable [:separator_pos ]
333+ variable_value = variable [separator_pos + 2 :] + '\n '
334+
335+ code_mask += f'print({ variable_name } )\n '
336+ text_mask += variable_value
337+
338+ code_mask = code_mask [:- 1 ]
339+ outputs_mask = [nbformat .v4 .new_output (text = text_mask , name = 'stdout' , output_type = 'stream' )]
340+
341+ cell_mask = nbformat .v4 .new_code_cell (source = code_mask , execution_count = execution_count , outputs = outputs_mask )
342+ notebook ['cells' ][pos ] = cell_mask
343+
344+
260345# Save notebook functions
261346def save_notebook (notebook , out_path_ipynb , display_link ):
262347 """ Save an instance of :class:`nbformat.notebooknode.NotebookNode` as ipynb file."""
0 commit comments