Skip to content

Commit

Permalink
jupyterhub-singleuser as a Jupyter Server 2.0 extension
Browse files Browse the repository at this point in the history
mostly a copy (fork) of singleuser app
using public APIs instead of lots of patching.

opt-in via `JUPYTERHUB_SINGLEUSER_EXTENSION=1`

missing features:

- control panel link patch for nbclassic
  • Loading branch information
minrk committed Jan 19, 2023
1 parent 126f8d0 commit 242e24c
Show file tree
Hide file tree
Showing 11 changed files with 872 additions and 38 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/test.yml
Expand Up @@ -91,6 +91,8 @@ jobs:
selenium: selenium
- python: "3.11"
main_dependencies: main_dependencies
- python: "3.10"
serverextension: serverextension

steps:
# NOTE: In GitHub workflows, environment variables are set by writing
Expand All @@ -114,8 +116,8 @@ jobs:
echo "PGPASSWORD=hub[test/:?" >> $GITHUB_ENV
echo "JUPYTERHUB_TEST_DB_URL=postgresql://test_user:hub%5Btest%2F%3A%3F@127.0.0.1:5432/jupyterhub" >> $GITHUB_ENV
fi
if [ "${{ matrix.jupyter_server }}" != "" ]; then
echo "JUPYTERHUB_SINGLEUSER_APP=jupyterhub.tests.mockserverapp.MockServerApp" >> $GITHUB_ENV
if [ "${{ matrix.serverextension }}" != "" ]; then
echo "JUPYTERHUB_SINGLEUSER_EXTENSION=1" >> $GITHUB_ENV
fi
- uses: actions/checkout@v3
# NOTE: actions/setup-node@v3 make use of a cache within the GitHub base
Expand Down Expand Up @@ -163,6 +165,9 @@ jobs:
if [ "${{ matrix.db }}" == "postgres" ]; then
pip install psycopg2-binary
fi
if [ "${{ matrix.serverextension }}" != "" ]; then
pip install 'jupyter-server>=2'
fi
pip freeze
Expand Down
7 changes: 7 additions & 0 deletions jupyterhub/__init__.py
@@ -1,3 +1,10 @@
from ._version import __version__, version_info


def _jupyter_server_extension_points():
from .singleuser.extension import JupyterHubSingleUser

return [{"module": "jupyterhub", "app": JupyterHubSingleUser}]


__all__ = ["__version__", "version_info"]
5 changes: 4 additions & 1 deletion jupyterhub/services/auth.py
Expand Up @@ -243,7 +243,6 @@ def _api_url(self):
return 'http://127.0.0.1:8081' + url_path_join(self.hub_prefix, 'api')

api_token = Unicode(
os.getenv('JUPYTERHUB_API_TOKEN', ''),
help="""API key for accessing Hub API.
Default: $JUPYTERHUB_API_TOKEN
Expand All @@ -253,6 +252,10 @@ def _api_url(self):
""",
).tag(config=True)

@default("api_token")
def _default_api_token(self):
return os.getenv('JUPYTERHUB_API_TOKEN', '')

hub_prefix = Unicode(
'/hub/',
help="""The URL prefix for the Hub itself.
Expand Down
39 changes: 33 additions & 6 deletions jupyterhub/singleuser/__init__.py
Expand Up @@ -2,17 +2,44 @@
Contains default notebook-app subclass and mixins
"""
from .app import SingleUserNotebookApp, main
import os

from .mixins import HubAuthenticatedHandler, make_singleuser_app

if os.environ.get("JUPYTERHUB_SINGLEUSER_EXTENSION", "") not in ("", "0"):
# check for conflict in singleuser entrypoint environment variables
if os.environ.get("JUPYTERHUB_SINGLEUSER_APP", "") not in {
"",
"jupyter_server",
"jupyter-server",
"extension",
"jupyter_server.serverapp.ServerApp",
}:
ext = os.environ["JUPYTERHUB_SINGLEUSER_EXTENSION"]
app = os.environ["JUPYTERHUB_SINGLEUSER_APP"]
raise ValueError(
f"Cannot use JUPYTERHUB_SINGLEUSER_EXTENSION=1 with JUPYTERHUB_SINGLEUSER_APP={app}."
" Please pick one or the other."
)
_as_extension = True
from .extension import main
else:
_as_extension = False
try:
from .app import SingleUserNotebookApp, main
except ImportError:
# check for Jupyter Server 2.0 ?
from .extension import main
else:
# backward-compatibility
JupyterHubLoginHandler = SingleUserNotebookApp.login_handler_class
JupyterHubLogoutHandler = SingleUserNotebookApp.logout_handler_class
OAuthCallbackHandler = SingleUserNotebookApp.oauth_callback_handler_class


__all__ = [
"SingleUserNotebookApp",
"main",
"HubAuthenticatedHandler",
"make_singleuser_app",
]

# backward-compatibility
JupyterHubLoginHandler = SingleUserNotebookApp.login_handler_class
JupyterHubLogoutHandler = SingleUserNotebookApp.logout_handler_class
OAuthCallbackHandler = SingleUserNotebookApp.oauth_callback_handler_class
2 changes: 1 addition & 1 deletion jupyterhub/singleuser/__main__.py
@@ -1,4 +1,4 @@
from .app import main
from . import main

if __name__ == '__main__':
main()
11 changes: 11 additions & 0 deletions jupyterhub/singleuser/app.py
Expand Up @@ -16,6 +16,17 @@

JUPYTERHUB_SINGLEUSER_APP = os.environ.get("JUPYTERHUB_SINGLEUSER_APP")

# allow shortcut references
_app_shortcuts = {
"notebook": "notebook.notebookapp.NotebookApp",
"jupyter_server": "jupyter_server.serverapp.ServerApp",
"jupyter-server": "jupyter_server.serverapp.ServerApp",
"extension": "jupyter_server.serverapp.ServerApp",
}

JUPYTERHUB_SINGLEUSER_APP = _app_shortcuts.get(
JUPYTERHUB_SINGLEUSER_APP, JUPYTERHUB_SINGLEUSER_APP
)

if JUPYTERHUB_SINGLEUSER_APP:
App = import_item(JUPYTERHUB_SINGLEUSER_APP)
Expand Down

0 comments on commit 242e24c

Please sign in to comment.