273 lines
9.9 KiB
Python
273 lines
9.9 KiB
Python
|
|
||
|
# Copyright (c) Jupyter Development Team.
|
||
|
# Distributed under the terms of the Modified BSD License.
|
||
|
|
||
|
from __future__ import print_function
|
||
|
|
||
|
import errno
|
||
|
import os.path
|
||
|
import sys
|
||
|
import json
|
||
|
|
||
|
from traitlets.config.application import Application
|
||
|
from jupyter_core.application import (
|
||
|
JupyterApp, base_flags, base_aliases
|
||
|
)
|
||
|
from traitlets import Instance, Dict, Unicode, Bool, List
|
||
|
|
||
|
from . import __version__
|
||
|
from .kernelspec import KernelSpecManager
|
||
|
|
||
|
|
||
|
class ListKernelSpecs(JupyterApp):
|
||
|
version = __version__
|
||
|
description = """List installed kernel specifications."""
|
||
|
kernel_spec_manager = Instance(KernelSpecManager)
|
||
|
json_output = Bool(False, help='output spec name and location as machine-readable json.',
|
||
|
config=True)
|
||
|
|
||
|
flags = {'json': ({'ListKernelSpecs': {'json_output': True}},
|
||
|
"output spec name and location as machine-readable json."),
|
||
|
'debug': base_flags['debug'],
|
||
|
}
|
||
|
|
||
|
def _kernel_spec_manager_default(self):
|
||
|
return KernelSpecManager(parent=self, data_dir=self.data_dir)
|
||
|
|
||
|
def start(self):
|
||
|
paths = self.kernel_spec_manager.find_kernel_specs()
|
||
|
specs = self.kernel_spec_manager.get_all_specs()
|
||
|
if not self.json_output:
|
||
|
if not specs:
|
||
|
print("No kernels available")
|
||
|
return
|
||
|
# pad to width of longest kernel name
|
||
|
name_len = len(sorted(paths, key=lambda name: len(name))[-1])
|
||
|
|
||
|
def path_key(item):
|
||
|
"""sort key function for Jupyter path priority"""
|
||
|
path = item[1]
|
||
|
for idx, prefix in enumerate(self.jupyter_path):
|
||
|
if path.startswith(prefix):
|
||
|
return (idx, path)
|
||
|
# not in jupyter path, artificially added to the front
|
||
|
return (-1, path)
|
||
|
|
||
|
print("Available kernels:")
|
||
|
for kernelname, path in sorted(paths.items(), key=path_key):
|
||
|
print(" %s %s" % (kernelname.ljust(name_len), path))
|
||
|
else:
|
||
|
print(json.dumps({
|
||
|
'kernelspecs': specs
|
||
|
}, indent=2))
|
||
|
|
||
|
|
||
|
|
||
|
class InstallKernelSpec(JupyterApp):
|
||
|
version = __version__
|
||
|
description = """Install a kernel specification directory.
|
||
|
|
||
|
Given a SOURCE DIRECTORY containing a kernel spec,
|
||
|
jupyter will copy that directory into one of the Jupyter kernel directories.
|
||
|
The default is to install kernelspecs for all users.
|
||
|
`--user` can be specified to install a kernel only for the current user.
|
||
|
"""
|
||
|
examples = """
|
||
|
jupyter kernelspec install /path/to/my_kernel --user
|
||
|
"""
|
||
|
usage = "jupyter kernelspec install SOURCE_DIR [--options]"
|
||
|
kernel_spec_manager = Instance(KernelSpecManager)
|
||
|
|
||
|
def _kernel_spec_manager_default(self):
|
||
|
return KernelSpecManager(data_dir=self.data_dir)
|
||
|
|
||
|
sourcedir = Unicode()
|
||
|
kernel_name = Unicode("", config=True,
|
||
|
help="Install the kernel spec with this name"
|
||
|
)
|
||
|
def _kernel_name_default(self):
|
||
|
return os.path.basename(self.sourcedir)
|
||
|
|
||
|
user = Bool(False, config=True,
|
||
|
help="""
|
||
|
Try to install the kernel spec to the per-user directory instead of
|
||
|
the system or environment directory.
|
||
|
"""
|
||
|
)
|
||
|
prefix = Unicode('', config=True,
|
||
|
help="""Specify a prefix to install to, e.g. an env.
|
||
|
The kernelspec will be installed in PREFIX/share/jupyter/kernels/
|
||
|
"""
|
||
|
)
|
||
|
replace = Bool(False, config=True,
|
||
|
help="Replace any existing kernel spec with this name."
|
||
|
)
|
||
|
|
||
|
aliases = {
|
||
|
'name': 'InstallKernelSpec.kernel_name',
|
||
|
'prefix': 'InstallKernelSpec.prefix',
|
||
|
}
|
||
|
aliases.update(base_aliases)
|
||
|
|
||
|
flags = {'user': ({'InstallKernelSpec': {'user': True}},
|
||
|
"Install to the per-user kernel registry"),
|
||
|
'replace': ({'InstallKernelSpec': {'replace': True}},
|
||
|
"Replace any existing kernel spec with this name."),
|
||
|
'sys-prefix': ({'InstallKernelSpec': {'prefix': sys.prefix}},
|
||
|
"Install to Python's sys.prefix. Useful in conda/virtual environments."),
|
||
|
'debug': base_flags['debug'],
|
||
|
}
|
||
|
|
||
|
def parse_command_line(self, argv):
|
||
|
super(InstallKernelSpec, self).parse_command_line(argv)
|
||
|
# accept positional arg as profile name
|
||
|
if self.extra_args:
|
||
|
self.sourcedir = self.extra_args[0]
|
||
|
else:
|
||
|
print("No source directory specified.")
|
||
|
self.exit(1)
|
||
|
|
||
|
def start(self):
|
||
|
if self.user and self.prefix:
|
||
|
self.exit("Can't specify both user and prefix. Please choose one or the other.")
|
||
|
try:
|
||
|
self.kernel_spec_manager.install_kernel_spec(self.sourcedir,
|
||
|
kernel_name=self.kernel_name,
|
||
|
user=self.user,
|
||
|
prefix=self.prefix,
|
||
|
replace=self.replace,
|
||
|
)
|
||
|
except OSError as e:
|
||
|
if e.errno == errno.EACCES:
|
||
|
print(e, file=sys.stderr)
|
||
|
if not self.user:
|
||
|
print("Perhaps you want to install with `sudo` or `--user`?", file=sys.stderr)
|
||
|
self.exit(1)
|
||
|
elif e.errno == errno.EEXIST:
|
||
|
print("A kernel spec is already present at %s" % e.filename, file=sys.stderr)
|
||
|
self.exit(1)
|
||
|
raise
|
||
|
|
||
|
class RemoveKernelSpec(JupyterApp):
|
||
|
version = __version__
|
||
|
description = """Remove one or more Jupyter kernelspecs by name."""
|
||
|
examples = """jupyter kernelspec remove python2 [my_kernel ...]"""
|
||
|
|
||
|
force = Bool(False, config=True,
|
||
|
help="""Force removal, don't prompt for confirmation."""
|
||
|
)
|
||
|
spec_names = List(Unicode())
|
||
|
|
||
|
kernel_spec_manager = Instance(KernelSpecManager)
|
||
|
def _kernel_spec_manager_default(self):
|
||
|
return KernelSpecManager(data_dir=self.data_dir, parent=self)
|
||
|
|
||
|
flags = {
|
||
|
'f': ({'RemoveKernelSpec': {'force': True}}, force.get_metadata('help')),
|
||
|
}
|
||
|
flags.update(JupyterApp.flags)
|
||
|
|
||
|
def parse_command_line(self, argv):
|
||
|
super(RemoveKernelSpec, self).parse_command_line(argv)
|
||
|
# accept positional arg as profile name
|
||
|
if self.extra_args:
|
||
|
self.spec_names = sorted(set(self.extra_args)) # remove duplicates
|
||
|
else:
|
||
|
self.exit("No kernelspec specified.")
|
||
|
|
||
|
def start(self):
|
||
|
self.kernel_spec_manager.ensure_native_kernel = False
|
||
|
spec_paths = self.kernel_spec_manager.find_kernel_specs()
|
||
|
missing = set(self.spec_names).difference(set(spec_paths))
|
||
|
if missing:
|
||
|
self.exit("Couldn't find kernel spec(s): %s" % ', '.join(missing))
|
||
|
|
||
|
if not self.force:
|
||
|
print("Kernel specs to remove:")
|
||
|
for name in self.spec_names:
|
||
|
print(" %s\t%s" % (name.ljust(20), spec_paths[name]))
|
||
|
answer = input("Remove %i kernel specs [y/N]: " % len(self.spec_names))
|
||
|
if not answer.lower().startswith('y'):
|
||
|
return
|
||
|
|
||
|
for kernel_name in self.spec_names:
|
||
|
try:
|
||
|
path = self.kernel_spec_manager.remove_kernel_spec(kernel_name)
|
||
|
except OSError as e:
|
||
|
if e.errno == errno.EACCES:
|
||
|
print(e, file=sys.stderr)
|
||
|
print("Perhaps you want sudo?", file=sys.stderr)
|
||
|
self.exit(1)
|
||
|
else:
|
||
|
raise
|
||
|
self.log.info("Removed %s", path)
|
||
|
|
||
|
|
||
|
class InstallNativeKernelSpec(JupyterApp):
|
||
|
version = __version__
|
||
|
description = """[DEPRECATED] Install the IPython kernel spec directory for this Python."""
|
||
|
kernel_spec_manager = Instance(KernelSpecManager)
|
||
|
|
||
|
def _kernel_spec_manager_default(self):
|
||
|
return KernelSpecManager(data_dir=self.data_dir)
|
||
|
|
||
|
user = Bool(False, config=True,
|
||
|
help="""
|
||
|
Try to install the kernel spec to the per-user directory instead of
|
||
|
the system or environment directory.
|
||
|
"""
|
||
|
)
|
||
|
|
||
|
flags = {'user': ({'InstallNativeKernelSpec': {'user': True}},
|
||
|
"Install to the per-user kernel registry"),
|
||
|
'debug': base_flags['debug'],
|
||
|
}
|
||
|
|
||
|
def start(self):
|
||
|
self.log.warning("`jupyter kernelspec install-self` is DEPRECATED as of 4.0."
|
||
|
" You probably want `ipython kernel install` to install the IPython kernelspec.")
|
||
|
try:
|
||
|
from ipykernel import kernelspec
|
||
|
except ImportError:
|
||
|
print("ipykernel not available, can't install its spec.", file=sys.stderr)
|
||
|
self.exit(1)
|
||
|
try:
|
||
|
kernelspec.install(self.kernel_spec_manager, user=self.user)
|
||
|
except OSError as e:
|
||
|
if e.errno == errno.EACCES:
|
||
|
print(e, file=sys.stderr)
|
||
|
if not self.user:
|
||
|
print("Perhaps you want to install with `sudo` or `--user`?", file=sys.stderr)
|
||
|
self.exit(1)
|
||
|
self.exit(e)
|
||
|
|
||
|
class KernelSpecApp(Application):
|
||
|
version = __version__
|
||
|
name = "jupyter kernelspec"
|
||
|
description = """Manage Jupyter kernel specifications."""
|
||
|
|
||
|
subcommands = Dict({
|
||
|
'list': (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
|
||
|
'install': (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0]),
|
||
|
'uninstall': (RemoveKernelSpec, "Alias for remove"),
|
||
|
'remove': (RemoveKernelSpec, RemoveKernelSpec.description.splitlines()[0]),
|
||
|
'install-self': (InstallNativeKernelSpec, InstallNativeKernelSpec.description.splitlines()[0]),
|
||
|
})
|
||
|
|
||
|
aliases = {}
|
||
|
flags = {}
|
||
|
|
||
|
def start(self):
|
||
|
if self.subapp is None:
|
||
|
print("No subcommand specified. Must specify one of: %s"% list(self.subcommands))
|
||
|
print()
|
||
|
self.print_description()
|
||
|
self.print_subcommands()
|
||
|
self.exit(1)
|
||
|
else:
|
||
|
return self.subapp.start()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
KernelSpecApp.launch_instance()
|