I have some notebooks that I want to execute programmatically in a
pytest test. I can use
nbconvert and these both work great. But I also want to be able to patch various functions and classes that my notebook calls (i.e. source code that is not written in the notebook). Using the regular suite of patching/mocking tools doesn’t work I presume because the notebooks are not being run in
Let’s consider a super simple example:
from mymodule import bar bar()
def bar(): print("bar")
import nbformat from nbconvert.preprocessors import ExecutePreprocessor import mymodule def test_foo(monkeypatch): monkeypatch.setattr(mymodule, "bar", lambda: print("foo")) with open("notebook.ipynb") as f: nb = nbformat.read(f, as_version=4) ep = ExecutePreprocessor(timeout=600, kernel_name='python3') ep.preprocess(nb) # prints "bar"
The monkeypatching does not work here, we still print “bar” rather than “foo”. One way I have come up with is to modify the
nb object by inserting the following code into the notebook (e.g. in the first cell) after loading but before executing:
import mymodule import pytest mp = pytest.MonkeyPatch() mp.setattr(mymodule, "bar", lambda: print("foo"))
This works and we now print “foo” when the test runs but this is quite inelegant. My question is whether there is another nicer way to do this?