You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
12 KiB
Python
304 lines
12 KiB
Python
from functools import wraps
|
|
from copy import deepcopy
|
|
from traitlets import TraitError
|
|
from traitlets.config.loader import (
|
|
Config,
|
|
)
|
|
from jupyter_core.application import JupyterApp
|
|
from jupyter_server.serverapp import ServerApp
|
|
from jupyter_server.extension.application import ExtensionApp
|
|
from .traits import NotebookAppTraits
|
|
|
|
|
|
def NBAPP_AND_SVAPP_SHIM_MSG(trait_name): return (
|
|
"'{trait_name}' was found in both NotebookApp "
|
|
"and ServerApp. This is likely a recent change. "
|
|
"This config will only be set in NotebookApp. "
|
|
"Please check if you should also config these traits in "
|
|
"ServerApp for your purpose.".format(
|
|
trait_name=trait_name,
|
|
)
|
|
)
|
|
|
|
|
|
def NBAPP_TO_SVAPP_SHIM_MSG(trait_name): return (
|
|
"'{trait_name}' has moved from NotebookApp to "
|
|
"ServerApp. This config will be passed to ServerApp. "
|
|
"Be sure to update your config before "
|
|
"our next release.".format(
|
|
trait_name=trait_name,
|
|
)
|
|
)
|
|
|
|
|
|
def EXTAPP_AND_NBAPP_AND_SVAPP_SHIM_MSG(trait_name, extapp_name): return (
|
|
"'{trait_name}' is found in {extapp_name}, NotebookApp, "
|
|
"and ServerApp. This is a recent change. "
|
|
"This config will only be set in {extapp_name}. "
|
|
"Please check if you should also config these traits in "
|
|
"NotebookApp and ServerApp for your purpose.".format(
|
|
trait_name=trait_name,
|
|
extapp_name=extapp_name
|
|
)
|
|
)
|
|
|
|
|
|
def EXTAPP_AND_SVAPP_SHIM_MSG(trait_name, extapp_name): return (
|
|
"'{trait_name}' is found in both {extapp_name} "
|
|
"and ServerApp. This is a recent change. "
|
|
"This config will only be set in {extapp_name}. "
|
|
"Please check if you should also config these traits in "
|
|
"ServerApp for your purpose.".format(
|
|
trait_name=trait_name,
|
|
extapp_name=extapp_name
|
|
)
|
|
)
|
|
|
|
|
|
def EXTAPP_AND_NBAPP_SHIM_MSG(trait_name, extapp_name): return (
|
|
"'{trait_name}' is found in both {extapp_name} "
|
|
"and NotebookApp. This is a recent change. "
|
|
"This config will only be set in {extapp_name}. "
|
|
"Please check if you should also config these traits in "
|
|
"NotebookApp for your purpose.".format(
|
|
trait_name=trait_name,
|
|
extapp_name=extapp_name
|
|
)
|
|
)
|
|
|
|
|
|
def NOT_EXTAPP_NBAPP_AND_SVAPP_SHIM_MSG(trait_name, extapp_name): return (
|
|
"'{trait_name}' is not found in {extapp_name}, but "
|
|
"it was found in both NotebookApp "
|
|
"and ServerApp. This is likely a recent change. "
|
|
"This config will only be set in ServerApp. "
|
|
"Please check if you should also config these traits in "
|
|
"NotebookApp for your purpose.".format(
|
|
trait_name=trait_name,
|
|
extapp_name=extapp_name
|
|
)
|
|
)
|
|
|
|
|
|
def EXTAPP_TO_SVAPP_SHIM_MSG(trait_name, extapp_name): return (
|
|
"'{trait_name}' has moved from {extapp_name} to "
|
|
"ServerApp. Be sure to update your config before "
|
|
"our next release.".format(
|
|
trait_name=trait_name,
|
|
extapp_name=extapp_name
|
|
)
|
|
)
|
|
|
|
|
|
def EXTAPP_TO_NBAPP_SHIM_MSG(trait_name, extapp_name): return (
|
|
"'{trait_name}' has moved from {extapp_name} to "
|
|
"NotebookApp. Be sure to update your config before "
|
|
"our next release.".format(
|
|
trait_name=trait_name,
|
|
extapp_name=extapp_name
|
|
)
|
|
)
|
|
|
|
|
|
# A tuple of traits that shouldn't be shimmed or throw any
|
|
# warnings of any kind.
|
|
IGNORED_TRAITS = ("open_browser", "log_level", "log_format", "default_url", "show_banner")
|
|
|
|
|
|
class NotebookConfigShimMixin:
|
|
"""A Mixin class for shimming configuration from
|
|
NotebookApp to ServerApp. This class handles warnings, errors,
|
|
etc.
|
|
|
|
This class should be used during a transition period for apps
|
|
that are switching from depending on NotebookApp to ServerApp.
|
|
|
|
After one release cycle, this class can be safely removed
|
|
from the inheriting class.
|
|
|
|
TL;DR
|
|
|
|
The entry point to shimming is at the `update_config` method.
|
|
Once traits are loaded, before updating config across all
|
|
configurable objects, this class injects a method to reroute
|
|
traits to their *most logical* classes.
|
|
|
|
This class raises warnings when:
|
|
1. a trait has moved.
|
|
2. a trait is redundant across classes.
|
|
|
|
Redundant traits across multiple classes now must be
|
|
configured separately, *or* removed from their old
|
|
location to avoid this warning.
|
|
|
|
For a longer description on how individual traits are handled,
|
|
read the docstring under `shim_config_from_notebook_to_jupyter_server`.
|
|
"""
|
|
|
|
@wraps(JupyterApp.update_config)
|
|
def update_config(self, config):
|
|
# Shim traits to handle transition from NotebookApp to ServerApp
|
|
shimmed_config = self.shim_config_from_notebook_to_jupyter_server(
|
|
config)
|
|
super().update_config(shimmed_config)
|
|
|
|
def shim_config_from_notebook_to_jupyter_server(self, config):
|
|
"""Reorganizes a config object to reroute traits to their expected destinations
|
|
after the transition from NotebookApp to ServerApp.
|
|
|
|
A detailed explanation of how traits are handled:
|
|
|
|
1. If the argument is prefixed with `ServerApp`,
|
|
pass this trait to `ServerApp`.
|
|
2. If the argument is prefixed with `NotebookApp`,
|
|
* If the argument is a trait of `NotebookApp` *and* `ServerApp`:
|
|
1. Raise a warning—**for the extension developers**—that
|
|
there's redundant traits.
|
|
2. Pass trait to `NotebookApp`.
|
|
* If the argument is a trait of just `ServerApp` only
|
|
(i.e. the trait moved from `NotebookApp` to `ServerApp`):
|
|
1. Raise a "this trait has moved" **for the user**.
|
|
3. Pass trait to `ServerApp`.
|
|
* If the argument is a trait of `NotebookApp` only, pass trait
|
|
to `NotebookApp`.
|
|
* If the argument is not found in any object, raise a
|
|
`"Trait not found."` error.
|
|
3. If the argument is prefixed with `ExtensionApp`:
|
|
* If the argument is a trait of `ExtensionApp`,
|
|
`NotebookApp`, and `ServerApp`,
|
|
1. Raise a warning about redundancy.
|
|
2. Pass to the ExtensionApp
|
|
* If the argument is a trait of `ExtensionApp` and `NotebookApp`,
|
|
1. Raise a warning about redundancy.
|
|
2. Pass to ExtensionApp.
|
|
* If the argument is a trait of `ExtensionApp` and `ServerApp`,
|
|
1. Raise a warning about redundancy.
|
|
2. Pass to ExtensionApp.
|
|
* If the argument is a trait of `ExtensionApp`.
|
|
1. Pass to ExtensionApp.
|
|
* If the argument is a trait of `NotebookApp` but not `ExtensionApp`,
|
|
1. Raise a warning that trait has likely moved to NotebookApp.
|
|
2. Pass to NotebookApp
|
|
* If the arguent is a trait of `ServerApp` but not `ExtensionApp`,
|
|
1. Raise a warning that the trait has likely moved to ServerApp.
|
|
2. Pass to ServerApp.
|
|
* else
|
|
* Raise a TraitError: "trait not found."
|
|
"""
|
|
extapp_name = self.__class__.__name__
|
|
|
|
# Pop out the various configurable objects that we need to evaluate.
|
|
nbapp_config = config.pop('NotebookApp', {})
|
|
svapp_config = config.pop('ServerApp', {})
|
|
extapp_config = config.pop(extapp_name, {})
|
|
|
|
# Created shimmed configs.
|
|
# Leave the rest of the config alone.
|
|
config_shim = deepcopy(config)
|
|
svapp_config_shim = {}
|
|
nbapp_config_shim = {}
|
|
extapp_config_shim = {}
|
|
|
|
extapp_traits = (
|
|
self.__class__.class_trait_names() +
|
|
ExtensionApp.class_trait_names()
|
|
)
|
|
svapp_traits = ServerApp.class_trait_names()
|
|
nbapp_traits = (
|
|
NotebookAppTraits.class_trait_names() +
|
|
ExtensionApp.class_trait_names()
|
|
)
|
|
|
|
# 1. Handle ServerApp traits.
|
|
svapp_config_shim.update(svapp_config)
|
|
|
|
# 2. Handle NotebookApp traits.
|
|
warning_msg = None
|
|
for trait_name, trait_value in nbapp_config.items():
|
|
in_svapp = trait_name in svapp_traits
|
|
in_nbapp = trait_name in nbapp_traits
|
|
if trait_name in IGNORED_TRAITS:
|
|
# Pass trait through without any warning message.
|
|
nbapp_config_shim.update({trait_name: trait_value})
|
|
elif in_svapp and in_nbapp:
|
|
warning_msg = NBAPP_AND_SVAPP_SHIM_MSG(trait_name)
|
|
nbapp_config_shim.update({trait_name: trait_value})
|
|
elif in_svapp:
|
|
warning_msg = NBAPP_TO_SVAPP_SHIM_MSG(trait_name)
|
|
svapp_config_shim.update({trait_name: trait_value})
|
|
elif in_nbapp:
|
|
nbapp_config_shim.update({trait_name: trait_value})
|
|
else:
|
|
raise TraitError("Trait, {}, not found.".format(trait_name))
|
|
|
|
# Raise a warning if it's given.
|
|
if warning_msg:
|
|
self.log.warning(warning_msg)
|
|
|
|
# 3. Handle ExtensionApp traits.
|
|
warning_msg = None
|
|
for trait_name, trait_value in extapp_config.items():
|
|
in_extapp = trait_name in extapp_traits
|
|
in_svapp = trait_name in svapp_traits
|
|
in_nbapp = trait_name in nbapp_traits
|
|
if trait_name in IGNORED_TRAITS:
|
|
# Pass trait through without any warning message.
|
|
extapp_config_shim.update({trait_name: trait_value})
|
|
elif all([in_extapp, in_svapp, in_nbapp]):
|
|
warning_msg = EXTAPP_AND_NBAPP_AND_SVAPP_SHIM_MSG(
|
|
trait_name,
|
|
extapp_name
|
|
)
|
|
extapp_config_shim.update({trait_name: trait_value})
|
|
elif in_extapp and in_svapp:
|
|
warning_msg = EXTAPP_AND_SVAPP_SHIM_MSG(
|
|
trait_name,
|
|
extapp_name
|
|
)
|
|
extapp_config_shim.update({trait_name: trait_value})
|
|
elif in_extapp and in_nbapp:
|
|
warning_msg = EXTAPP_AND_NBAPP_SHIM_MSG(
|
|
trait_name,
|
|
extapp_name
|
|
)
|
|
extapp_config_shim.update({trait_name: trait_value})
|
|
elif in_extapp:
|
|
extapp_config_shim.update({trait_name: trait_value})
|
|
elif in_svapp and in_nbapp:
|
|
warning_msg = NOT_EXTAPP_NBAPP_AND_SVAPP_SHIM_MSG(
|
|
trait_name,
|
|
extapp_name
|
|
)
|
|
svapp_config_shim.update({trait_name: trait_value})
|
|
elif in_svapp:
|
|
warning_msg = EXTAPP_TO_SVAPP_SHIM_MSG(
|
|
trait_name,
|
|
extapp_name
|
|
)
|
|
svapp_config_shim.update({trait_name: trait_value})
|
|
elif in_nbapp:
|
|
warning_msg = EXTAPP_TO_NBAPP_SHIM_MSG(
|
|
trait_name,
|
|
extapp_name
|
|
)
|
|
nbapp_config_shim.update({trait_name: trait_value})
|
|
else:
|
|
raise TraitError("Trait, {}, not found.".format(trait_name))
|
|
|
|
# Raise warning if one is given
|
|
if warning_msg:
|
|
self.log.warning(warning_msg)
|
|
|
|
# Build config for shimmed traits.
|
|
new_config = Config({
|
|
'NotebookApp': nbapp_config_shim,
|
|
'ServerApp': svapp_config_shim,
|
|
})
|
|
if extapp_config_shim:
|
|
new_config.update(Config({
|
|
self.__class__.__name__: extapp_config_shim
|
|
}))
|
|
# Update the full config with new values
|
|
config_shim.update(new_config)
|
|
return config_shim
|