Execution and Coverage Reporting

The core component of the notebook execution API is the ExecuteCoveragePreprocessor class, which is a subclass of nbconvert.preprocessors.ExecutePreprocessor, that can additionally create code coverage analytics.

This class is called by execute_notebook(), which returns an ExecuteResult object.

In:
import ruamel.yaml as yaml
from pytest_notebook.execution import execute_notebook
from pytest_notebook.notebook import create_notebook, create_cell, dump_notebook
In:
notebook = create_notebook()
notebook.cells = [
    create_cell("""
from pytest_notebook import __version__
from pytest_notebook.notebook import create_notebook
print(__version__)
"""
    )
]
In:
result = execute_notebook(notebook, with_coverage=True)
result.notebook
Out:
{'nbformat': 4,
 'nbformat_minor': 2,
 'metadata': {'language_info': {'name': 'python',
   'version': '3.6.7',
   'mimetype': 'text/x-python',
   'codemirror_mode': {'name': 'ipython', 'version': 3},
   'pygments_lexer': 'ipython3',
   'nbconvert_exporter': 'python',
   'file_extension': '.py'}},
 'cells': [{'cell_type': 'code',
   'metadata': {},
   'execution_count': 1,
   'source': '\nfrom pytest_notebook import __version__\nfrom pytest_notebook.notebook import create_notebook\nprint(__version__)\n',
   'outputs': [{'output_type': 'stream',
     'name': 'stdout',
     'text': '0.6.0\n'}]}]}
In:
result.coverage_data()
Out:
<CoverageData lines={5} arcs=None tracers={0} runs=[0]>
In:
print(yaml.dump(result.coverage_dict))
lines:
  /Users/cjs14/GitHub/pytest-notebook/pytest_notebook/__init__.py: [4, 5]
  /Users/cjs14/GitHub/pytest-notebook/pytest_notebook/diffing.py: [1, 2, 3, 4, 5,
    7, 8, 9, 10, 11, 12, 24, 25, 66, 67, 98, 101, 116, 117, 162, 163]
  /Users/cjs14/GitHub/pytest-notebook/pytest_notebook/notebook.py: [1, 2, 3, 4, 5,
    6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 19, 21, 25, 26, 49, 50, 80, 81, 108, 109,
    112, 142, 151, 173, 174, 176, 178, 179, 180, 181, 184, 191, 192, 195, 202, 203,
    204, 205, 207, 208, 209, 210, 214, 245, 246, 252, 253, 260, 267, 275, 291, 292,
    293, 295, 308]
  /Users/cjs14/GitHub/pytest-notebook/pytest_notebook/resources/__init__.py: [1]
  /Users/cjs14/GitHub/pytest-notebook/pytest_notebook/utils.py: [1, 2, 4, 5, 6, 9,
    29, 52, 86, 99, 136, 138, 142, 144, 100, 102, 106, 108, 112, 32, 35, 40, 41, 44,
    45, 49, 114, 115, 116, 120, 122, 123, 124, 125, 126, 128, 134, 149, 151, 87, 89,
    97, 156]

The coverage can be limited to particular files or modules, by setting cov_source.

In:
result = execute_notebook(
    notebook, with_coverage=True, cov_source=['pytest_notebook.notebook'])
print(yaml.dump(result.coverage_dict))
lines:
  /Users/cjs14/GitHub/pytest-notebook/pytest_notebook/notebook.py: [1, 2, 3, 4, 5,
    6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 19, 21, 25, 26, 49, 50, 80, 81, 108, 109,
    112, 142, 151, 173, 174, 176, 178, 179, 180, 181, 184, 191, 192, 195, 202, 203,
    204, 205, 207, 208, 209, 210, 214, 245, 246, 252, 253, 260, 267, 275, 291, 292,
    293, 295, 308]

Integration with pytest-cov

If the pytest-cov plugin is installed, the NBRegressionFixture will be initialised with the settings and coverage.Coverage object, that pytest-cov has created.

If the --nb-coverage flag is set, then nb_regression will run coverage introspection, and merge the data back into the main Coverage object.

In:
%load_ext pytest_notebook.ipy_magic
In:
%%pytest --disable-warnings --color=yes --cov=pytest_notebook --nb-coverage --log-cli-level=info

import logging
import importlib_resources
from pytest_notebook import example_nbs

def test_notebook(nb_regression):
    logging.getLogger(__name__).info(nb_regression)
    with importlib_resources.path(example_nbs, "coverage.ipynb") as path:
        nb_regression.check(str(path))
============================= test session starts ==============================
platform darwin -- Python 3.6.7, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /private/var/folders/dm/b2qnkb_n3r72slmpxlfmcjvm00lbnd/T/tmpxcs1xsgm
plugins: cov-2.7.1, datadir-1.3.0, regressions-1.0.5, notebook-0.5.1
collected 1 item

test_ipycell.py::test_notebook
-------------------------------- live log call ---------------------------------
INFO     test_ipycell:test_ipycell.py:7 NBRegressionFixture(exec_notebook=True, exec_cwd=None, exec_allow_errors=False, exec_timeout=120, coverage=True, cov_config='.coveragerc', cov_source=('pytest_notebook',), cov_merge=<coverage.control.Coverage object at 0x103ec3e48>, post_processors=('coalesce_streams',), process_resources={}, diff_replace=(), diff_ignore=('/cells/*/outputs/*/traceback',), diff_use_color=True, diff_color_words=False, force_regen=False)
INFO     pytest_notebook.execution:execution.py:147 About to execute notebook with 1 cells
INFO     pytest_notebook.execution:execution.py:153 Executing notebook with kernel: python
INFO     pytest_notebook.execution:execution.py:155 Recording coverage for notebook
INFO     pytest_notebook.execution:execution.py:173 Executing cell 0
INFO     pytest_notebook.nb_regression:nb_regression.py:306 Merging coverage.
PASSED                                                                   [100%]

---------- coverage: platform darwin, python 3.6.7-final-0 -----------
Name                                                                          Stmts   Miss  Cover
-------------------------------------------------------------------------------------------------
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/__init__.py                   1      0   100%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/diffing.py                   83     40    52%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/example_nbs/__init__.py       0      0   100%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/execution.py                103     61    41%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/ipy_magic.py                 80     80     0%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/nb_regression.py            184    112    39%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/notebook.py                 140     74    47%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/plugin.py                   117     81    31%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/post_processors.py           93     69    26%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/resources/__init__.py         0      0   100%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/utils.py                     58     23    60%
-------------------------------------------------------------------------------------------------
TOTAL                                                                           859    540    37%

===================== 1 passed, 1 warnings in 3.73 seconds =====================
Coverage.py warning: Module pytest_notebook was previously imported, but not measured (module-not-measured)

This is also the case, when using the pytest file collection approach.

In:
%%pytest --disable-warnings --color=yes --cov=pytest_notebook --log-cli-level=info

---
[pytest]
nb_coverage = True
nb_test_files = True
---

***
(dump_notebook(notebook), "test_notebook1.ipynb")
***
============================= test session starts ==============================
platform darwin -- Python 3.6.7, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /private/var/folders/dm/b2qnkb_n3r72slmpxlfmcjvm00lbnd/T/tmpzc571yr2, inifile: pytest.ini
plugins: cov-2.7.1, datadir-1.3.0, regressions-1.0.5, notebook-0.5.1
collected 1 item

test_notebook1.ipynb::nbregression(test_notebook1)
-------------------------------- live log call ---------------------------------
INFO     pytest_notebook.execution:execution.py:147 About to execute notebook with 1 cells
INFO     pytest_notebook.execution:execution.py:153 Executing notebook with kernel: python
INFO     pytest_notebook.execution:execution.py:155 Recording coverage for notebook
INFO     pytest_notebook.execution:execution.py:173 Executing cell 0
INFO     pytest_notebook.nb_regression:nb_regression.py:306 Merging coverage.
FAILED                                                                   [100%]

=================================== FAILURES ===================================
____________________ notebook: nbregression(test_notebook1) ____________________
pytest_notebook.nb_regression.NBRegressionError:
--- expected
+++ obtained
## replaced (type changed from NoneType to int) /cells/0/execution_count:
-  None
+  1

## inserted before /cells/0/outputs/0:
+  output:
+    output_type: stream
+    name: stdout
+    text:
+      0.6.0

## added /metadata/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.6.7


------------------------------ Captured log call -------------------------------
INFO     pytest_notebook.execution:execution.py:147 About to execute notebook with 1 cells
INFO     pytest_notebook.execution:execution.py:153 Executing notebook with kernel: python
INFO     pytest_notebook.execution:execution.py:155 Recording coverage for notebook
INFO     pytest_notebook.execution:execution.py:173 Executing cell 0
INFO     pytest_notebook.nb_regression:nb_regression.py:306 Merging coverage.

---------- coverage: platform darwin, python 3.6.7-final-0 -----------
Name                                                                          Stmts   Miss  Cover
-------------------------------------------------------------------------------------------------
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/__init__.py                   1      0   100%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/diffing.py                   83     11    87%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/example_nbs/__init__.py       0      0   100%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/execution.py                103     61    41%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/ipy_magic.py                 80     80     0%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/nb_regression.py            184    112    39%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/notebook.py                 140     74    47%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/plugin.py                   117     70    40%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/post_processors.py           93     69    26%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/resources/__init__.py         0      0   100%
/Users/cjs14/GitHub/pytest-notebook/pytest_notebook/utils.py                     58     23    60%
-------------------------------------------------------------------------------------------------
TOTAL                                                                           859    500    42%

===================== 1 failed, 1 warnings in 3.49 seconds =====================
Coverage.py warning: Module pytest_notebook was previously imported, but not measured (module-not-measured)