diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 8ceaf34d..6aac58f0 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -118,6 +118,8 @@ common_aliases = { 'config': 'JupyterHub.config_file', 'db': 'JupyterHub.db_url', } +if isinstance(Application.aliases, dict): + common_aliases.update(Application.aliases) aliases = { 'base-url': 'JupyterHub.base_url', @@ -134,7 +136,10 @@ token_aliases = {} token_aliases.update(common_aliases) aliases.update(common_aliases) -flags = { +flags = {} +if isinstance(Application.flags, dict): + flags.update(Application.flags) +hub_flags = { 'debug': ( {'Application': {'log_level': logging.DEBUG}}, "set log level to logging.DEBUG (maximize logging output)", @@ -164,6 +169,7 @@ flags = { "[DEPRECATED in 0.7: does nothing]", ), } +flags.update(hub_flags) COOKIE_SECRET_BYTES = ( 32 # the number of bytes to use when generating new cookie secrets @@ -3191,6 +3197,18 @@ class JupyterHub(Application): self.http_server.stop() self.io_loop.add_callback(self.io_loop.stop) + async def start_show_config(self): + """Async wrapper around base start_show_config method""" + # We need this because of our custom launch_instance_async, + # where `start` isn't a blocking call, + # it only gets async things going + # and `--show-config` replaces `start` with a blocking function. + # so our version: + # 1. calls the original blocking method + # 2. stops the event loop when we are done, so the process exits + super().start_show_config() + self.exit(0) + async def launch_instance_async(self, argv=None): try: await self.initialize(argv) diff --git a/jupyterhub/tests/test_app.py b/jupyterhub/tests/test_app.py index 47f54165..d7bf90d2 100644 --- a/jupyterhub/tests/test_app.py +++ b/jupyterhub/tests/test_app.py @@ -1,10 +1,12 @@ """Test the JupyterHub entry point""" import binascii +import json import logging import os import re import sys import time +from distutils.version import LooseVersion as V from subprocess import check_output from subprocess import PIPE from subprocess import Popen @@ -13,6 +15,7 @@ from tempfile import TemporaryDirectory from unittest.mock import patch import pytest +import traitlets from traitlets.config import Config from .. import orm @@ -30,6 +33,27 @@ def test_help_all(): assert '--JupyterHub.ip' in out +@pytest.mark.skipif(V(traitlets.__version__) < V('5'), reason="requires traitlets 5") +def test_show_config(tmpdir): + tmpdir.chdir() + p = Popen( + [sys.executable, '-m', 'jupyterhub', '--show-config', '--debug'], stdout=PIPE + ) + p.wait(timeout=10) + out = p.stdout.read().decode('utf8', 'replace') + assert 'log_level' in out + + p = Popen( + [sys.executable, '-m', 'jupyterhub', '--show-config-json', '--debug'], + stdout=PIPE, + ) + p.wait(timeout=10) + out = p.stdout.read().decode('utf8', 'replace') + config = json.loads(out) + assert 'JupyterHub' in config + assert config["JupyterHub"]["log_level"] == 10 + + def test_token_app(): cmd = [sys.executable, '-m', 'jupyterhub', 'token'] out = check_output(cmd + ['--help-all']).decode('utf8', 'replace')