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