The tradeoffs of using an interactive programming environment
%reload_ext autoreload
%autoreload 2
%matplotlib inline
import json,re
from pathlib import Path
import io
Let's start by simply grabbing a ipynb
file
fname = Path('01_tensors_matmul.ipynb'); fname
ipynb
files are simply JSON plain text format. So we can load it and it gives us a dictionary.
fname_out = f'nb_{fname.stem.split("_")[0]}.py'; fname_out
main_dic = json.load(open(fname,'r',encoding="utf-8"))
main_dic.keys()
Looking at the cells
key we can see each cell of the jupyter notebook and what properties it has.
main_dic['cells'][0]
Now we want to be look at each cell and determine if it should be exported as part of our module's functions.
We do this by putting #export
in any cell we want to export and using a function to read each cell in the loaded notebook and return True
or False
depending on if the export tag is present or not.
def is_export(cell):
# if the cell is not code return false
if cell['cell_type'] != 'code': return False
src = cell['source']
# if the len
if len(src) == 0 or len(src[0]) < 7: return False
return re.match(r'^\s*#\s*export\s*$', src[0], re.IGNORECASE) is not None
code_cells = [c for c in main_dic['cells'] if is_export(c)]
Now we have a list of all the cells marked for export
code_cells[0]
Lastly, we can iterate through the list, grab the code put into a string called module
and export it as a python file.
module = f'''
#################################################
### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ###
#################################################
# file to edit: dev_nb/{fname.name}
'''
for cell in code_cells:
module += ''.join(cell['source'][1:]) + '\n\n'
module
We now have a quick way to export our functions and build as we go using jupyter notebooks.