You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
6.5 KiB
189 lines
6.5 KiB
4 years ago
|
"""The IPython kernel spec for Jupyter"""
|
||
|
|
||
|
# Copyright (c) IPython Development Team.
|
||
|
# Distributed under the terms of the Modified BSD License.
|
||
|
|
||
|
from __future__ import print_function
|
||
|
|
||
|
import errno
|
||
|
import json
|
||
|
import os
|
||
|
import shutil
|
||
|
import sys
|
||
|
import tempfile
|
||
|
|
||
|
from jupyter_client.kernelspec import KernelSpecManager
|
||
|
|
||
|
pjoin = os.path.join
|
||
|
|
||
|
KERNEL_NAME = 'python%i' % sys.version_info[0]
|
||
|
|
||
|
# path to kernelspec resources
|
||
|
RESOURCES = pjoin(os.path.dirname(__file__), 'resources')
|
||
|
|
||
|
|
||
|
def make_ipkernel_cmd(mod='ipykernel_launcher', executable=None, extra_arguments=None, **kw):
|
||
|
"""Build Popen command list for launching an IPython kernel.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
mod : str, optional (default 'ipykernel')
|
||
|
A string of an IPython module whose __main__ starts an IPython kernel
|
||
|
|
||
|
executable : str, optional (default sys.executable)
|
||
|
The Python executable to use for the kernel process.
|
||
|
|
||
|
extra_arguments : list, optional
|
||
|
A list of extra arguments to pass when executing the launch code.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
|
||
|
A Popen command list
|
||
|
"""
|
||
|
if executable is None:
|
||
|
executable = sys.executable
|
||
|
extra_arguments = extra_arguments or []
|
||
|
arguments = [executable, '-m', mod, '-f', '{connection_file}']
|
||
|
arguments.extend(extra_arguments)
|
||
|
|
||
|
return arguments
|
||
|
|
||
|
|
||
|
def get_kernel_dict(extra_arguments=None):
|
||
|
"""Construct dict for kernel.json"""
|
||
|
return {
|
||
|
'argv': make_ipkernel_cmd(extra_arguments=extra_arguments),
|
||
|
'display_name': 'Python %i' % sys.version_info[0],
|
||
|
'language': 'python',
|
||
|
}
|
||
|
|
||
|
|
||
|
def write_kernel_spec(path=None, overrides=None, extra_arguments=None):
|
||
|
"""Write a kernel spec directory to `path`
|
||
|
|
||
|
If `path` is not specified, a temporary directory is created.
|
||
|
If `overrides` is given, the kernelspec JSON is updated before writing.
|
||
|
|
||
|
The path to the kernelspec is always returned.
|
||
|
"""
|
||
|
if path is None:
|
||
|
path = os.path.join(tempfile.mkdtemp(suffix='_kernels'), KERNEL_NAME)
|
||
|
|
||
|
# stage resources
|
||
|
shutil.copytree(RESOURCES, path)
|
||
|
# write kernel.json
|
||
|
kernel_dict = get_kernel_dict(extra_arguments)
|
||
|
|
||
|
if overrides:
|
||
|
kernel_dict.update(overrides)
|
||
|
with open(pjoin(path, 'kernel.json'), 'w') as f:
|
||
|
json.dump(kernel_dict, f, indent=1)
|
||
|
|
||
|
return path
|
||
|
|
||
|
|
||
|
def install(kernel_spec_manager=None, user=False, kernel_name=KERNEL_NAME, display_name=None,
|
||
|
prefix=None, profile=None):
|
||
|
"""Install the IPython kernelspec for Jupyter
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
|
||
|
kernel_spec_manager: KernelSpecManager [optional]
|
||
|
A KernelSpecManager to use for installation.
|
||
|
If none provided, a default instance will be created.
|
||
|
user: bool [default: False]
|
||
|
Whether to do a user-only install, or system-wide.
|
||
|
kernel_name: str, optional
|
||
|
Specify a name for the kernelspec.
|
||
|
This is needed for having multiple IPython kernels for different environments.
|
||
|
display_name: str, optional
|
||
|
Specify the display name for the kernelspec
|
||
|
profile: str, optional
|
||
|
Specify a custom profile to be loaded by the kernel.
|
||
|
prefix: str, optional
|
||
|
Specify an install prefix for the kernelspec.
|
||
|
This is needed to install into a non-default location, such as a conda/virtual-env.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
|
||
|
The path where the kernelspec was installed.
|
||
|
"""
|
||
|
if kernel_spec_manager is None:
|
||
|
kernel_spec_manager = KernelSpecManager()
|
||
|
|
||
|
if (kernel_name != KERNEL_NAME) and (display_name is None):
|
||
|
# kernel_name is specified and display_name is not
|
||
|
# default display_name to kernel_name
|
||
|
display_name = kernel_name
|
||
|
overrides = {}
|
||
|
if display_name:
|
||
|
overrides["display_name"] = display_name
|
||
|
if profile:
|
||
|
extra_arguments = ["--profile", profile]
|
||
|
if not display_name:
|
||
|
# add the profile to the default display name
|
||
|
overrides["display_name"] = 'Python %i [profile=%s]' % (sys.version_info[0], profile)
|
||
|
else:
|
||
|
extra_arguments = None
|
||
|
path = write_kernel_spec(overrides=overrides, extra_arguments=extra_arguments)
|
||
|
dest = kernel_spec_manager.install_kernel_spec(
|
||
|
path, kernel_name=kernel_name, user=user, prefix=prefix)
|
||
|
# cleanup afterward
|
||
|
shutil.rmtree(path)
|
||
|
return dest
|
||
|
|
||
|
# Entrypoint
|
||
|
|
||
|
from traitlets.config import Application
|
||
|
|
||
|
|
||
|
class InstallIPythonKernelSpecApp(Application):
|
||
|
"""Dummy app wrapping argparse"""
|
||
|
name = 'ipython-kernel-install'
|
||
|
|
||
|
def initialize(self, argv=None):
|
||
|
if argv is None:
|
||
|
argv = sys.argv[1:]
|
||
|
self.argv = argv
|
||
|
|
||
|
def start(self):
|
||
|
import argparse
|
||
|
parser = argparse.ArgumentParser(prog=self.name,
|
||
|
description="Install the IPython kernel spec.")
|
||
|
parser.add_argument('--user', action='store_true',
|
||
|
help="Install for the current user instead of system-wide")
|
||
|
parser.add_argument('--name', type=str, default=KERNEL_NAME,
|
||
|
help="Specify a name for the kernelspec."
|
||
|
" This is needed to have multiple IPython kernels at the same time.")
|
||
|
parser.add_argument('--display-name', type=str,
|
||
|
help="Specify the display name for the kernelspec."
|
||
|
" This is helpful when you have multiple IPython kernels.")
|
||
|
parser.add_argument('--profile', type=str,
|
||
|
help="Specify an IPython profile to load. "
|
||
|
"This can be used to create custom versions of the kernel.")
|
||
|
parser.add_argument('--prefix', type=str,
|
||
|
help="Specify an install prefix for the kernelspec."
|
||
|
" This is needed to install into a non-default location, such as a conda/virtual-env.")
|
||
|
parser.add_argument('--sys-prefix', action='store_const', const=sys.prefix, dest='prefix',
|
||
|
help="Install to Python's sys.prefix."
|
||
|
" Shorthand for --prefix='%s'. For use in conda/virtual-envs." % sys.prefix)
|
||
|
opts = parser.parse_args(self.argv)
|
||
|
try:
|
||
|
dest = install(user=opts.user, kernel_name=opts.name, profile=opts.profile,
|
||
|
prefix=opts.prefix, display_name=opts.display_name)
|
||
|
except OSError as e:
|
||
|
if e.errno == errno.EACCES:
|
||
|
print(e, file=sys.stderr)
|
||
|
if opts.user:
|
||
|
print("Perhaps you want `sudo` or `--user`?", file=sys.stderr)
|
||
|
self.exit(1)
|
||
|
raise
|
||
|
print("Installed kernelspec %s in %s" % (opts.name, dest))
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
InstallIPythonKernelSpecApp.launch_instance()
|