diff --git a/requirements.txt b/requirements.txt index 7eec9e51..482c3a16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ black pytest pytest-cov tox -importnb \ No newline at end of file +importnb +watchdog diff --git a/tests/test_importnb.ipynb b/tests/test_importnb.ipynb new file mode 100644 index 00000000..6e3a38d3 --- /dev/null +++ b/tests/test_importnb.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [], + "source": [ + "from importnb import Notebook, Partial, reload, load_ipython_extension, unload_ipython_extension\n", + "from nbformat import v4\n", + "from pathlib import Path\n", + "import shutil, os, functools\n", + "from pytest import fixture, mark\n" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "source =\"\"\"\n", + "foo = 42\n", + "assert {}\n", + "bar= 100\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "def new_notebook(str='foo'):\n", + " return v4.writes(v4.new_notebook(cells=[\n", + " v4.new_code_cell(source.format(str))\n", + " ]))" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "@fixture(scope='function')\n", + "def single_file(request):\n", + " file = Path('foobar.ipynb')\n", + " file.write_text(new_notebook())\n", + " request.addfinalizer(functools.partial(os.remove, file))\n", + " return file" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "@fixture\n", + "def clean_up_file(single_file, request):\n", + " def clean_sys():\n", + " import sys\n", + " del sys.modules['foobar']\n", + " sys.path_importer_cache.clear()\n", + " request.addfinalizer(clean_sys)" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [], + "source": [ + "def validate_reload(module):\n", + " try:\n", + " reload(module)\n", + " assert False, \"\"\"The reload should fail.\"\"\"\n", + " except:\n", + " assert True, \"\"\"Cannot reload a file outside of a context manager\"\"\"\n", + "\n", + " with Notebook():\n", + " assert reload(module)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "def test_single_file_with_context(clean_up_file):\n", + " with Notebook():\n", + " import foobar\n", + " assert foobar.foo == 42 and foobar.bar == 100\n", + " \n", + " validate_reload(foobar)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@fixture\n", + "def extension(clean_up_file, request):\n", + " load_ipython_extension()\n", + " request.addfinalizer(unload_ipython_extension)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def test_single_with_extension(extension):\n", + " import foobar\n", + " assert foobar.foo == 42 and foobar.bar == 100" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "@mark.xfail\n", + "def test_single_file_relative(single_file):\n", + " with Notebook():\n", + " from . import foobar" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "@fixture\n", + "def single_directory(request):\n", + " root = Path('a_test_package')\n", + " root.mkdir(exist_ok=True)\n", + " (root / 'foobar.ipynb').write_text(new_notebook())\n", + " (root / 'failure.ipynb').write_text(new_notebook('False'))\n", + " (root / 'py.py').write_text(\"\"\"from . import foobar\\nbaz = 'foobar'\"\"\")\n", + " request.addfinalizer(functools.partial(shutil.rmtree, root))\n", + " return root" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@mark.xfail\n", + "def test_single_file_without_context():\n", + " import foobar" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "def test_package(single_directory):\n", + " with Notebook():\n", + " from a_test_package import foobar, py\n", + " \n", + " assert foobar.foo == 42 and foobar.bar == 100\n", + " assert py.baz == 'foobar'\n", + " assert py.foobar is foobar\n", + " validate_reload(foobar)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "@mark.xfail\n", + "def test_package_failure(single_directory):\n", + " with Notebook():\n", + " from a_test_package import failure" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "def test_package_failure_partial(single_directory):\n", + " with Partial():\n", + " from a_test_package import failure\n", + " \n", + " assert isinstance(failure.__exception__, AssertionError), \"\"\"\n", + " The wrong error was returned likely because of importnb.\"\"\"\n", + "\n", + " from traceback import print_tb\n", + " from io import StringIO\n", + " s = StringIO()\n", + " print_tb(failure.__exception__.__traceback__, file=s)\n", + " assert \"\"\"a_test_package/failure.ipynb\", line 11, in \\n\"\"\" in s.getvalue(), \"\"\"Traceback is not satisfied\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "p6", + "language": "python", + "name": "other-env" + }, + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tricks.yaml b/tricks.yaml new file mode 100644 index 00000000..d5495d94 --- /dev/null +++ b/tricks.yaml @@ -0,0 +1,6 @@ +tricks: +- watchdog.tricks.ShellCommandTrick: + patterns: + - ./tests/test_*.ipynb + shell_command: | + pytest tests/test_importnb.ipynb --verbose --capture=no