diff --git a/IPython/kernel/kernelspecapp.py b/IPython/kernel/kernelspecapp.py new file mode 100644 index 0000000..0bce02d --- /dev/null +++ b/IPython/kernel/kernelspecapp.py @@ -0,0 +1,109 @@ + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + +import errno +import os.path + +from IPython.config.application import Application +from IPython.core.application import BaseIPythonApplication, base_flags +from IPython.utils.traitlets import Instance, Dict, Unicode, Bool + +from .kernelspec import KernelSpecManager + +def _pythonfirst(s): + "Sort key function that will put strings starting with 'python' first." + if s.startswith('python'): + return '' + return s + +class ListKernelSpecs(BaseIPythonApplication): + description = """List installed kernel specifications.""" + kernel_spec_manager = Instance(KernelSpecManager) + + def _kernel_spec_manager_default(self): + return KernelSpecManager(ipython_dir=self.ipython_dir) + + def start(self): + print("Available kernels:") + for kernelname in sorted(self.kernel_spec_manager.find_kernel_specs(), + key=_pythonfirst): + print(" %s" % kernelname) + + +class InstallKernelSpec(BaseIPythonApplication): + description = """Install a kernel specification directory.""" + kernel_spec_manager = Instance(KernelSpecManager) + + def _kernel_spec_manager_default(self): + return KernelSpecManager(ipython_dir=self.ipython_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) + + system = Bool(False, config=True, + help=""" + Try to install the kernel spec to the systemwide directory instead of + the per-user directory. + """ + ) + replace = Bool(False, config=True, + help="Replace any existing kernel spec with this name." + ) + + aliases = {'name': 'InstallKernelSpec.kernel_name'} + + flags = {'system': ({'InstallKernelSpec': {'system': True}}, + "Install to the systemwide kernel registry"), + 'replace': ({'InstallKernelSpec': {'replace': True}}, + "Replace any existing kernel spec with this name."), + } + flags.update(base_flags) + + 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): + try: + self.kernel_spec_manager.install_kernel_spec(self.sourcedir, + kernel_name=self.kernel_name, + system=self.system, + replace=self.replace, + ) + except OSError as e: + if e.errno == errno.EACCES: + print("Permission denied") + self.exit(1) + elif e.errno == errno.EEXIST: + print("A kernel spec named %r is already present" % self.kernel_name) + self.exit(1) + raise + +class KernelSpecApp(Application): + name = "ipython-kernelspec" + description = """Manage IPython kernel specifications.""" + + subcommands = Dict(dict( + list = (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]), + install = (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0]) + )) + + 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() diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index 658b2cf..7de0339 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -250,6 +250,9 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): trust=('IPython.nbformat.sign.TrustNotebookApp', "Sign notebooks to trust their potentially unsafe contents at load." ), + kernelspec=('IPython.kernel.kernelspecapp.KernelSpecApp', + "Manage IPython kernel specifications." + ), ) subcommands['install-nbextension'] = ( "IPython.html.nbextensions.NBExtensionApp",