mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-11 12:03:00 +00:00
simplify app mixin
get handler classes from instance attributes, rather than arguments simplifies API
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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):
|
||||
|
@@ -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()
|
Reference in New Issue
Block a user