##// END OF EJS Templates
Add API function to install a kernelspec
Thomas Kluyver -
Show More
@@ -1,142 +1,177 b''
1 1 import io
2 2 import json
3 3 import os
4 import shutil
4 5 import sys
5 6
6 7 pjoin = os.path.join
7 8
8 9 from IPython.utils.path import get_ipython_dir
9 10 from IPython.utils.py3compat import PY3
10 11 from IPython.utils.traitlets import HasTraits, List, Unicode, Dict
11 12
12 13 if os.name == 'nt':
13 14 programdata = os.environ.get('PROGRAMDATA', None)
14 15 if programdata:
15 16 SYSTEM_KERNEL_DIR = pjoin(programdata, 'ipython', 'kernels')
16 17 else: # PROGRAMDATA is not defined by default on XP.
17 18 SYSTEM_KERNEL_DIR = None
18 19 else:
19 20 SYSTEM_KERNEL_DIR = "/usr/share/ipython/kernels"
20 21
21 22 NATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'
22 23
23 24 class KernelSpec(HasTraits):
24 25 argv = List()
25 26 display_name = Unicode()
26 27 language = Unicode()
27 28 codemirror_mode = None
28 29 env = Dict()
29 30
30 31 resource_dir = Unicode()
31 32
32 33 def __init__(self, resource_dir, argv, display_name, language,
33 34 codemirror_mode=None):
34 35 super(KernelSpec, self).__init__(resource_dir=resource_dir, argv=argv,
35 36 display_name=display_name, language=language,
36 37 codemirror_mode=codemirror_mode)
37 38 if not self.codemirror_mode:
38 39 self.codemirror_mode = self.language
39 40
40 41 @classmethod
41 42 def from_resource_dir(cls, resource_dir):
42 43 """Create a KernelSpec object by reading kernel.json
43 44
44 45 Pass the path to the *directory* containing kernel.json.
45 46 """
46 47 kernel_file = pjoin(resource_dir, 'kernel.json')
47 48 with io.open(kernel_file, 'r', encoding='utf-8') as f:
48 49 kernel_dict = json.load(f)
49 50 return cls(resource_dir=resource_dir, **kernel_dict)
50 51
51 52 def _is_kernel_dir(path):
52 53 """Is ``path`` a kernel directory?"""
53 54 return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json'))
54 55
55 56 def _list_kernels_in(dir):
56 57 """Return a mapping of kernel names to resource directories from dir.
57 58
58 59 If dir is None or does not exist, returns an empty dict.
59 60 """
60 61 if dir is None or not os.path.isdir(dir):
61 62 return {}
62 63 return {f.lower(): pjoin(dir, f) for f in os.listdir(dir)
63 64 if _is_kernel_dir(pjoin(dir, f))}
64 65
65 66 class NoSuchKernel(KeyError):
66 67 def __init__(self, name):
67 68 self.name = name
68 69
69 70 class KernelSpecManager(HasTraits):
70 71 ipython_dir = Unicode()
71 72 def _ipython_dir_default(self):
72 73 return get_ipython_dir()
73 74
74 75 user_kernel_dir = Unicode()
75 76 def _user_kernel_dir_default(self):
76 77 return pjoin(self.ipython_dir, 'kernels')
77 78
78 79 kernel_dirs = List(
79 80 help="List of kernel directories to search. Later ones take priority over earlier."
80 81 )
81 82 def _kernel_dirs_default(self):
82 83 return [
83 84 SYSTEM_KERNEL_DIR,
84 85 self.user_kernel_dir,
85 86 ]
86 87
87 88 def _make_native_kernel_dir(self):
88 89 """Makes a kernel directory for the native kernel.
89 90
90 91 The native kernel is the kernel using the same Python runtime as this
91 92 process. This will put its informatino in the user kernels directory.
92 93 """
93 94 path = pjoin(self.user_kernel_dir, NATIVE_KERNEL_NAME)
94 95 os.makedirs(path, mode=0o755)
95 96 with open(pjoin(path, 'kernel.json'), 'w') as f:
96 97 json.dump({'argv':[NATIVE_KERNEL_NAME, '-c',
97 98 'from IPython.kernel.zmq.kernelapp import main; main()',
98 99 '-f', '{connection_file}'],
99 100 'display_name': 'Python 3' if PY3 else 'Python 2',
100 101 'language': 'python',
101 102 'codemirror_mode': {'name': 'python',
102 103 'version': sys.version_info[0]},
103 104 },
104 105 f, indent=1)
105 106 # TODO: Copy icons into directory
106 107 return path
107 108
108 109 def find_kernel_specs(self):
109 110 """Returns a dict mapping kernel names to resource directories."""
110 111 d = {}
111 112 for kernel_dir in self.kernel_dirs:
112 113 d.update(_list_kernels_in(kernel_dir))
113 114
114 115 if NATIVE_KERNEL_NAME not in d:
115 116 d[NATIVE_KERNEL_NAME] = self._make_native_kernel_dir()
116 117 return d
117 118 # TODO: Caching?
118 119
119 120 def get_kernel_spec(self, kernel_name):
120 121 """Returns a :class:`KernelSpec` instance for the given kernel_name.
121 122
122 123 Raises :exc:`NoSuchKernel` if the given kernel name is not found.
123 124 """
124 125 if kernel_name == 'python':
125 126 kernel_name = NATIVE_KERNEL_NAME
126 127 d = self.find_kernel_specs()
127 128 try:
128 129 resource_dir = d[kernel_name.lower()]
129 130 except KeyError:
130 131 raise NoSuchKernel(kernel_name)
131 132 return KernelSpec.from_resource_dir(resource_dir)
132 133
134 def install_kernel_spec(self, source_dir, kernel_name=None, system=False,
135 replace=False):
136 """Install a kernel spec by copying its directory.
137
138 If ``kernel_name`` is not given, the basename of ``source_dir`` will
139 be used.
140
141 If ``system`` is True, it will attempt to install into the systemwide
142 kernel registry. If the process does not have appropriate permissions,
143 an :exc:`OSError` will be raised.
144
145 If ``replace`` is True, this will replace an existing kernel of the same
146 name. Otherwise, if the destination already exists, an :exc:`OSError`
147 will be raised.
148 """
149 if not kernel_name:
150 kernel_name = os.path.basename(source_dir)
151 kernel_name = kernel_name.lower()
152
153 if system:
154 destination = os.path.join(SYSTEM_KERNEL_DIR, kernel_name)
155 else:
156 destination = os.path.join(self.user_kernel_dir, kernel_name)
157
158 if replace and os.path.isdir(destination):
159 shutil.rmtree(destination)
160
161 shutil.copytree(source_dir, destination)
162
133 163 def find_kernel_specs():
134 164 """Returns a dict mapping kernel names to resource directories."""
135 165 return KernelSpecManager().find_kernel_specs()
136 166
137 167 def get_kernel_spec(kernel_name):
138 168 """Returns a :class:`KernelSpec` instance for the given kernel_name.
139 169
140 170 Raises KeyError if the given kernel name is not found.
141 171 """
142 172 return KernelSpecManager().get_kernel_spec(kernel_name)
173
174 def install_kernel_spec(source_dir, kernel_name=None, system=False):
175 return KernelSpecManager().install_kernel_spec(source_dir, kernel_name, system)
176
177 install_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__
General Comments 0
You need to be logged in to leave comments. Login now