Skip to content

Commit 64eed5c

Browse files
authored
Add pytest and handle warnings (#6338)
1 parent 0390be2 commit 64eed5c

File tree

9 files changed

+218
-30
lines changed

9 files changed

+218
-30
lines changed

.github/workflows/build.yml

+8-15
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,21 @@ jobs:
3939
- name: Base Setup
4040
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
4141

42-
- name: Install dependencies
42+
- name: Install the package
4343
run: |
44-
python -m pip install -U jupyter_packaging~=0.10
44+
python -m pip install ".[test]""
45+
jlpm run build:test
4546
46-
- name: Install the package
47+
- name: Unit tests
4748
run: |
48-
python -m pip install .
49+
jlpm run test
50+
pytest -vv || pytest -vv --lf
51+
52+
- name: Integration Tests
4953
jupyter labextension list 2>&1 | grep -ie "@jupyter-notebook/lab-extension.*enabled.*ok" -
5054
jupyter server extension list 2>&1 | grep -ie "notebook.*enabled" -
5155
python -m jupyterlab.browser_check
5256

53-
- name: Lint
54-
run: |
55-
jlpm
56-
jlpm run eslint:check
57-
jlpm run prettier:check
58-
59-
- name: Test
60-
run: |
61-
jlpm run build:test
62-
jlpm run test
63-
6457
install:
6558
needs: [build]
6659
runs-on: ${{ matrix.os }}

.github/workflows/docs.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ jobs:
3131
run: |
3232
EXIT_STATUS=0
3333
make -C docs/ html SPHINXOPTS="-W" || EXIT_STATUS=$?
34-
pytest --nbval --current-env docs || EXIT_STATUS=$?
34+
# Ignore warnings to work around
35+
# # https://github.com/computationalmodelling/nbval/issues/180
36+
pytest --nbval --current-env -W default docs || EXIT_STATUS=$?
3537
exit $EXIT_STATUS

MANIFEST.in

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ include package.json
88
include install.json
99
include ts*.json
1010

11+
recursive-include tests *
12+
1113
graft notebook/labextension
1214
graft notebook/static
1315
graft notebook/templates

docs/source/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696
# |version| and |release|, also used in various other places throughout the
9797
# built documents.
9898
#
99-
_version_py = "../../notebook/_version.py"
99+
_version_py = os.path.join(here, "../../notebook/_version.py")
100100
version_ns = {}
101101
exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns)
102102
# The short X.Y version.

notebook/app.py

+29-13
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from notebook_shim.shim import NotebookConfigShimMixin
1818
from tornado import web
1919
from tornado.gen import maybe_future
20-
from traitlets import Bool
20+
from traitlets import Bool, default
2121

2222
from ._version import __version__
2323

@@ -181,11 +181,6 @@ class JupyterNotebookApp(NotebookConfigShimMixin, LabServerApp):
181181
file_url_prefix = "/notebooks"
182182
load_other_extensions = True
183183
app_dir = app_dir
184-
app_settings_dir = pjoin(app_dir, "settings")
185-
schemas_dir = pjoin(app_dir, "schemas")
186-
themes_dir = pjoin(app_dir, "themes")
187-
user_settings_dir = get_user_settings_dir()
188-
workspaces_dir = get_workspaces_dir()
189184
subcommands = {}
190185

191186
expose_app_in_browser = Bool(
@@ -206,6 +201,34 @@ class JupyterNotebookApp(NotebookConfigShimMixin, LabServerApp):
206201
"Whether to enable collaborative mode.",
207202
)
208203

204+
@default("static_dir")
205+
def _default_static_dir(self):
206+
return os.path.join(HERE, "static")
207+
208+
@default("templates_dir")
209+
def _default_templates_dir(self):
210+
return os.path.join(HERE, "templates")
211+
212+
@default("app_settings_dir")
213+
def _default_app_settings_dir(self):
214+
return pjoin(app_dir, "settings")
215+
216+
@default("schemas_dir")
217+
def _default_schemas_dir(self):
218+
return pjoin(app_dir, "schemas")
219+
220+
@default("themes_dir")
221+
def _default_themes_dir(self):
222+
return pjoin(app_dir, "themes")
223+
224+
@default("user_settings_dir")
225+
def _default_user_settings_dir(self):
226+
return get_user_settings_dir()
227+
228+
@default("workspaces_dir")
229+
def _default_workspaces_dir(self):
230+
return get_workspaces_dir()
231+
209232
def initialize_handlers(self):
210233
self.handlers.append(
211234
(
@@ -222,13 +245,6 @@ def initialize_handlers(self):
222245
self.handlers.append(("/terminals/(.*)", TerminalHandler))
223246
super().initialize_handlers()
224247

225-
def initialize_templates(self):
226-
super().initialize_templates()
227-
self.static_dir = os.path.join(HERE, "static")
228-
self.templates_dir = os.path.join(HERE, "templates")
229-
self.static_paths = [self.static_dir]
230-
self.template_paths = [self.templates_dir]
231-
232248
def initialize_settings(self):
233249
super().initialize_settings()
234250

pyproject.toml

+15
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,18 @@ npm = ["jlpm"]
1818

1919
[tool.check-manifest]
2020
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/**"]
21+
22+
[tool.pytest.ini_options]
23+
addopts = "-raXs --durations 10 --color=yes --doctest-modules"
24+
testpaths = [
25+
"tests/"
26+
]
27+
timeout = 300
28+
# Restore this setting to debug failures
29+
# timeout_method = "thread"
30+
filterwarnings = [
31+
"error",
32+
# Pending release of https://github.com/jupyterlab/jupyterlab_server/pull/259
33+
"ignore:metadata:DeprecationWarning",
34+
"ignore:There is no current event loop:DeprecationWarning",
35+
]

setup.cfg

+8
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,17 @@ test =
4242
pytest-cov
4343
requests
4444
pytest-tornasync
45+
pytest-timeout
4546
pytest-console-scripts
4647
ipykernel
4748
pre-commit
49+
jupyterlab_server[test]
50+
51+
[options.packages.find]
52+
exclude =
53+
docs.*
54+
tests
55+
tests.*
4856

4957
[options.entry_points]
5058
console_scripts =

tests/conftest.py

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import json
2+
import os
3+
import os.path as osp
4+
import shutil
5+
from importlib.resources import path
6+
from os.path import join as pjoin
7+
8+
import pytest
9+
10+
from notebook.app import JupyterNotebookApp
11+
12+
pytest_plugins = ["jupyter_server.pytest_plugin"]
13+
14+
15+
def mkdir(tmp_path, *parts):
16+
path = tmp_path.joinpath(*parts)
17+
if not path.exists():
18+
path.mkdir(parents=True)
19+
return path
20+
21+
22+
app_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "app_settings"))
23+
user_settings_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "user_settings"))
24+
schemas_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "schemas"))
25+
workspaces_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "workspaces"))
26+
labextensions_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "labextensions_dir"))
27+
28+
29+
@pytest.fixture
30+
def make_notebook_app(
31+
jp_root_dir,
32+
jp_template_dir,
33+
app_settings_dir,
34+
user_settings_dir,
35+
schemas_dir,
36+
workspaces_dir,
37+
labextensions_dir,
38+
):
39+
def _make_notebook_app(**kwargs):
40+
41+
return JupyterNotebookApp(
42+
static_dir=str(jp_root_dir),
43+
templates_dir=str(jp_template_dir),
44+
app_url="/",
45+
app_settings_dir=str(app_settings_dir),
46+
user_settings_dir=str(user_settings_dir),
47+
schemas_dir=str(schemas_dir),
48+
workspaces_dir=str(workspaces_dir),
49+
extra_labextensions_path=[str(labextensions_dir)],
50+
)
51+
52+
# Create the index files.
53+
index = jp_template_dir.joinpath("index.html")
54+
index.write_text(
55+
"""
56+
<!DOCTYPE html>
57+
<html>
58+
<head>
59+
<title>{{page_config['appName'] | e}}</title>
60+
</head>
61+
<body>
62+
{# Copy so we do not modify the page_config with updates. #}
63+
{% set page_config_full = page_config.copy() %}
64+
{# Set a dummy variable - we just want the side effect of the update. #}
65+
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
66+
<script id="jupyter-config-data" type="application/json">
67+
{{ page_config_full | tojson }}
68+
</script>
69+
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
70+
<script type="text/javascript">
71+
/* Remove token from URL. */
72+
(function () {
73+
var parsedUrl = new URL(window.location.href);
74+
if (parsedUrl.searchParams.get('token')) {
75+
parsedUrl.searchParams.delete('token');
76+
window.history.replaceState({ }, '', parsedUrl.href);
77+
}
78+
})();
79+
</script>
80+
</body>
81+
</html>
82+
"""
83+
)
84+
85+
# Copy the schema files.
86+
test_data = str(path("jupyterlab_server", "test_data"))
87+
src = pjoin(test_data, "schemas", "@jupyterlab")
88+
dst = pjoin(str(schemas_dir), "@jupyterlab")
89+
if os.path.exists(dst):
90+
shutil.rmtree(dst)
91+
shutil.copytree(src, dst)
92+
93+
# Create the federated extensions
94+
for name in ["apputils-extension", "codemirror-extension"]:
95+
target_name = name + "-federated"
96+
target = pjoin(str(labextensions_dir), "@jupyterlab", target_name)
97+
src = pjoin(test_data, "schemas", "@jupyterlab", name)
98+
dst = pjoin(target, "schemas", "@jupyterlab", target_name)
99+
if osp.exists(dst):
100+
shutil.rmtree(dst)
101+
shutil.copytree(src, dst)
102+
with open(pjoin(target, "package.orig.json"), "w") as fid:
103+
data = dict(name=target_name, jupyterlab=dict(extension=True))
104+
json.dump(data, fid)
105+
106+
# Copy the overrides file.
107+
src = pjoin(test_data, "app-settings", "overrides.json")
108+
dst = pjoin(str(app_settings_dir), "overrides.json")
109+
if os.path.exists(dst):
110+
os.remove(dst)
111+
shutil.copyfile(src, dst)
112+
113+
# Copy workspaces.
114+
data = pjoin(test_data, "workspaces")
115+
for item in os.listdir(data):
116+
src = pjoin(data, item)
117+
dst = pjoin(str(workspaces_dir), item)
118+
if os.path.exists(dst):
119+
os.remove(dst)
120+
shutil.copy(src, str(workspaces_dir))
121+
122+
return _make_notebook_app
123+
124+
125+
@pytest.fixture
126+
def notebookapp(jp_serverapp, make_notebook_app):
127+
app = make_notebook_app()
128+
app._link_jupyter_server_extension(jp_serverapp)
129+
app.initialize()
130+
return app

tests/test_app.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
3+
4+
@pytest.fixture
5+
def notebooks(jp_create_notebook, notebookapp):
6+
nbpaths = (
7+
"notebook1.ipynb",
8+
"jlab_test_notebooks/notebook2.ipynb",
9+
"jlab_test_notebooks/level2/notebook3.ipynb",
10+
)
11+
for nb in nbpaths:
12+
jp_create_notebook(nb)
13+
return nbpaths
14+
15+
16+
async def test_notebook_handler(notebooks, jp_fetch):
17+
for nbpath in notebooks:
18+
r = await jp_fetch("/", nbpath)
19+
assert r.code == 200
20+
# Check that the lab template is loaded
21+
html = r.body.decode()
22+
assert "Jupyter Notebook" in html

0 commit comments

Comments
 (0)