compSPI / simSPI

Generative Models
9 stars 10 forks source link

Reduce the boilerplate code in test_notebooks.py #130

Open bogdantoader opened 2 years ago

bogdantoader commented 2 years ago

Currently when a new notebook is added, one needs to either create a new test_x.py file that replicates a lot of the code in tests/test_notebooks.py, or add a new set of functions in test_notebooks (test_resources, _exec_notebook, test_new_notebook). I think it's possible to change the _exec_notebook and test_X functions so that for each new notebook we only need to add a new test_resources function, and then have a test_notebooks function that loops through each of these resources functions and calls _exec_notebook with the parameters in them.

ninamiolane commented 2 years ago

Excellent idea! Something like this could help (copy-pasted from ioSPI):

"""Unit tests for the notebooks."""

import glob
import os
import subprocess
import tempfile

import pytest

NOTEBOOKS_DIR = "notebooks"
NOTEBOOKS_TO_SKIP = os.path.join(NOTEBOOKS_DIR, "download_and_upload_with_osf.ipynb")

def _exec_notebook(path):
    """Execute notebook at path.
    Parameters
    ----------
    path : str
        Relative path of the notebook.
        E.g. notebooks/particle_metadata.ipynb
    """
    file_name = tempfile.NamedTemporaryFile(suffix=".ipynb").name
    args = [
        "jupyter",
        "nbconvert",
        "--to",
        "notebook",
        "--execute",
        "--ExecutePreprocessor.timeout=1000",
        "--ExecutePreprocessor.kernel_name=python3",
        "--output",
        file_name,
        path,
    ]
    subprocess.check_call(args)

paths = sorted(glob.glob(f"{NOTEBOOKS_DIR}/*.ipynb"))

@pytest.mark.parametrize("path", paths)
def test_notebook(path):
    """Test the notebook at path by executing it.
    Parameters
    ----------
    path : str
        Relative path of the notebooks.
        E.g. notebooks/particle_metadata.ipynb
    """
    if path in NOTEBOOKS_TO_SKIP:
        pytest.skip()
    _exec_notebook(path)