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 main
|
||||||
from .app import SingleUserNotebookApp
|
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.
|
- $JUPYTERHUB_SINGLEUSER_APP, the base Application class, to be wrapped in JupyterHub authentication.
|
||||||
default: notebook.notebookapp.NotebookApp
|
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
|
import os
|
||||||
|
|
||||||
@@ -18,38 +12,9 @@ from .mixins import make_singleuser_app
|
|||||||
JUPYTERHUB_SINGLEUSER_APP = (
|
JUPYTERHUB_SINGLEUSER_APP = (
|
||||||
os.environ.get("JUPYTERHUB_SINGLEUSER_APP") or "notebook.notebookapp.NotebookApp"
|
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)
|
App = import_item(JUPYTERHUB_SINGLEUSER_APP)
|
||||||
|
|
||||||
JUPYTERHUB_SINGLEUSER_PKG = os.environ.get("JUPYTERHUB_SINGLEUSER_PKG")
|
SingleUserNotebookApp = make_singleuser_app(App)
|
||||||
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
main = SingleUserNotebookApp.launch_instance
|
main = SingleUserNotebookApp.launch_instance
|
||||||
|
@@ -31,6 +31,7 @@ from traitlets import Bool
|
|||||||
from traitlets import Bytes
|
from traitlets import Bytes
|
||||||
from traitlets import CUnicode
|
from traitlets import CUnicode
|
||||||
from traitlets import default
|
from traitlets import default
|
||||||
|
from traitlets import import_item
|
||||||
from traitlets import Integer
|
from traitlets import Integer
|
||||||
from traitlets import observe
|
from traitlets import observe
|
||||||
from traitlets import TraitError
|
from traitlets import TraitError
|
||||||
@@ -208,9 +209,6 @@ def _exclude_home(path_list):
|
|||||||
yield p
|
yield p
|
||||||
|
|
||||||
|
|
||||||
from traitlets import HasTraits
|
|
||||||
|
|
||||||
|
|
||||||
class SingleUserNotebookAppMixin(Configurable):
|
class SingleUserNotebookAppMixin(Configurable):
|
||||||
"""A Subclass of the regular NotebookApp that is aware of the parent multiuser context."""
|
"""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])
|
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
|
"""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.
|
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`
|
App should be a subclass of `notebook.notebookapp.NotebookApp`
|
||||||
or `jupyter_server.serverapp.ServerApp`
|
or `jupyter_server.serverapp.ServerApp`.
|
||||||
|
|
||||||
Must be passed base classes for:
|
|
||||||
|
|
||||||
- App
|
|
||||||
- LoginHandler
|
|
||||||
- LogoutHandler
|
|
||||||
- BaseHandler
|
|
||||||
"""
|
"""
|
||||||
# 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):
|
class JupyterHubLoginHandler(JupyterHubLoginHandlerMixin, LoginHandler):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -687,13 +719,12 @@ def make_singleuser_app(App, LoginHandler, LogoutHandler, BaseHandler):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# create merged aliases & flags
|
# create merged aliases & flags
|
||||||
empty_parent_app = App()
|
|
||||||
merged_aliases = {}
|
merged_aliases = {}
|
||||||
merged_aliases.update(empty_parent_app.aliases)
|
merged_aliases.update(empty_parent_app.aliases or {})
|
||||||
merged_aliases.update(aliases)
|
merged_aliases.update(aliases)
|
||||||
|
|
||||||
merged_flags = {}
|
merged_flags = {}
|
||||||
merged_flags.update(empty_parent_app.flags)
|
merged_flags.update(empty_parent_app.flags or {})
|
||||||
merged_flags.update(flags)
|
merged_flags.update(flags)
|
||||||
# create mixed-in App class, bringing it all together
|
# create mixed-in App class, bringing it all together
|
||||||
class SingleUserNotebookApp(SingleUserNotebookAppMixin, App):
|
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