import nbformat import os import pytest import re import glob from nbconvert.preprocessors import ExecutePreprocessor # inspired by http://www.blog.pythonlibrary.org/2018/10/16/testing-jupyter-notebooks/ def run_notebook(notebook_path): nb_name, _ = os.path.splitext(os.path.basename(notebook_path)) with open(notebook_path) as f: nb = nbformat.read(f, as_version=4) proc = ExecutePreprocessor(timeout=600, kernel_name='python3') proc.allow_errors = True proc.preprocess(nb) for num, cell in enumerate(nb.cells): if 'outputs' in cell: for output in cell['outputs']: if output.output_type == 'error': return cell.execution_count, output.traceback return None # 7-bit C1 ANSI sequences def escape_ansi_control(error): ansi_escape = re.compile(r''' \x1B # ESC [@-_] # 7-bit C1 Fe [0-?]* # Parameter bytes [ -/]* # Intermediate bytes [@-~] # Final byte ''', re.VERBOSE) sanitized = "" for line in error: sanitized += ansi_escape.sub('', line) + "\n" return sanitized class TestDocs: def test_docs(self): dirs = 'docs/', 'docs/tutorials/' cwd = os.getcwd() for dir in dirs: os.chdir(dir) files = sorted(glob.glob("*.ipynb")) for filename in files: errors = run_notebook(filename) if errors is not None: pytest.fail("\nNotebook {}, Cell {} failed:\n{}".format(filename,errors[0], escape_ansi_control(errors[1]))) os.chdir(cwd)