From 77fd8bc4808e6606af6ba0030cb2cb4aa36e0b57 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Sun, 6 May 2018 00:17:45 -0400 Subject: [PATCH] Convert the unittest to the pytest conventions (#27) * Pin wheel, twine, and setuptools versions to allow a markdown description on the warehouse * Rewrite the unittests as pytests and add a watcher for improved development in lab. * https://github.com/yaml/pyyaml/issues/126 install yaml from github to pass 3.7dev --- requirements.txt | 4 +- setup.py | 13 +- src/importnb/_version.py | 2 +- tests/test_importnb.ipynb | 241 ++++++++++++++++++++++++++++++++++++++ tricks.yaml | 6 + 5 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 tests/test_importnb.ipynb create mode 100644 tricks.yaml diff --git a/requirements.txt b/requirements.txt index 7eec9e5..cba11af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,6 @@ black pytest pytest-cov tox -importnb \ No newline at end of file +importnb +git+https://github.com/yaml/pyyaml.git +watchdog diff --git a/setup.py b/setup.py index e625ae6..d523f17 100644 --- a/setup.py +++ b/setup.py @@ -15,15 +15,24 @@ author="deathbeds", author_email="tony.fast@gmail.com", description="Import .ipynb files as modules in the system path.", + long_description=( (here / "readme.md").read_text() + "\n\n" + (here / "changelog.md").read_text() ), -# long_description_content_type='text/markdown', + + long_description_content_type='text/markdown', + setup_requires=[ + 'pytest-runner', + 'setuptools>=38.6.0', + 'twine>=1.11.0', + 'wheel>=0.31.0' + ], + url="https://github.com/deathbeds/importnb", python_requires=">=3.6", license="BSD-3-Clause", - setup_requires=['pytest-runner'], + tests_require=['pytest'], install_requires=[ "dataclasses", diff --git a/src/importnb/_version.py b/src/importnb/_version.py index 788da1f..fe404ae 100644 --- a/src/importnb/_version.py +++ b/src/importnb/_version.py @@ -1 +1 @@ -__version__ = "0.2.4" +__version__ = "0.2.5" diff --git a/tests/test_importnb.ipynb b/tests/test_importnb.ipynb new file mode 100644 index 0000000..6e3a38d --- /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 0000000..d5495d9 --- /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