Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle open_browser trait in ServerApp and ExtensionApp differently #375

Merged
merged 1 commit into from
Jan 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions jupyter_server/extension/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Unicode,
List,
Dict,
Bool,
default
)
from traitlets.config import Config
Expand Down Expand Up @@ -147,9 +148,20 @@ class method. This method can be set as a entry_point in
# A useful class property that subclasses can override to
# configure the underlying Jupyter Server when this extension
# is launched directly (using its `launch_instance` method).
serverapp_config = {
"open_browser": True
}
serverapp_config = {}

# Some subclasses will likely ovrride this trait to flip
# the default value to True if they offer a browser
# based frontend.
open_browser = Bool(
False,
help="""Whether to open in a browser after starting.
The specific browser used is platform dependent and
determined by the python standard library `webbrowser`
module, unless it is overridden using the --browser
(ServerApp.browser) configuration option.
"""
).tag(config=True)

# The extension name used to name the jupyter config
# file, jupyter_{name}_config.
Expand Down Expand Up @@ -365,6 +377,8 @@ def initialize_server(cls, argv=[], load_other_extensions=True, **kwargs):
config = Config(cls._jupyter_server_config())
serverapp = ServerApp.instance(**kwargs, argv=[], config=config)
serverapp.initialize(argv=argv, find_extensions=load_other_extensions)
# Inform the serverapp that this extension app started the app.
serverapp._starter_app_name = cls.name
return serverapp

def initialize(self):
Expand Down
51 changes: 49 additions & 2 deletions jupyter_server/serverapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,28 @@ def _default_allow_remote(self):
"""
)

# The name of the app that started this server (if not started directly).
# It is sometimes important to know if + which another app (say a server extension)
# started the serverapp to properly configure some traits.
# This trait should not be configured by users. It will likely be set by ExtensionApp.
_starter_app_name = Unicode(None, allow_none=True)

@validate('_starter_app_name')
def _validate_starter_app(self, proposal):
# Check that a previous server extension isn't named yet
value = proposal["value"]
if self._starter_app_name != None:
raise TraitError("Another extension was already named as the starter_server_extension.")
return value

@property
def starter_app(self):
"""Get the Extension that started this server."""
name = self._starter_app_name
if name is None:
return
return self.extension_manager.extension_points.get(name, None).app

open_browser = Bool(False, config=True,
help="""Whether to open in a browser after starting.
The specific browser used is platform dependent and
Expand All @@ -895,6 +917,31 @@ def _default_allow_remote(self):
(ServerApp.browser) configuration option.
""")


def _handle_browser_opening(self):
"""This method handles whether a browser should be opened.
By default, Jupyter Server doesn't try to open an browser. However,
it's many server extensions might want to open the browser by default.
This essentially toggles the default value for open_browser.

From a UX perspective, this needs to be surfaced to the user. The default
behavior of Jupyter Server switches, which can be confusing.
"""
# If the server was started by another application, use that applications
# trait for the open_browser trait. If that trait is not given, ignore
if self.starter_app:
try:
if self.starter_app.open_browser:
self.launch_browser()
# If the starter_app doesn't have an open_browser trait, ignore
# move on and don't start a browser.
except AttributeError:
pass
else:
if self.open_browser:
self.launch_browser()


browser = Unicode(u'', config=True,
help="""Specify what command to use to invoke a web
browser when starting the server. If not specified, the
Expand Down Expand Up @@ -1807,8 +1854,8 @@ def start_app(self):
self.write_server_info_file()
self.write_browser_open_file()

if self.open_browser:
self.launch_browser()
# Handle the browser opening.
self._handle_browser_opening()

if self.token and self._token_generated:
# log full URL with generated token, so there's a copy/pasteable link
Expand Down