kernelspecapp.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. # Copyright (c) Jupyter Development Team.
  2. # Distributed under the terms of the Modified BSD License.
  3. from __future__ import print_function
  4. import errno
  5. import os.path
  6. import sys
  7. import json
  8. from traitlets.config.application import Application
  9. from jupyter_core.application import (
  10. JupyterApp, base_flags, base_aliases
  11. )
  12. from traitlets import Instance, Dict, Unicode, Bool, List
  13. from . import __version__
  14. from .kernelspec import KernelSpecManager
  15. try:
  16. raw_input
  17. except NameError:
  18. # py3
  19. raw_input = input
  20. class ListKernelSpecs(JupyterApp):
  21. version = __version__
  22. description = """List installed kernel specifications."""
  23. kernel_spec_manager = Instance(KernelSpecManager)
  24. json_output = Bool(False, help='output spec name and location as machine-readable json.',
  25. config=True)
  26. flags = {'json': ({'ListKernelSpecs': {'json_output': True}},
  27. "output spec name and location as machine-readable json."),
  28. 'debug': base_flags['debug'],
  29. }
  30. def _kernel_spec_manager_default(self):
  31. return KernelSpecManager(parent=self, data_dir=self.data_dir)
  32. def start(self):
  33. paths = self.kernel_spec_manager.find_kernel_specs()
  34. specs = self.kernel_spec_manager.get_all_specs()
  35. if not self.json_output:
  36. if not specs:
  37. print("No kernels available")
  38. return
  39. # pad to width of longest kernel name
  40. name_len = len(sorted(paths, key=lambda name: len(name))[-1])
  41. def path_key(item):
  42. """sort key function for Jupyter path priority"""
  43. path = item[1]
  44. for idx, prefix in enumerate(self.jupyter_path):
  45. if path.startswith(prefix):
  46. return (idx, path)
  47. # not in jupyter path, artificially added to the front
  48. return (-1, path)
  49. print("Available kernels:")
  50. for kernelname, path in sorted(paths.items(), key=path_key):
  51. print(" %s %s" % (kernelname.ljust(name_len), path))
  52. else:
  53. print(json.dumps({
  54. 'kernelspecs': specs
  55. }, indent=2))
  56. class InstallKernelSpec(JupyterApp):
  57. version = __version__
  58. description = """Install a kernel specification directory.
  59. Given a SOURCE DIRECTORY containing a kernel spec,
  60. jupyter will copy that directory into one of the Jupyter kernel directories.
  61. The default is to install kernelspecs for all users.
  62. `--user` can be specified to install a kernel only for the current user.
  63. """
  64. examples = """
  65. jupyter kernelspec install /path/to/my_kernel --user
  66. """
  67. usage = "jupyter kernelspec install SOURCE_DIR [--options]"
  68. kernel_spec_manager = Instance(KernelSpecManager)
  69. def _kernel_spec_manager_default(self):
  70. return KernelSpecManager(data_dir=self.data_dir)
  71. sourcedir = Unicode()
  72. kernel_name = Unicode("", config=True,
  73. help="Install the kernel spec with this name"
  74. )
  75. def _kernel_name_default(self):
  76. return os.path.basename(self.sourcedir)
  77. user = Bool(False, config=True,
  78. help="""
  79. Try to install the kernel spec to the per-user directory instead of
  80. the system or environment directory.
  81. """
  82. )
  83. prefix = Unicode('', config=True,
  84. help="""Specify a prefix to install to, e.g. an env.
  85. The kernelspec will be installed in PREFIX/share/jupyter/kernels/
  86. """
  87. )
  88. replace = Bool(False, config=True,
  89. help="Replace any existing kernel spec with this name."
  90. )
  91. aliases = {
  92. 'name': 'InstallKernelSpec.kernel_name',
  93. 'prefix': 'InstallKernelSpec.prefix',
  94. }
  95. aliases.update(base_aliases)
  96. flags = {'user': ({'InstallKernelSpec': {'user': True}},
  97. "Install to the per-user kernel registry"),
  98. 'replace': ({'InstallKernelSpec': {'replace': True}},
  99. "Replace any existing kernel spec with this name."),
  100. 'sys-prefix': ({'InstallKernelSpec': {'prefix': sys.prefix}},
  101. "Install to Python's sys.prefix. Useful in conda/virtual environments."),
  102. 'debug': base_flags['debug'],
  103. }
  104. def parse_command_line(self, argv):
  105. super(InstallKernelSpec, self).parse_command_line(argv)
  106. # accept positional arg as profile name
  107. if self.extra_args:
  108. self.sourcedir = self.extra_args[0]
  109. else:
  110. print("No source directory specified.")
  111. self.exit(1)
  112. def start(self):
  113. if self.user and self.prefix:
  114. self.exit("Can't specify both user and prefix. Please choose one or the other.")
  115. try:
  116. self.kernel_spec_manager.install_kernel_spec(self.sourcedir,
  117. kernel_name=self.kernel_name,
  118. user=self.user,
  119. prefix=self.prefix,
  120. replace=self.replace,
  121. )
  122. except OSError as e:
  123. if e.errno == errno.EACCES:
  124. print(e, file=sys.stderr)
  125. if not self.user:
  126. print("Perhaps you want to install with `sudo` or `--user`?", file=sys.stderr)
  127. self.exit(1)
  128. elif e.errno == errno.EEXIST:
  129. print("A kernel spec is already present at %s" % e.filename, file=sys.stderr)
  130. self.exit(1)
  131. raise
  132. class RemoveKernelSpec(JupyterApp):
  133. version = __version__
  134. description = """Remove one or more Jupyter kernelspecs by name."""
  135. examples = """jupyter kernelspec remove python2 [my_kernel ...]"""
  136. force = Bool(False, config=True,
  137. help="""Force removal, don't prompt for confirmation."""
  138. )
  139. spec_names = List(Unicode())
  140. kernel_spec_manager = Instance(KernelSpecManager)
  141. def _kernel_spec_manager_default(self):
  142. return KernelSpecManager(data_dir=self.data_dir, parent=self)
  143. flags = {
  144. 'f': ({'RemoveKernelSpec': {'force': True}}, force.get_metadata('help')),
  145. }
  146. flags.update(JupyterApp.flags)
  147. def parse_command_line(self, argv):
  148. super(RemoveKernelSpec, self).parse_command_line(argv)
  149. # accept positional arg as profile name
  150. if self.extra_args:
  151. self.spec_names = sorted(set(self.extra_args)) # remove duplicates
  152. else:
  153. self.exit("No kernelspec specified.")
  154. def start(self):
  155. self.kernel_spec_manager.ensure_native_kernel = False
  156. spec_paths = self.kernel_spec_manager.find_kernel_specs()
  157. missing = set(self.spec_names).difference(set(spec_paths))
  158. if missing:
  159. self.exit("Couldn't find kernel spec(s): %s" % ', '.join(missing))
  160. if not self.force:
  161. print("Kernel specs to remove:")
  162. for name in self.spec_names:
  163. print(" %s\t%s" % (name.ljust(20), spec_paths[name]))
  164. answer = raw_input("Remove %i kernel specs [y/N]: " % len(self.spec_names))
  165. if not answer.lower().startswith('y'):
  166. return
  167. for kernel_name in self.spec_names:
  168. try:
  169. path = self.kernel_spec_manager.remove_kernel_spec(kernel_name)
  170. except OSError as e:
  171. if e.errno == errno.EACCES:
  172. print(e, file=sys.stderr)
  173. print("Perhaps you want sudo?", file=sys.stderr)
  174. self.exit(1)
  175. else:
  176. raise
  177. self.log.info("Removed %s", path)
  178. class InstallNativeKernelSpec(JupyterApp):
  179. version = __version__
  180. description = """[DEPRECATED] Install the IPython kernel spec directory for this Python."""
  181. kernel_spec_manager = Instance(KernelSpecManager)
  182. def _kernel_spec_manager_default(self):
  183. return KernelSpecManager(data_dir=self.data_dir)
  184. user = Bool(False, config=True,
  185. help="""
  186. Try to install the kernel spec to the per-user directory instead of
  187. the system or environment directory.
  188. """
  189. )
  190. flags = {'user': ({'InstallNativeKernelSpec': {'user': True}},
  191. "Install to the per-user kernel registry"),
  192. 'debug': base_flags['debug'],
  193. }
  194. def start(self):
  195. self.log.warning("`jupyter kernelspec install-self` is DEPRECATED as of 4.0."
  196. " You probably want `ipython kernel install` to install the IPython kernelspec.")
  197. try:
  198. from ipykernel import kernelspec
  199. except ImportError:
  200. print("ipykernel not available, can't install its spec.", file=sys.stderr)
  201. self.exit(1)
  202. try:
  203. kernelspec.install(self.kernel_spec_manager, user=self.user)
  204. except OSError as e:
  205. if e.errno == errno.EACCES:
  206. print(e, file=sys.stderr)
  207. if not self.user:
  208. print("Perhaps you want to install with `sudo` or `--user`?", file=sys.stderr)
  209. self.exit(1)
  210. self.exit(e)
  211. class KernelSpecApp(Application):
  212. version = __version__
  213. name = "jupyter kernelspec"
  214. description = """Manage Jupyter kernel specifications."""
  215. subcommands = Dict({
  216. 'list': (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
  217. 'install': (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0]),
  218. 'uninstall': (RemoveKernelSpec, "Alias for remove"),
  219. 'remove': (RemoveKernelSpec, RemoveKernelSpec.description.splitlines()[0]),
  220. 'install-self': (InstallNativeKernelSpec, InstallNativeKernelSpec.description.splitlines()[0]),
  221. })
  222. aliases = {}
  223. flags = {}
  224. def start(self):
  225. if self.subapp is None:
  226. print("No subcommand specified. Must specify one of: %s"% list(self.subcommands))
  227. print()
  228. self.print_description()
  229. self.print_subcommands()
  230. self.exit(1)
  231. else:
  232. return self.subapp.start()
  233. if __name__ == '__main__':
  234. KernelSpecApp.launch_instance()