QuantumLearning/tests/test_notebook_execution.py

71 lines
2 KiB
Python

from __future__ import annotations
import os
from pathlib import Path
import socket
import nbformat
from nbformat.validator import normalize
from nbclient import NotebookClient
import pytest
from quantum_learning import load_notebook_execution_plan, project_root
def _local_kernel_ports_available() -> bool:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("127.0.0.1", 0))
return True
except PermissionError:
return False
def _prepare_runtime_dirs() -> None:
root = project_root() / ".tmp_test_artifacts" / "notebook_execution"
ipython_dir = root / "ipython"
mpl_dir = root / "matplotlib"
ipython_dir.mkdir(parents=True, exist_ok=True)
mpl_dir.mkdir(parents=True, exist_ok=True)
os.environ.setdefault("IPYTHONDIR", str(ipython_dir))
os.environ.setdefault("MPLCONFIGDIR", str(mpl_dir))
os.environ.setdefault("MPLBACKEND", "Agg")
def _load_notebook(path: Path):
with path.open() as handle:
notebook = nbformat.read(handle, as_version=4)
normalize(notebook)
return notebook
@pytest.mark.notebook
@pytest.mark.parametrize(
"target",
load_notebook_execution_plan().targets,
ids=lambda target: target.identifier,
)
def test_execution_plan_notebooks_run_without_errors(target):
if not _local_kernel_ports_available():
pytest.skip("Notebook execution needs localhost kernel ports, which this sandbox blocks.")
_prepare_runtime_dirs()
notebook_path = project_root() / target.path
notebook = _load_notebook(notebook_path)
client = NotebookClient(
notebook,
kernel_name="python3",
timeout=target.timeout_seconds,
resources={"metadata": {"path": str(notebook_path.parent)}},
)
executed = client.execute()
error_outputs = [
output
for cell in executed.cells
for output in cell.get("outputs", [])
if output.get("output_type") == "error"
]
assert notebook_path.exists()
assert not error_outputs