Skip to content

Commit 273a5f5

Browse files
authored
Use jupyter_server instead of notebook (#927)
1 parent 3888f05 commit 273a5f5

File tree

16 files changed

+74
-70
lines changed

16 files changed

+74
-70
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
curl -L -o $HOME/.sbt/launchers/1.3.12/sbt-launch.jar https://repo1.maven.org/maven2/org/scala-sbt/sbt-launch/1.3.12/sbt-launch.jar
3838
- name: Install Python dependencies
3939
run: |
40-
python -m pip install --upgrade setuptools pip websocket-client flake8 pytest coverage codecov
40+
python -m pip install --upgrade setuptools pip websocket-client flake8 pytest pytest-tornasync ipykernel coverage codecov
4141
- name: Build Jupyter Enterprise Gateway conda env
4242
run: |
4343
SA="source $CONDA_HOME/bin/activate" make env
@@ -61,7 +61,7 @@ jobs:
6161
timeout_minutes: 3
6262
max_attempts: 1
6363
command: |
64-
pytest enterprise_gateway/tests
64+
pytest -v -s enterprise_gateway/tests
6565
- name: Run integration tests
6666
run: |
6767
SA="source $CONDA_HOME/bin/activate" make itest-yarn

Makefile

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ test-debug:
111111
test: TEST?=
112112
test: ## Run unit tests
113113
ifeq ($(TEST),)
114-
$(SA) $(ENV) && pytest -v $(TEST_DEBUG_OPTS) enterprise_gateway/tests
114+
$(SA) $(ENV) && pytest -v -s $(TEST_DEBUG_OPTS) enterprise_gateway/tests
115115
else
116116
# e.g., make test TEST="test_gatewayapp.TestGatewayAppConfig"
117-
$(SA) $(ENV) && pytest -v $(TEST_DEBUG_OPTS) enterprise_gateway/tests/$(TEST)
117+
$(SA) $(ENV) && pytest -v -s $(TEST_DEBUG_OPTS) enterprise_gateway/tests/$(TEST)
118118
endif
119119

120120
release: POST_SDIST=upload
@@ -173,21 +173,21 @@ ITEST_OPTIONS?=
173173

174174
ITEST_YARN_PORT?=8888
175175
ITEST_YARN_HOST?=localhost:$(ITEST_YARN_PORT)
176-
ITEST_YARN_TESTS?=enterprise_gateway.itests
176+
ITEST_YARN_TESTS?=enterprise_gateway/itests
177177

178178
ITEST_KERNEL_LAUNCH_TIMEOUT=120
179179

180180
LOG_LEVEL=INFO
181181

182182
itest-yarn-debug: ## Run integration tests (optionally) against docker demo (YARN) container with print statements
183-
make LOG_LEVEL=DEBUG TEST_DEBUG_OPTS="--nocapture --nologcapture --logging-level=10" itest-yarn
183+
make LOG_LEVEL=DEBUG TEST_DEBUG_OPTS="--log-level=10" itest-yarn
184184

185185
PREP_ITEST_YARN?=1
186186
itest-yarn: ## Run integration tests (optionally) against docker demo (YARN) container
187187
ifeq (1, $(PREP_ITEST_YARN))
188188
make itest-yarn-prep
189189
endif
190-
($(SA) $(ENV) && GATEWAY_HOST=$(ITEST_YARN_HOST) LOG_LEVEL=$(LOG_LEVEL) KERNEL_USERNAME=$(ITEST_USER) KERNEL_LAUNCH_TIMEOUT=$(ITEST_KERNEL_LAUNCH_TIMEOUT) SPARK_VERSION=$(SPARK_VERSION) ITEST_HOSTNAME_PREFIX=$(ITEST_HOSTNAME_PREFIX) nosetests -v $(TEST_DEBUG_OPTS) $(ITEST_YARN_TESTS))
190+
($(SA) $(ENV) && GATEWAY_HOST=$(ITEST_YARN_HOST) LOG_LEVEL=$(LOG_LEVEL) KERNEL_USERNAME=$(ITEST_USER) KERNEL_LAUNCH_TIMEOUT=$(ITEST_KERNEL_LAUNCH_TIMEOUT) SPARK_VERSION=$(SPARK_VERSION) ITEST_HOSTNAME_PREFIX=$(ITEST_HOSTNAME_PREFIX) pytest -v -s $(TEST_DEBUG_OPTS) $(ITEST_YARN_TESTS))
191191
@echo "Run \`docker logs itest-yarn\` to see enterprise-gateway log."
192192

193193
PREP_TIMEOUT?=60
@@ -201,7 +201,7 @@ itest-yarn-prep:
201201
# This should get cleaned up once docker support is more mature
202202
ITEST_DOCKER_PORT?=8889
203203
ITEST_DOCKER_HOST?=localhost:$(ITEST_DOCKER_PORT)
204-
ITEST_DOCKER_TESTS?=enterprise_gateway.itests.test_r_kernel.TestRKernelLocal enterprise_gateway.itests.test_python_kernel.TestPythonKernelLocal enterprise_gateway.itests.test_scala_kernel.TestScalaKernelLocal
204+
ITEST_DOCKER_TESTS?=enterprise_gateway/itests/test_r_kernel.py::TestRKernelLocal enterprise_gateway/itests/test_python_kernel.py::TestPythonKernelLocal enterprise_gateway/itests/test_scala_kernel.py::TestScalaKernelLocal
205205
ITEST_DOCKER_KERNELS=PYTHON_KERNEL_LOCAL_NAME=python_docker SCALA_KERNEL_LOCAL_NAME=scala_docker R_KERNEL_LOCAL_NAME=R_docker
206206

207207
itest-docker-debug: ## Run integration tests (optionally) against docker container with print statements
@@ -212,7 +212,7 @@ itest-docker: ## Run integration tests (optionally) against docker swarm
212212
ifeq (1, $(PREP_ITEST_DOCKER))
213213
make itest-docker-prep
214214
endif
215-
($(SA) $(ENV) && GATEWAY_HOST=$(ITEST_DOCKER_HOST) LOG_LEVEL=$(LOG_LEVEL) KERNEL_USERNAME=$(ITEST_USER) KERNEL_LAUNCH_TIMEOUT=$(ITEST_KERNEL_LAUNCH_TIMEOUT) $(ITEST_DOCKER_KERNELS) nosetests -v $(TEST_DEBUG_OPTS) $(ITEST_DOCKER_TESTS))
215+
($(SA) $(ENV) && GATEWAY_HOST=$(ITEST_DOCKER_HOST) LOG_LEVEL=$(LOG_LEVEL) KERNEL_USERNAME=$(ITEST_USER) KERNEL_LAUNCH_TIMEOUT=$(ITEST_KERNEL_LAUNCH_TIMEOUT) $(ITEST_DOCKER_KERNELS) pytest -v -s $(TEST_DEBUG_OPTS) $(ITEST_DOCKER_TESTS))
216216
@echo "Run \`docker service logs itest-docker\` to see enterprise-gateway log."
217217

218218
PREP_TIMEOUT?=60

enterprise_gateway/base/handlers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"""Tornado handlers for the base of the API."""
44

55
import json
6-
import notebook._version
7-
from notebook.base.handlers import APIHandler
6+
import jupyter_server._version
7+
from jupyter_server.base.handlers import APIHandler
88
from tornado import web
99
from ..mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin
1010
from .._version import __version__
@@ -15,14 +15,14 @@ class APIVersionHandler(TokenAuthorizationMixin,
1515
JSONErrorsMixin,
1616
APIHandler):
1717
""""
18-
Extends the notebook server base API handler with token auth, CORS, and
19-
JSON errors to produce version information for notebook and gateway.
18+
Extends the jupyter_server base API handler with token auth, CORS, and
19+
JSON errors to produce version information for jupyter_server and gateway.
2020
"""
2121
def get(self):
2222
# not authenticated, so give as few info as possible
23-
# to be backwards compatibile, use only 'version' for the notebook version
23+
# to be backwards compatibile, use only 'version' for the jupyter_server version
2424
# and be more specific for gateway_version
25-
self.finish(json.dumps({"version": notebook.__version__, "gateway_version": __version__}))
25+
self.finish(json.dumps({"version": jupyter_server.__version__, "gateway_version": __version__}))
2626

2727

2828
class NotFoundHandler(JSONErrorsMixin, web.RequestHandler):

enterprise_gateway/enterprisegatewayapp.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,16 @@
1414
import time
1515
import weakref
1616

17-
# Install the pyzmq ioloop. This has to be done before anything else from
18-
# tornado is imported.
1917
from zmq.eventloop import ioloop
20-
ioloop.install()
21-
2218
from tornado import httpserver
2319
from tornado import web
2420
from tornado.log import enable_pretty_logging
2521

2622
from traitlets.config import Configurable
2723
from jupyter_core.application import JupyterApp, base_aliases
2824
from jupyter_client.kernelspec import KernelSpecManager
29-
from notebook.notebookapp import random_ports
30-
from notebook.utils import url_path_join
25+
from jupyter_server.serverapp import random_ports
26+
from jupyter_server.utils import url_path_join
3127

3228
from ._version import __version__
3329

@@ -175,7 +171,7 @@ def init_webapp(self):
175171
Adds the various managers and web-front configuration values to the
176172
Tornado settings for reference by the handlers.
177173
"""
178-
# Enable the same pretty logging the notebook uses
174+
# Enable the same pretty logging the server uses
179175
enable_pretty_logging()
180176

181177
# Configure the tornado logging level too
@@ -204,7 +200,7 @@ def init_webapp(self):
204200
eg_list_kernels=self.list_kernels,
205201
eg_authorized_users=self.authorized_users,
206202
eg_unauthorized_users=self.unauthorized_users,
207-
# Also set the allow_origin setting used by notebook so that the
203+
# Also set the allow_origin setting used by jupyter_server so that the
208204
# check_origin method used everywhere respects the value
209205
allow_origin=self.allow_origin,
210206
# Always allow remote access (has been limited to localhost >= notebook 5.6)

enterprise_gateway/services/api/handlers.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"""Tornado handlers for kernel specs."""
44
import os
55

6-
from notebook.utils import maybe_future
7-
from tornado import gen, web
6+
from jupyter_server.utils import ensure_async
7+
from tornado import web
88
from ...mixins import CORSMixin
99

1010

@@ -25,14 +25,13 @@ def initialize(self):
2525
"""
2626
web.StaticFileHandler.initialize(self, path=os.path.dirname(__file__))
2727

28-
@gen.coroutine
29-
def get(self):
28+
async def get(self):
3029
"""Handler for a get on a specific handler
3130
"""
3231
resource_name, content_type = self.get_resource_metadata()
3332
self.set_header('Content-Type', content_type)
3433
res = web.StaticFileHandler.get(self, resource_name)
35-
yield maybe_future(res)
34+
await ensure_async(res)
3635

3736
def options(self, **kwargs):
3837
"""Method for properly handling CORS pre-flight"""

enterprise_gateway/services/kernels/handlers.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
import os
66

77
import tornado
8-
import notebook.services.kernels.handlers as notebook_handlers
8+
import jupyter_server.services.kernels.handlers as jupyter_server_handlers
99
from jupyter_client.jsonutil import date_default
10-
from tornado import gen, web
10+
from tornado import web
1111
from functools import partial
1212
from ...mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin
1313

1414

1515
class MainKernelHandler(TokenAuthorizationMixin,
1616
CORSMixin,
1717
JSONErrorsMixin,
18-
notebook_handlers.MainKernelHandler):
19-
"""Extends the notebook main kernel handler with token auth, CORS, and
18+
jupyter_server_handlers.MainKernelHandler):
19+
"""Extends the jupyter_server main kernel handler with token auth, CORS, and
2020
JSON errors.
2121
"""
2222

@@ -28,8 +28,7 @@ def env_whitelist(self):
2828
def env_process_whitelist(self):
2929
return self.settings['eg_env_process_whitelist']
3030

31-
@gen.coroutine
32-
def post(self):
31+
async def post(self):
3332
"""Overrides the super class method to manage env in the request body.
3433
3534
Max kernel limits are now enforced in RemoteMappingKernelManager.start_kernel().
@@ -88,13 +87,13 @@ def post(self):
8887
env=env,
8988
kernel_headers=kernel_headers)
9089
try:
91-
yield super(MainKernelHandler, self).post()
90+
await super(MainKernelHandler, self).post()
9291
finally:
9392
self.kernel_manager.start_kernel = orig_start
9493
else:
95-
yield super(MainKernelHandler, self).post()
94+
await super(MainKernelHandler, self).post()
9695

97-
def get(self):
96+
async def get(self):
9897
"""Overrides the super class method to honor the kernel listing
9998
configuration setting.
10099
@@ -108,7 +107,7 @@ def get(self):
108107
if not self.settings.get('eg_list_kernels'):
109108
raise tornado.web.HTTPError(403, 'Forbidden')
110109
else:
111-
super(MainKernelHandler, self).get()
110+
await super(MainKernelHandler, self).get()
112111

113112
def options(self, **kwargs):
114113
"""Method for properly handling CORS pre-flight"""
@@ -118,8 +117,8 @@ def options(self, **kwargs):
118117
class KernelHandler(TokenAuthorizationMixin,
119118
CORSMixin,
120119
JSONErrorsMixin,
121-
notebook_handlers.KernelHandler):
122-
"""Extends the notebook kernel handler with token auth, CORS, and
120+
jupyter_server_handlers.KernelHandler):
121+
"""Extends the jupyter_server kernel handler with token auth, CORS, and
123122
JSON errors.
124123
"""
125124

@@ -136,7 +135,7 @@ def get(self, kernel_id):
136135

137136

138137
default_handlers = []
139-
for path, cls in notebook_handlers.default_handlers:
138+
for path, cls in jupyter_server_handlers.default_handlers:
140139
if cls.__name__ in globals():
141140
# Use the same named class from here if it exists
142141
default_handlers.append((path, globals()[cls.__name__]))

enterprise_gateway/services/kernels/remotemanager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from tornado import web
1111
from ipython_genutils.py3compat import unicode_type
1212
from ipython_genutils.importstring import import_item
13-
from notebook.services.kernels.kernelmanager import AsyncMappingKernelManager
13+
from jupyter_server.services.kernels.kernelmanager import AsyncMappingKernelManager
1414
from jupyter_client.ioloop.manager import AsyncIOLoopKernelManager
1515
from traitlets import directional_link, log as traitlets_log
1616

enterprise_gateway/services/kernelspecs/handlers.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"""Tornado handlers for kernel specs."""
44
import json
55

6-
from notebook.base.handlers import IPythonHandler
7-
from notebook.services.kernelspecs.handlers import is_kernelspec_model, kernelspec_model
8-
from notebook.utils import maybe_future, url_unescape
6+
from jupyter_server.base.handlers import JupyterHandler
7+
from jupyter_server.services.kernelspecs.handlers import is_kernelspec_model, kernelspec_model
8+
from jupyter_server.utils import ensure_async, url_unescape
99
from tornado import web
1010
from ...base.handlers import APIHandler
1111
from ...mixins import TokenAuthorizationMixin, CORSMixin, JSONErrorsMixin
@@ -75,7 +75,7 @@ async def get(self):
7575
if kernel_user:
7676
self.log.debug("Searching kernels for user '%s' " % kernel_user)
7777

78-
kspecs = await maybe_future(ksm.get_all_specs())
78+
kspecs = await ensure_async(ksm.get_all_specs())
7979

8080
list_kernels_found = []
8181
for kernel_name, kernel_info in kspecs.items():
@@ -117,7 +117,7 @@ async def get(self, kernel_name):
117117
if kernel_user_filter:
118118
kernel_user = kernel_user_filter[0].decode("utf-8")
119119
try:
120-
spec = await maybe_future(ksm.get_kernel_spec(kernel_name))
120+
spec = await ensure_async(ksm.get_kernel_spec(kernel_name))
121121
except KeyError:
122122
raise web.HTTPError(404, u'Kernel spec %s not found' % kernel_name)
123123
if is_kernelspec_model(spec):
@@ -139,7 +139,7 @@ class KernelSpecResourceHandler(TokenAuthorizationMixin,
139139
CORSMixin,
140140
JSONErrorsMixin,
141141
web.StaticFileHandler,
142-
IPythonHandler):
142+
JupyterHandler):
143143
SUPPORTED_METHODS = ('GET', 'HEAD')
144144

145145
@property
@@ -153,7 +153,7 @@ def initialize(self):
153153
async def get(self, kernel_name, path, include_body=True):
154154
ksm = self.kernel_spec_cache
155155
try:
156-
kernelspec = await maybe_future(ksm.get_kernel_spec(kernel_name))
156+
kernelspec = await ensure_async(ksm.get_kernel_spec(kernel_name))
157157
self.root = kernelspec.resource_dir
158158
except KeyError as e:
159159
raise web.HTTPError(404,
@@ -168,7 +168,7 @@ def head(self, kernel_name, path):
168168

169169
kernel_name_regex = r"(?P<kernel_name>[\w\.\-%]+)"
170170

171-
# Extends the default handlers from the notebook package with token auth, CORS
171+
# Extends the default handlers from the jupyter_server package with token auth, CORS
172172
# and JSON errors.
173173
default_handlers = [
174174
(r"/api/kernelspecs", MainKernelSpecHandler),

enterprise_gateway/services/kernelspecs/kernelspec_cache.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from watchdog.events import FileSystemEventHandler, FileMovedEvent
88

99
from jupyter_client.kernelspec import KernelSpec
10-
from notebook.utils import maybe_future
10+
from jupyter_server.utils import ensure_async
1111
from traitlets.config import SingletonConfigurable
1212
from traitlets.traitlets import CBool, default
1313
from typing import Dict, Optional, Union
@@ -56,7 +56,7 @@ async def get_kernel_spec(self, kernel_name: str) -> KernelSpec:
5656
"""
5757
kernelspec = self.get_item(kernel_name)
5858
if not kernelspec:
59-
kernelspec = await maybe_future(self.kernel_spec_manager.get_kernel_spec(kernel_name))
59+
kernelspec = await ensure_async(self.kernel_spec_manager.get_kernel_spec(kernel_name))
6060
if kernelspec:
6161
self.put_item(kernel_name, kernelspec)
6262
return kernelspec
@@ -77,7 +77,7 @@ async def get_all_specs(self) -> Dict[str, CacheItemType]:
7777
"""
7878
kernelspecs = self.get_all_items()
7979
if not kernelspecs:
80-
kernelspecs = await maybe_future(self.kernel_spec_manager.get_all_specs())
80+
kernelspecs = await ensure_async(self.kernel_spec_manager.get_all_specs())
8181
if kernelspecs:
8282
self.put_all_items(kernelspecs)
8383
return kernelspecs
@@ -182,8 +182,8 @@ def _initialize(self):
182182
self.observed_dirs.add(kernel_dir)
183183
self.observer.schedule(KernelSpecChangeHandler(self), kernel_dir, recursive=True)
184184
else:
185-
self.log.warn("KernelSpecCache: kernel_dir '{kernel_dir}' does not exist"
186-
" and will not be observed.".format(kernel_dir=kernel_dir))
185+
self.log.warning("KernelSpecCache: kernel_dir '{kernel_dir}' does not exist"
186+
" and will not be observed.".format(kernel_dir=kernel_dir))
187187
self.observer.start()
188188

189189
@staticmethod

enterprise_gateway/services/processproxies/conductor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from .processproxy import RemoteProcessProxy
1717

18-
from notebook.utils import url_unescape
18+
from jupyter_server.utils import url_unescape
1919

2020
from random import randint
2121

enterprise_gateway/services/processproxies/processproxy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from calendar import timegm
2626
from ipython_genutils.py3compat import with_metaclass
2727
from jupyter_client import launch_kernel, localinterfaces
28-
from notebook import _tz
28+
from jupyter_server import _tz
2929
from zmq.ssh import tunnel
3030

3131
try:

0 commit comments

Comments
 (0)