nbval
nbval is a pytest plugin designed to validate Jupyter notebooks. It allows users to execute notebooks as part of their test suite and compare cell outputs against previously saved outputs, ensuring reproducibility and correctness. The current version is 0.11.0, and it has a sporadic but active release cadence, typically with minor releases every 6-12 months.
Warnings
- breaking The `--nbval-sanitize` command-line option was removed in version 0.10.0. This option was previously used to sanitize notebook outputs before comparison but was deprecated in earlier versions.
- breaking Support for Python 3.6 was dropped in version 0.9.0. Users on Python 3.6 will not be able to install or run `nbval` versions 0.9.0 or newer.
- gotcha By default, `nbval` performs a strict diff on notebook outputs. This can lead to very verbose output in case of failures, especially with slight differences in timestamps, floating-point precision, or minor formatting changes. This behavior is controlled by the `nbval_diff` option.
- gotcha nbval's primary function is *output validation*, not just execution and failure on any runtime error. It compares the newly generated outputs against the stored outputs in the notebook. If the notebook is expected to raise an exception or has no outputs for a cell, this needs to be explicitly indicated using cell metadata (e.g., `raises-exception`, `skip-execution`).
Install
-
pip install nbval pytest
Imports
- nbval functionality
nbval is primarily used via the pytest CLI (e.g., `pytest --nbval`) and typically does not require direct Python imports for its core validation features. pytest automatically discovers and loads the plugin upon installation.
Quickstart
import pytest
import json
import os
# 1. Create a dummy Jupyter notebook file for testing
notebook_content = {
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{"name": "stdout", "output_type": "stream", "text": ["Hello from nbval!\n"]}
],
"source": ["print('Hello from nbval!')"]
}
],
"metadata": {
"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"},
"language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7"}
},
"nbformat": 4,
"nbformat_minor": 5
}
notebook_filename = "example.ipynb"
with open(notebook_filename, "w") as f:
json.dump(notebook_content, f, indent=4)
print(f"Created {notebook_filename}. Running nbval tests...")
# 2. Run pytest programmatically with nbval
# The --nbval flag enables the plugin, and the notebook filename specifies the target.
exit_code = pytest.main(["--nbval", notebook_filename])
# 3. Report results and clean up
# os.remove(notebook_filename) # Uncomment to clean up the notebook file after run
if exit_code == 0:
print(f"\nnbval tests passed for {notebook_filename}!")
else:
print(f"\nnbval tests failed for {notebook_filename} with exit code {exit_code}.")