simplify app mixin

get handler classes from instance attributes, rather than arguments

simplifies API
This commit is contained in:
Min RK
2020-07-31 10:27:32 +02:00
parent d0da677813
commit d2a42a69b0
4 changed files with 56 additions and 75 deletions

View File

@@ -4,3 +4,10 @@ Contains default notebook-app subclass and mixins
"""
from .app import main
from .app import SingleUserNotebookApp
from .mixins import HubAuthenticatedHandler
from .mixins import make_singleuser_app
# backward-compatibility
JupyterHubLoginHandler = SingleUserNotebookApp.login_handler_class
JupyterHubLogoutHandler = SingleUserNotebookApp.logout_handler_class
OAuthCallbackHandler = SingleUserNotebookApp.oauth_callback_handler_class

View File

@@ -2,12 +2,6 @@
- $JUPYTERHUB_SINGLEUSER_APP, the base Application class, to be wrapped in JupyterHub authentication.
default: notebook.notebookapp.NotebookApp
- $JUPYTERHUB_SINGLEUSER_PKG, e.g. notebook or jupyter_server.
Typically inferred from $JUPYTEHUB_SINGLEUSER_APP.
Package layout must include:
- base.handlers.JupyterHandler
- auth.login.LoginHandler
- auth.logout.LogoutHandler
"""
import os
@@ -18,38 +12,9 @@ from .mixins import make_singleuser_app
JUPYTERHUB_SINGLEUSER_APP = (
os.environ.get("JUPYTERHUB_SINGLEUSER_APP") or "notebook.notebookapp.NotebookApp"
)
JUPYTERHUB_SINGLEUSER_PKG = os.environ.get("JUPYTERHUB_SINGLEUSER_PKG") or "notebook"
App = import_item(JUPYTERHUB_SINGLEUSER_APP)
JUPYTERHUB_SINGLEUSER_PKG = os.environ.get("JUPYTERHUB_SINGLEUSER_PKG")
if not JUPYTERHUB_SINGLEUSER_PKG:
# guess notebook or jupyter_server based on App class
for cls in App.mro():
pkg = cls.__module__.split(".", 1)[0]
if pkg in {"notebook", "jupyter_server"}:
JUPYTERHUB_SINGLEUSER_PKG = pkg
break
else:
raise RuntimeError(
"Failed to infer JUPYTERHUB_SINGLEUSER_PKG from {}, please set it directly".format(
JUPYTERHUB_SINGLEUSER_APP
)
)
LoginHandler = import_item(pkg + ".auth.login.LoginHandler")
LogoutHandler = import_item(pkg + ".auth.logout.LogoutHandler")
# BaseHandler could be called JupyterHandler or old IPythonHandler
try:
BaseHandler = import_item(pkg + ".base.handlers.JupyterHandler")
except ImportError:
BaseHandler = import_item(pkg + ".base.handlers.IPythonHandler")
SingleUserNotebookApp = make_singleuser_app(
App,
LoginHandler=LoginHandler,
LogoutHandler=LogoutHandler,
BaseHandler=BaseHandler,
)
SingleUserNotebookApp = make_singleuser_app(App)
main = SingleUserNotebookApp.launch_instance

View File

@@ -31,6 +31,7 @@ from traitlets import Bool
from traitlets import Bytes
from traitlets import CUnicode
from traitlets import default
from traitlets import import_item
from traitlets import Integer
from traitlets import observe
from traitlets import TraitError
@@ -208,9 +209,6 @@ def _exclude_home(path_list):
yield p
from traitlets import HasTraits
class SingleUserNotebookAppMixin(Configurable):
"""A Subclass of the regular NotebookApp that is aware of the parent multiuser context."""
@@ -660,23 +658,57 @@ class SingleUserNotebookAppMixin(Configurable):
env.loader = ChoiceLoader([FunctionLoader(get_page), orig_loader])
def make_singleuser_app(App, LoginHandler, LogoutHandler, BaseHandler):
def detect_base_package(App):
"""Detect the base package for an App class
Will return 'notebook' or 'jupyter_server'
based on which package App subclasses from.
Will return None if neither is identified (e.g. fork package, or duck-typing).
"""
# guess notebook or jupyter_server based on App class inheritance
for cls in App.mro():
pkg = cls.__module__.split(".", 1)[0]
if pkg in {"notebook", "jupyter_server"}:
return pkg
return None
def make_singleuser_app(App):
"""Make and return a singleuser notebook app
given existing notebook or jupyter_server classes,
given existing notebook or jupyter_server Application classes,
mix-in jupyterhub auth.
Instances of App must have the following attributes defining classes:
- .login_handler_class
- .logout_handler_class
- .base_handler_class (only required if not a subclass of the default app
in jupyter_server or notebook)
App should be a subclass of `notebook.notebookapp.NotebookApp`
or `jupyter_server.serverapp.ServerApp`
Must be passed base classes for:
- App
- LoginHandler
- LogoutHandler
- BaseHandler
or `jupyter_server.serverapp.ServerApp`.
"""
# create handler classes from mixins + bases
empty_parent_app = App()
# detect base classes
LoginHandler = empty_parent_app.login_handler_class
LogoutHandler = empty_parent_app.logout_handler_class
BaseHandler = getattr(empty_parent_app, "base_handler_class", None)
if BaseHandler is None:
pkg = detect_base_package(App)
if pkg == "jupyter_server":
BaseHandler = import_item("jupyter_server.base.handlers.JupyterHandler")
elif pkg == "notebook":
BaseHandler = import_item("notebook.base.handlers.IPythonHandler")
else:
raise ValueError(
"{}.base_handler_class must be defined".format(App.__name__)
)
# create Handler classes from mixins + bases
class JupyterHubLoginHandler(JupyterHubLoginHandlerMixin, LoginHandler):
pass
@@ -687,13 +719,12 @@ def make_singleuser_app(App, LoginHandler, LogoutHandler, BaseHandler):
pass
# create merged aliases & flags
empty_parent_app = App()
merged_aliases = {}
merged_aliases.update(empty_parent_app.aliases)
merged_aliases.update(empty_parent_app.aliases or {})
merged_aliases.update(aliases)
merged_flags = {}
merged_flags.update(empty_parent_app.flags)
merged_flags.update(empty_parent_app.flags or {})
merged_flags.update(flags)
# create mixed-in App class, bringing it all together
class SingleUserNotebookApp(SingleUserNotebookAppMixin, App):

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env python
"""Extend regular notebook server to be aware of multiuser things."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from notebook.auth.login import LoginHandler
from notebook.auth.logout import LogoutHandler
from notebook.base.handlers import IPythonHandler
from notebook.notebookapp import NotebookApp
from .mixins import make_singleuser_app
SingleUserNotebookApp = make_singleuser_app(
NotebookApp=NotebookApp,
LoginHandler=LoginHandler,
LogoutHandler=LogoutHandler,
BaseHandler=IPythonHandler,
)
main = SingleUserNotebookApp.launch_instance
if __name__ == '__main__':
main()