#!/usr/bin/env pythonimport nbformat,firefrom nbconvert.preprocessors import ExecutePreprocessordef run_notebook(path):"Executes notebook `path` and shows any exceptions. Useful for testing" nb = nbformat.read(open(path), as_version=nbformat.NO_CONVERT) ExecutePreprocessor(timeout=600).preprocess(nb, {})print('done')if__name__=='__main__': fire.Fire(run_notebook)
34:08 - Jeremy explaining the source code of notebook2script.py; Jupyter notebook is just a json data file
#!/usr/bin/env pythonimport json,fire,refrom pathlib import Pathimport iodef is_export(cell):if cell['cell_type'] !='code': returnFalse src = cell['source']iflen(src) ==0orlen(src[0]) <7: returnFalse#import pdb; pdb.set_trace()return re.match(r'^\s*#\s*export\s*$', src[0], re.IGNORECASE) isnotNonedef getSortedFiles(allFiles, upTo=None):'''Returns all the notebok files sorted by name. allFiles = True : returns all files = '*_*.ipynb' : returns this pattern upTo = None : no upper limit = filter : returns all files up to 'filter' included The sorting optioj is important to ensure that the notebok are executed in correct order. '''import glob ret = []if (allFiles==True): ret = glob.glob('*.ipynb') # Checks both that is bool type and that is Trueif (isinstance(allFiles,str)): ret = glob.glob(allFiles)if0==len(ret): print('WARNING: No files found')return retif upTo isnotNone: ret = [f for f in ret ifstr(f)<=str(upTo)]returnsorted(ret)def notebook2script(fname=None, allFiles=None, upTo=None):'''Finds cells starting with `#export` and puts them into a new module + allFiles: convert all files in the folder + upTo: convert files up to specified one included ES: notebook2script --allFiles=True # Parse all files notebook2script --allFiles=nb* # Parse all files starting with nb* notebook2script --upTo=10 # Parse all files with (name<='10') notebook2script --allFiles=*_*.ipynb --upTo=10 # Parse all files with an '_' and (name<='10') '''# initial checksif (allFiles isNone) and (upTo isnotNone): allFiles=True# Enable allFiles if upTo is presentif (fname isNone) and (not allFiles): print('Should provide a file name')ifnot allFiles: notebook2scriptSingle(fname)else:print('Begin...') [notebook2scriptSingle(f) for f in getSortedFiles(allFiles,upTo)]print('...End')def notebook2scriptSingle(fname):"Finds cells starting with `#export` and puts them into a new module" fname = Path(fname) fname_out =f'nb_{fname.stem.split("_")[0]}.py' main_dic = json.load(open(fname,'r',encoding="utf-8")) code_cells = [c for c in main_dic['cells'] if is_export(c)] 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'# remove trailing spaces module = re.sub(r' +$', '', module, flags=re.MULTILINE)ifnot (fname.parent/'exp').exists(): (fname.parent/'exp').mkdir() output_path = fname.parent/'exp'/fname_outwith io.open(output_path, "w", encoding="utf-8") as f: f.write(module[:-2])print(f"Converted {fname} to {output_path}")if__name__=='__main__': fire.Fire(notebook2script)