From 64eed5caa457a6a01dba5813f704a31a40b6a0cc Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 1 Apr 2022 15:08:30 -0500 Subject: [PATCH] Add pytest and handle warnings (#6338) --- .github/workflows/build.yml | 23 +++---- .github/workflows/docs.yml | 4 +- MANIFEST.in | 2 + docs/source/conf.py | 2 +- notebook/app.py | 42 ++++++++---- pyproject.toml | 15 +++++ setup.cfg | 8 +++ tests/conftest.py | 130 ++++++++++++++++++++++++++++++++++++ tests/test_app.py | 22 ++++++ 9 files changed, 218 insertions(+), 30 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/test_app.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa6d06c794..afc2880c6c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,28 +39,21 @@ jobs: - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - - name: Install dependencies + - name: Install the package run: | - python -m pip install -U jupyter_packaging~=0.10 + python -m pip install ".[test]"" + jlpm run build:test - - name: Install the package + - name: Unit tests run: | - python -m pip install . + jlpm run test + pytest -vv || pytest -vv --lf + + - name: Integration Tests jupyter labextension list 2>&1 | grep -ie "@jupyter-notebook/lab-extension.*enabled.*ok" - jupyter server extension list 2>&1 | grep -ie "notebook.*enabled" - python -m jupyterlab.browser_check - - name: Lint - run: | - jlpm - jlpm run eslint:check - jlpm run prettier:check - - - name: Test - run: | - jlpm run build:test - jlpm run test - install: needs: [build] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 49159fbb42..78417689b6 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -31,5 +31,7 @@ jobs: run: | EXIT_STATUS=0 make -C docs/ html SPHINXOPTS="-W" || EXIT_STATUS=$? - pytest --nbval --current-env docs || EXIT_STATUS=$? + # Ignore warnings to work around + # # https://github.com/computationalmodelling/nbval/issues/180 + pytest --nbval --current-env -W default docs || EXIT_STATUS=$? exit $EXIT_STATUS diff --git a/MANIFEST.in b/MANIFEST.in index 743cf31fb3..e506ced66e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,6 +8,8 @@ include package.json include install.json include ts*.json +recursive-include tests * + graft notebook/labextension graft notebook/static graft notebook/templates diff --git a/docs/source/conf.py b/docs/source/conf.py index 078c0b1c01..dc10ab8609 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -96,7 +96,7 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -_version_py = "../../notebook/_version.py" +_version_py = os.path.join(here, "../../notebook/_version.py") version_ns = {} exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # The short X.Y version. diff --git a/notebook/app.py b/notebook/app.py index 1354bb125c..da0980fafd 100644 --- a/notebook/app.py +++ b/notebook/app.py @@ -17,7 +17,7 @@ from notebook_shim.shim import NotebookConfigShimMixin from tornado import web from tornado.gen import maybe_future -from traitlets import Bool +from traitlets import Bool, default from ._version import __version__ @@ -181,11 +181,6 @@ class JupyterNotebookApp(NotebookConfigShimMixin, LabServerApp): file_url_prefix = "/notebooks" load_other_extensions = True app_dir = app_dir - app_settings_dir = pjoin(app_dir, "settings") - schemas_dir = pjoin(app_dir, "schemas") - themes_dir = pjoin(app_dir, "themes") - user_settings_dir = get_user_settings_dir() - workspaces_dir = get_workspaces_dir() subcommands = {} expose_app_in_browser = Bool( @@ -206,6 +201,34 @@ class JupyterNotebookApp(NotebookConfigShimMixin, LabServerApp): "Whether to enable collaborative mode.", ) + @default("static_dir") + def _default_static_dir(self): + return os.path.join(HERE, "static") + + @default("templates_dir") + def _default_templates_dir(self): + return os.path.join(HERE, "templates") + + @default("app_settings_dir") + def _default_app_settings_dir(self): + return pjoin(app_dir, "settings") + + @default("schemas_dir") + def _default_schemas_dir(self): + return pjoin(app_dir, "schemas") + + @default("themes_dir") + def _default_themes_dir(self): + return pjoin(app_dir, "themes") + + @default("user_settings_dir") + def _default_user_settings_dir(self): + return get_user_settings_dir() + + @default("workspaces_dir") + def _default_workspaces_dir(self): + return get_workspaces_dir() + def initialize_handlers(self): self.handlers.append( ( @@ -222,13 +245,6 @@ def initialize_handlers(self): self.handlers.append(("/terminals/(.*)", TerminalHandler)) super().initialize_handlers() - def initialize_templates(self): - super().initialize_templates() - self.static_dir = os.path.join(HERE, "static") - self.templates_dir = os.path.join(HERE, "templates") - self.static_paths = [self.static_dir] - self.template_paths = [self.templates_dir] - def initialize_settings(self): super().initialize_settings() diff --git a/pyproject.toml b/pyproject.toml index e856ee131d..15079fdc95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,3 +18,18 @@ npm = ["jlpm"] [tool.check-manifest] ignore = ["app/**", "binder/**", "buildutils/**", "docs/**", "packages/**", "codecov.yml", "*.json", "yarn.lock", "readthedocs.yml", ".bumpversion.cfg", ".*", "lint-staged.config.js", "*.svg", "notebook/labextension/**", "notebook/schemas/**", "notebook/static/**", "notebook/template/**", "ui-tests/**"] + +[tool.pytest.ini_options] +addopts = "-raXs --durations 10 --color=yes --doctest-modules" +testpaths = [ + "tests/" +] +timeout = 300 +# Restore this setting to debug failures +# timeout_method = "thread" +filterwarnings = [ + "error", + # Pending release of https://github.com/jupyterlab/jupyterlab_server/pull/259 + "ignore:metadata:DeprecationWarning", + "ignore:There is no current event loop:DeprecationWarning", +] diff --git a/setup.cfg b/setup.cfg index cd546b627a..7af05592a7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,9 +42,17 @@ test = pytest-cov requests pytest-tornasync + pytest-timeout pytest-console-scripts ipykernel pre-commit + jupyterlab_server[test] + +[options.packages.find] +exclude = + docs.* + tests + tests.* [options.entry_points] console_scripts = diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000..f3efe90371 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,130 @@ +import json +import os +import os.path as osp +import shutil +from importlib.resources import path +from os.path import join as pjoin + +import pytest + +from notebook.app import JupyterNotebookApp + +pytest_plugins = ["jupyter_server.pytest_plugin"] + + +def mkdir(tmp_path, *parts): + path = tmp_path.joinpath(*parts) + if not path.exists(): + path.mkdir(parents=True) + return path + + +app_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "app_settings")) +user_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "user_settings")) +schemas_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "schemas")) +workspaces_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "workspaces")) +labextensions_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "labextensions_dir")) + + +@pytest.fixture +def make_notebook_app( + jp_root_dir, + jp_template_dir, + app_settings_dir, + user_settings_dir, + schemas_dir, + workspaces_dir, + labextensions_dir, +): + def _make_notebook_app(**kwargs): + + return JupyterNotebookApp( + static_dir=str(jp_root_dir), + templates_dir=str(jp_template_dir), + app_url="/", + app_settings_dir=str(app_settings_dir), + user_settings_dir=str(user_settings_dir), + schemas_dir=str(schemas_dir), + workspaces_dir=str(workspaces_dir), + extra_labextensions_path=[str(labextensions_dir)], + ) + + # Create the index files. + index = jp_template_dir.joinpath("index.html") + index.write_text( + """ + + + + {{page_config['appName'] | e}} + + + {# Copy so we do not modify the page_config with updates. #} + {% set page_config_full = page_config.copy() %} + {# Set a dummy variable - we just want the side effect of the update. #} + {% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} + + + + + +""" + ) + + # Copy the schema files. + test_data = str(path("jupyterlab_server", "test_data")) + src = pjoin(test_data, "schemas", "@jupyterlab") + dst = pjoin(str(schemas_dir), "@jupyterlab") + if os.path.exists(dst): + shutil.rmtree(dst) + shutil.copytree(src, dst) + + # Create the federated extensions + for name in ["apputils-extension", "codemirror-extension"]: + target_name = name + "-federated" + target = pjoin(str(labextensions_dir), "@jupyterlab", target_name) + src = pjoin(test_data, "schemas", "@jupyterlab", name) + dst = pjoin(target, "schemas", "@jupyterlab", target_name) + if osp.exists(dst): + shutil.rmtree(dst) + shutil.copytree(src, dst) + with open(pjoin(target, "package.orig.json"), "w") as fid: + data = dict(name=target_name, jupyterlab=dict(extension=True)) + json.dump(data, fid) + + # Copy the overrides file. + src = pjoin(test_data, "app-settings", "overrides.json") + dst = pjoin(str(app_settings_dir), "overrides.json") + if os.path.exists(dst): + os.remove(dst) + shutil.copyfile(src, dst) + + # Copy workspaces. + data = pjoin(test_data, "workspaces") + for item in os.listdir(data): + src = pjoin(data, item) + dst = pjoin(str(workspaces_dir), item) + if os.path.exists(dst): + os.remove(dst) + shutil.copy(src, str(workspaces_dir)) + + return _make_notebook_app + + +@pytest.fixture +def notebookapp(jp_serverapp, make_notebook_app): + app = make_notebook_app() + app._link_jupyter_server_extension(jp_serverapp) + app.initialize() + return app diff --git a/tests/test_app.py b/tests/test_app.py new file mode 100644 index 0000000000..89482cd229 --- /dev/null +++ b/tests/test_app.py @@ -0,0 +1,22 @@ +import pytest + + +@pytest.fixture +def notebooks(jp_create_notebook, notebookapp): + nbpaths = ( + "notebook1.ipynb", + "jlab_test_notebooks/notebook2.ipynb", + "jlab_test_notebooks/level2/notebook3.ipynb", + ) + for nb in nbpaths: + jp_create_notebook(nb) + return nbpaths + + +async def test_notebook_handler(notebooks, jp_fetch): + for nbpath in notebooks: + r = await jp_fetch("/", nbpath) + assert r.code == 200 + # Check that the lab template is loaded + html = r.body.decode() + assert "Jupyter Notebook" in html