diff --git a/dev_tools/notebooks/notebook_test.py b/dev_tools/notebooks/notebook_test.py index 5e4ec69e7b7..babc1a890bf 100644 --- a/dev_tools/notebooks/notebook_test.py +++ b/dev_tools/notebooks/notebook_test.py @@ -20,6 +20,8 @@ # tests ensure that notebooks are still working with the latest version of cirq. import os +import sys +import tempfile import pytest @@ -50,9 +52,41 @@ ] +@pytest.fixture +def require_packages_not_changed(): + """Verify notebook test does not change packages in the Python test environment. + + Raise AssertionError if the pre-existing set of Python packages changes in any way. + """ + # TODO: remove this after deprecation of Python 3.7 + if sys.version_info < (3, 8, 0): + return + import importlib.metadata + + packages_before = set((d.name, d.version) for d in importlib.metadata.distributions()) + yield + packages_after = set((d.name, d.version) for d in importlib.metadata.distributions()) + assert packages_after == packages_before + + +@pytest.fixture(scope='module') +def env_with_temporary_pip_target(): + """Setup system environment that tells pip to install packages to a temporary directory.""" + with tempfile.TemporaryDirectory(suffix='-notebook-site-packages') as tmpdirname: + pythonpath = ( + f'{tmpdirname}{os.pathsep}{os.environ["PYTHONPATH"]}' + if 'PYTHONPATH' in os.environ + else tmpdirname + ) + env = {**os.environ, 'PYTHONPATH': pythonpath, 'PIP_TARGET': tmpdirname} + yield env + + @pytest.mark.slow @pytest.mark.parametrize("notebook_path", filter_notebooks(list_all_notebooks(), SKIP_NOTEBOOKS)) -def test_notebooks_against_released_cirq(notebook_path): +def test_notebooks_against_released_cirq( + notebook_path, require_packages_not_changed, env_with_temporary_pip_target +): """Test that jupyter notebooks execute. In order to speed up the execution of these tests an auxiliary file may be supplied which @@ -73,7 +107,12 @@ def test_notebooks_against_released_cirq(notebook_path): papermill {rewritten_notebook_path} {out_path} {papermill_flags}""" result = shell_tools.run( - cmd, log_run_to_stderr=False, shell=True, check=False, capture_output=True + cmd, + log_run_to_stderr=False, + shell=True, + check=False, + capture_output=True, + env=env_with_temporary_pip_target, ) if result.returncode != 0: