Skip to content

Commit

Permalink
Mimic patch for decorator and pytest fixtures (#77)
Browse files Browse the repository at this point in the history
* Mimic patch for decorator and pytest fixtures
Fix #75

* Fix flake8

Co-authored-by: Fr茅d茅ric Collonval <frederic.collonval@ariadnext.com>
  • Loading branch information
fcollonval and Fr茅d茅ric Collonval committed Jan 7, 2021
1 parent 5fcca72 commit c82fc8f
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 10 deletions.
36 changes: 26 additions & 10 deletions testbook/testbook.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import nbformat
import functools
from unittest.mock import DEFAULT

try:
from pytest import fixture
except ImportError: # pragma: no cover
def fixture(func, *args, **kwargs):
return func
import nbformat

from .client import TestbookNotebookClient


class testbook:
"""`testbook` acts as function decorator or a context manager.
When the function/with statement exits the kernels started when
entering the function/with statement will be terminated.
If `testbook` is used as a decorator, the `TestbookNotebookClient`
will be passed as first argument to the decorated function.
"""
# Developer notes:
#
# To trick pytest, we mimic the API of unittest.mock.patch in testbook.
# Notably, the following elements are added:
# * attribute_name, Class attribute (see below)
# * new, Instance attribute (see __init__)
# * patchings, wrapper attributes (see __call__)

attribute_name = None

def __init__(self, nb, execute=None, timeout=60, kernel_name='python3', allow_errors=False):
self.execute = execute
self.client = TestbookNotebookClient(
Expand All @@ -19,6 +34,8 @@ def __init__(self, nb, execute=None, timeout=60, kernel_name='python3', allow_er
kernel_name=kernel_name
)

self.new = DEFAULT

def _prepare(self):
if self.execute is True:
self.client.execute()
Expand All @@ -34,12 +51,11 @@ def __exit__(self, *args):
self.client._cleanup_kernel()

def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs): # pragma: no cover
with self.client.setup_kernel():
self._prepare()
func(self.client, *args, **kwargs)

wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__

return fixture(wrapper)
wrapper.patchings = [self]
return wrapper
6 changes: 6 additions & 0 deletions testbook/tests/test_testbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ def test_testbook_decorator_with_markers(nb, cell_index_args, expected_result):
assert nb._cell_index(cell_index_args) == expected_result


@pytest.mark.parametrize("cell_index_args, expected_result", [(2, 2), ('hello', 1)])
@testbook('testbook/tests/resources/inject.ipynb', execute=True)
def test_testbook_decorator_with_markers_order_does_not_matter(nb, cell_index_args, expected_result):
assert nb._cell_index(cell_index_args) == expected_result


def test_testbook_execute_all_cells_context_manager():
with testbook('testbook/tests/resources/inject.ipynb', execute=True) as tb:
for cell in tb.cells[:-1]:
Expand Down

0 comments on commit c82fc8f

Please sign in to comment.