nbval
nbval copied to clipboard
Is it possible to mock an object globally for all notebooks, eg with conftest.py?
I have a suite of example notebooks that I wish to use as tests. Many use a python package to connect to a server, but when testing the syntax for making that connection is different. For example, in general the notebooks invoke Client() and because they're in the prod environment the connection requires no additional information, but the tests are run from a different runner which needs something like Client(additional_credentials).
Client is from an external library I cannot change and does not provide a good way to override the defaults from environment variables, etc. My plan was to mock the Client() during testing by using a session-scoped, autouse=True fixture in a conftest.py to inject the extra information into Client() calls. This works for regular pytests (.py files), but the notebooks evaluated by nbval do not have their Client() mocked over.
Schematic example:
client.py
class Client():
def __init__(self, creds):
self.x = creds
conftest.py
class ModifedClient():
def __init__(self, *args, **kwargs):
self.x = "some other creds"
@pytest.fixture(scope="session", autouse=True)
def patch_over_client(request):
patched = mock.patch('client.Client', side_effect=ModifiedClient)
active_mock = patched.start()
def unpatch():
patched.stop()
request.addfinalizer(unpatch)
calling_notebook.ipynb
# (pretend these are cells)
from client import Client
c = Client()
assert c.x == "some other creds"
Is there a way to make this work or a better pattern achieve the same result?
I don't think there's any great way to do this, because the notebook code is running in a separate process - nbval launches a Jupyter kernel, and sends the cells to that. It might be possible to hack something with .pth files or a sitecustomize.py (see the site module docs) to make code run when the kernel is starting up. But that definitely wouldn't be elegant, and I don't know quite how to ensure it's cleaned up at the right time.