Merge pull request #11 from bollwyvl/nbext-pain-validation

More docstrings!
This commit is contained in:
Jonathan Frederic 2016-03-10 09:34:42 -08:00
commit e48015e08f

View File

@ -65,13 +65,15 @@ def check_nbextension(files, user=False, prefix=None, nbextensions_dir=None, sys
files : list(paths)
a list of relative paths within nbextensions.
user : bool [default: False]
Whether to check the user's .ipython/nbextensions directory.
Whether to check the user's .jupyter/nbextensions directory.
Otherwise check a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
prefix : str [optional]
Specify install prefix, if it should differ from default (e.g. /usr/local).
Will check prefix/share/jupyter/nbextensions
nbextensions_dir : str [optional]
Specify absolute path of nbextensions directory explicitly.
sys_prefix : bool [default: False]
Install into the sys.prefix, i.e. environment
"""
nbext = _get_nbextension_dir(user=user, sys_prefix=sys_prefix, prefix=prefix, nbextensions_dir=nbextensions_dir)
# make sure nbextensions dir exists
@ -240,6 +242,7 @@ def install_nbextension_python(package, overwrite=False, symlink=False,
return full_dests
def uninstall_nbextension(dest, require, user=False, sys_prefix=False, prefix=None,
nbextensions_dir=None, logger=None):
"""Uninstall a Javascript extension of the notebook
@ -290,7 +293,10 @@ def uninstall_nbextension(dest, require, user=False, sys_prefix=False, prefix=No
def uninstall_nbextension_python(package,
user=False, sys_prefix=False, prefix=None, nbextensions_dir=None,
logger=None):
"""Uninstall an nbextension bundled in a Python package."""
"""Uninstall an nbextension bundled in a Python package.
See parameters of `install_nbextension_python`
"""
m, nbexts = _get_nbextension_metadata(package)
for nbext in nbexts:
dest = nbext['dest']
@ -301,8 +307,28 @@ def uninstall_nbextension_python(package,
prefix=prefix, nbextensions_dir=nbextensions_dir, logger=logger)
def _set_nbextension_state(section, require, state, user, sys_prefix,
logger=None):
def _set_nbextension_state(section, require, state,
user=False, sys_prefix=False, logger=None):
"""Set whether the section's frontend should require the named nbextension
Returns True if the final state is the one requested.
Parameters
----------
section : string
The section of the server to change, one of NBCONFIG_SECTIONS
require : string
An importable AMD module inside the nbextensions static path
state : bool
The state in which to leave the extension
user : bool [default: False]
Whether to check the user's .jupyter/nbextensions directory.
Otherwise check a system-wide install (e.g. /usr/local/share/jupyter/nbextensions).
sys_prefix : bool [default: False]
Install into the sys.prefix, i.e. environment
logger : Jupyter logger [optional]
Logger instance to use
"""
config_dir = os.path.join(
_get_config_dir(user=user, sys_prefix=sys_prefix), 'nbconfig')
cm = BaseJSONConfigManager(config_dir=config_dir)
@ -313,12 +339,30 @@ def _set_nbextension_state(section, require, state, user, sys_prefix,
require
))
cm.update(section, {"load_extensions": {require: state}})
return cm.get(section).get(require) == state
def _set_nbextension_state_python(state, package, user, sys_prefix,
logger=None):
"""
Enable or disable a nbextension
"""Enable or disable some nbextensions stored in a python package
Returns a list of whether the state was achieved (i.e. changed, or was
already right)
Parameters
----------
state : Bool
Whether the extensions should be enabled
package : str
Importable Python package (no dotted-notation!) exposing the
magic-named `_jupyter_nbextension_paths` function
user : bool [default: False]
Whether to enable in the user's nbextensions directory.
sys_prefix : bool [default: False]
Enable/disable in the sys.prefix, i.e. environment
logger : Jupyter logger [optional]
Logger instance to use
"""
m, nbexts = _get_nbextension_metadata(package)
return [_set_nbextension_state(section=nbext["section"],
@ -329,14 +373,52 @@ def _set_nbextension_state_python(state, package, user, sys_prefix,
for nbext in nbexts]
def enable_nbextension(section, require, user, sys_prefix, logger=None):
def enable_nbextension(section, require, user=False, sys_prefix=False,
logger=None):
"""Enable a named nbextension
Returns True if the final state is the one requested.
Parameters
----------
section : string
The section of the server to change, one of NBCONFIG_SECTIONS
require : string
An importable AMD module inside the nbextensions static path
user : bool [default: False]
Whether to enable in the user's nbextensions directory.
sys_prefix : bool [default: False]
Whether to enable in the sys.prefix, i.e. environment
logger : Jupyter logger [optional]
Logger instance to use
"""
return _set_nbextension_state(section=section, require=require,
state=True,
user=user, sys_prefix=sys_prefix,
logger=logger)
def disable_nbextension(section, require, user, sys_prefix, logger=None):
def disable_nbextension(section, require, user=False, sys_prefix=False,
logger=None):
"""Disable a named nbextension
Returns True if the final state is the one requested.
Parameters
----------
section : string
The section of the server to change, one of NBCONFIG_SECTIONS
require : string
An importable AMD module inside the nbextensions static path
user : bool [default: False]
Whether to enable in the user's nbextensions directory.
sys_prefix : bool [default: False]
Whether to enable in the sys.prefix, i.e. environment
logger : Jupyter logger [optional]
Logger instance to use
"""
return _set_nbextension_state(section=section, require=require,
state=False,
user=user, sys_prefix=sys_prefix,
@ -345,19 +427,63 @@ def disable_nbextension(section, require, user, sys_prefix, logger=None):
def enable_nbextension_python(package, user=False, sys_prefix=False,
logger=None):
"""Enable an nbextension associated with a Python package."""
"""Enable some nbextensions associated with a Python package.
Returns a list of whether the state was achieved (i.e. changed, or was
already right)
Parameters
----------
package : str
Importable Python package (no dotted-notation!) exposing the
magic-named `_jupyter_nbextension_paths` function
user : bool [default: False]
Whether to enable in the user's nbextensions directory.
sys_prefix : bool [default: False]
Whether to enable in the sys.prefix, i.e. environment
logger : Jupyter logger [optional]
Logger instance to use
"""
return _set_nbextension_state_python(True, package, user, sys_prefix,
logger=logger)
def disable_nbextension_python(package, user=False, sys_prefix=False,
logger=None):
"""Disable an nbextension associated with a Python package."""
"""Disable some nbextensions associated with a Python package.
Returns True if the final state is the one requested.
Parameters
----------
package : str
Importable Python package (no dotted-notation!) exposing the
magic-named `_jupyter_nbextension_paths` function
user : bool [default: False]
Whether to enable in the user's nbextensions directory.
sys_prefix : bool [default: False]
Whether to enable in the sys.prefix, i.e. environment
logger : Jupyter logger [optional]
Logger instance to use
"""
return _set_nbextension_state_python(False, package, user, sys_prefix,
logger=logger)
def validate_nbextension(require, logger=None):
"""Validate a named nbextension.
Looks across all of the nbextension directories.
Returns a list of warnings.
require : str
require.js path used to load the extension
logger : Jupyter logger [optional]
Logger instance to use
"""
warnings = []
infos = []
@ -467,7 +593,7 @@ _base_flags = {
_base_flags['python'] = _base_flags['py']
class BaseNBExtensionApp(JupyterApp):
"""Base nbextension installer app"""
_log_formatter_cls = LogFormatter
flags = _base_flags
version = __version__
@ -480,10 +606,12 @@ class BaseNBExtensionApp(JupyterApp):
verbose = Any(None, config=True, help="DEPRECATED: Verbosity level")
def _verbose_changed(self):
"""Warn about verbosity changes"""
import warnings
warnings.warn("`verbose` traits of `{}` has been deprecated, has no effects and will be removed in notebook 5.0.".format(type(self).__name__), DeprecationWarning)
def _log_format_default(self):
"""A default format for messages"""
return "%(message)s"
@ -539,9 +667,11 @@ class InstallNBExtensionApp(BaseNBExtensionApp):
destination = Unicode('', config=True, help="Destination for the copy or symlink")
def _config_file_name_default(self):
"""The default config file name."""
return 'jupyter_notebook_config'
def install_extensions(self):
"""Perform the installation of nbextension(s)"""
if len(self.extra_args)>1:
raise ValueError("only one nbextension allowed at a time. Call multiple times to install multiple extensions.")
@ -558,6 +688,7 @@ class InstallNBExtensionApp(BaseNBExtensionApp):
)
def start(self):
"""Perform the App's function as configured"""
if not self.extra_args:
sys.exit('Please specify an nbextension to install')
else:
@ -592,9 +723,11 @@ class UninstallNBExtensionApp(BaseNBExtensionApp):
destination = Unicode('', config=True, help="Destination for the copy or symlink")
def _config_file_name_default(self):
"""The default config file name."""
return 'jupyter_notebook_config'
def uninstall_extensions(self):
"""Uninstall some nbextensions"""
kwargs = {
'user': self.user,
'sys_prefix': self.sys_prefix,
@ -625,7 +758,7 @@ class UninstallNBExtensionApp(BaseNBExtensionApp):
class ToggleNBExtensionApp(BaseNBExtensionApp):
"""A base class for apps that enable/disable extensions"""
name = "jupyter nbextension enable/disable"
version = __version__
description = "Enable/disable an nbextension using frontend configuration files."
@ -639,9 +772,21 @@ class ToggleNBExtensionApp(BaseNBExtensionApp):
_toggle_value = None
def _config_file_name_default(self):
"""The default config file name."""
return 'jupyter_notebook_config'
def toggle_nbextension_python(self, package):
"""Toggle some extensions in an importable Python package.
Returns a list of booleans indicating whether the state was changed as
requested.
Parameters
----------
package : str
Importable Python package (no dotted-notation!) exposing the
magic-named `_jupyter_nbextension_paths` function
"""
toggle = (enable_nbextension_python if self._toggle_value
else disable_nbextension_python)
return toggle(package,
@ -650,6 +795,15 @@ class ToggleNBExtensionApp(BaseNBExtensionApp):
logger=self.log)
def toggle_nbextension(self, require):
"""Toggle some a named nbextension by require-able AMD module.
Returns whether the state was changed as requested.
Parameters
----------
require : str
require.js path used to load the nbextension
"""
toggle = (enable_nbextension if self._toggle_value
else disable_nbextension)
return toggle(self.section, require,
@ -668,26 +822,27 @@ class ToggleNBExtensionApp(BaseNBExtensionApp):
class EnableNBExtensionApp(ToggleNBExtensionApp):
"""An App that enables nbextensions"""
name = "jupyter nbextension enable"
description = "Enable an nbextension using frontend configuration files."
_toggle_value = True
class DisableNBExtensionApp(ToggleNBExtensionApp):
"""An App that disables nbextensions"""
name = "jupyter nbextension disable"
description = "Disable an nbextension using frontend configuration files."
_toggle_value = None
class ListNBExtensionsApp(BaseNBExtensionApp):
"""An App that lists and validates nbextensions"""
name = "jupyter nbextension list"
version = __version__
description = "List all nbextensions known by the configuration system"
def list_nbextensions(self):
"""List all the nbextensions"""
config_dirs = [os.path.join(p, 'nbconfig') for p in jupyter_config_path()]
for config_dir in config_dirs:
@ -706,6 +861,7 @@ class ListNBExtensionsApp(BaseNBExtensionApp):
validate_nbextension(require, logger=self.log)
def start(self):
"""Perform the App's functions as configured"""
self.list_nbextensions()
@ -718,7 +874,7 @@ jupyter nbextension uninstall --py <packagename> # uninstall an nbextension in
"""
class NBExtensionApp(BaseNBExtensionApp):
"""Base jupyter nbextension command entry point"""
name = "jupyter nbextension"
version = __version__
description = "Work with Jupyter notebook extensions"
@ -733,6 +889,7 @@ class NBExtensionApp(BaseNBExtensionApp):
)
def start(self):
"""Perform the App's functions as configured"""
super(NBExtensionApp, self).start()
# The above should have called a subcommand and raised NoStart; if we
@ -748,7 +905,20 @@ main = NBExtensionApp.launch_instance
def _should_copy(src, dest, logger=None):
"""Should a file be copied?"""
"""Should a file be copied, if it doesn't exist, or is newer?
Returns whether the file needs to be updated.
Parameters
----------
src : string
A path that should exist from which to copy a file
src : string
A path that might exist to which to copy a file
logger : Jupyter logger [optional]
Logger instance to use
"""
if not os.path.exists(dest):
return True
if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6:
@ -763,7 +933,18 @@ def _should_copy(src, dest, logger=None):
def _maybe_copy(src, dest, logger=None):
"""Copy a file if it needs updating."""
"""Copy a file if it needs updating.
Parameters
----------
src : string
A path that should exist from which to copy a file
src : string
A path that might exist to which to copy a file
logger : Jupyter logger [optional]
Logger instance to use
"""
if _should_copy(src, dest, logger=logger):
if logger:
logger.info("Copying: %s -> %s" % (src, dest))
@ -771,7 +952,16 @@ def _maybe_copy(src, dest, logger=None):
def _safe_is_tarfile(path):
"""Safe version of is_tarfile, return False on IOError."""
"""Safe version of is_tarfile, return False on IOError.
Returns whether the file exists and is a tarfile.
Parameters
----------
path : string
A path that might not exist and or be a tarfile
"""
try:
return tarfile.is_tarfile(path)
except IOError:
@ -779,7 +969,20 @@ def _safe_is_tarfile(path):
def _get_nbextension_dir(user=False, sys_prefix=False, prefix=None, nbextensions_dir=None):
"""Return the nbextension directory specified"""
"""Return the nbextension directory specified
Parameters
----------
user : bool [default: False]
Get the user's .jupyter/nbextensions directory
sys_prefix : bool [default: False]
Get sys.prefix, i.e. ~/.envs/my-env/share/jupyter/nbextensions
prefix : str [optional]
Get custom prefix
nbextensions_dir : str [optional]
Get what you put in
"""
if sum(map(bool, [user, prefix, nbextensions_dir, sys_prefix])) > 1:
raise ArgumentConflict("cannot specify more than one of user, sys_prefix, prefix, or nbextensions_dir")
if user:
@ -796,7 +999,10 @@ def _get_nbextension_dir(user=False, sys_prefix=False, prefix=None, nbextensions
def _nbextension_dirs():
"""The possible locations of nbextensions."""
"""The possible locations of nbextensions.
Returns a list of known base extension locations
"""
return [
pjoin(jupyter_data_dir(), u'nbextensions'),
pjoin(ENV_JUPYTER_PATH[0], u'nbextensions'),
@ -805,6 +1011,18 @@ def _nbextension_dirs():
def _get_config_dir(user=False, sys_prefix=False):
"""Get the location of config files for the current context
Returns the string to the enviornment
Parameters
----------
user : bool [default: False]
Get the user's .jupyter config directory
sys_prefix : bool [default: False]
Get sys.prefix, i.e. ~/.envs/my-env/etc/jupyter
"""
if user and sys_prefix:
raise ArgumentConflict("Cannot specify more than one of user or sys_prefix")
if user:
@ -817,6 +1035,22 @@ def _get_config_dir(user=False, sys_prefix=False):
def _get_nbextension_metadata(package):
"""Get the list of nbextension paths associated with a python package.
Returns a tuple of (the module, [{
'section': 'notebook',
'src': 'mockextension',
'dest': '_mockdestination',
'require': '_mockdestination/index'
}])
Parameters
----------
package : str
Importable Python package (no dotted-notation!) exposing the
magic-named `_jupyter_nbextension_paths` function
"""
m = __import__(package)
if not hasattr(m, '_jupyter_nbextension_paths'):
raise KeyError('The Python package {} is not a valid nbextension'.format(package))
@ -825,17 +1059,39 @@ def _get_nbextension_metadata(package):
def _read_config_data(user=False, sys_prefix=False):
"""Get the config for the current context
Returns the string to the enviornment
Parameters
----------
user : bool [default: False]
Get the user's .jupyter config directory
sys_prefix : bool [default: False]
Get sys.prefix, i.e. ~/.envs/my-env/etc/jupyter
"""
config_dir = _get_config_dir(user=user, sys_prefix=sys_prefix)
config_man = BaseJSONConfigManager(config_dir=config_dir)
return config_man.get('jupyter_notebook_config')
def _write_config_data(data, user=False, sys_prefix=False):
"""Update the config for the current context
Parameters
----------
data : object
An object which can be accepted by ConfigManager.update
user : bool [default: False]
Get the user's .jupyter config directory
sys_prefix : bool [default: False]
Get sys.prefix, i.e. ~/.envs/my-env/etc/jupyter
"""
config_dir = _get_config_dir(user=user, sys_prefix=sys_prefix)
config_man = BaseJSONConfigManager(config_dir=config_dir)
config_man.update('jupyter_notebook_config', data)
if __name__ == '__main__':
main()