##// END OF EJS Templates
Merge pull request #7381 from dsblank/patch-4...
Matthias Bussonnier -
r19811:a9e5b954 merge
parent child Browse files
Show More
@@ -1,222 +1,222 b''
1 import io
1 import io
2 import json
2 import json
3 import os
3 import os
4 import shutil
4 import shutil
5 import sys
5 import sys
6
6
7 pjoin = os.path.join
7 pjoin = os.path.join
8
8
9 from IPython.utils.path import get_ipython_dir
9 from IPython.utils.path import get_ipython_dir
10 from IPython.utils.py3compat import PY3
10 from IPython.utils.py3compat import PY3
11 from IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any
11 from IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any
12 from .launcher import make_ipkernel_cmd
12 from .launcher import make_ipkernel_cmd
13
13
14 if os.name == 'nt':
14 if os.name == 'nt':
15 programdata = os.environ.get('PROGRAMDATA', None)
15 programdata = os.environ.get('PROGRAMDATA', None)
16 if programdata:
16 if programdata:
17 SYSTEM_KERNEL_DIRS = [pjoin(programdata, 'ipython', 'kernels')]
17 SYSTEM_KERNEL_DIRS = [pjoin(programdata, 'ipython', 'kernels')]
18 else: # PROGRAMDATA is not defined by default on XP.
18 else: # PROGRAMDATA is not defined by default on XP.
19 SYSTEM_KERNEL_DIRS = []
19 SYSTEM_KERNEL_DIRS = []
20 else:
20 else:
21 SYSTEM_KERNEL_DIRS = ["/usr/share/jupyter/kernels",
21 SYSTEM_KERNEL_DIRS = ["/usr/share/jupyter/kernels",
22 "/usr/local/share/jupyter/kernels",
22 "/usr/local/share/jupyter/kernels",
23 ]
23 ]
24
24
25 NATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'
25 NATIVE_KERNEL_NAME = 'python3' if PY3 else 'python2'
26
26
27 def _pythonfirst(s):
27 def _pythonfirst(s):
28 "Sort key function that will put strings starting with 'python' first."
28 "Sort key function that will put strings starting with 'python' first."
29 if s == NATIVE_KERNEL_NAME:
29 if s == NATIVE_KERNEL_NAME:
30 return ' ' + s # Two spaces to sort this first of all
30 return ' ' + s # Two spaces to sort this first of all
31 elif s.startswith('python'):
31 elif s.startswith('python'):
32 # Space is not valid in kernel names, so this should sort first
32 # Space is not valid in kernel names, so this should sort first
33 return ' ' + s
33 return ' ' + s
34 return s
34 return s
35
35
36 class KernelSpec(HasTraits):
36 class KernelSpec(HasTraits):
37 argv = List()
37 argv = List()
38 display_name = Unicode()
38 display_name = Unicode()
39 env = Dict()
39 env = Dict()
40 resource_dir = Unicode()
40 resource_dir = Unicode()
41
41
42 @classmethod
42 @classmethod
43 def from_resource_dir(cls, resource_dir):
43 def from_resource_dir(cls, resource_dir):
44 """Create a KernelSpec object by reading kernel.json
44 """Create a KernelSpec object by reading kernel.json
45
45
46 Pass the path to the *directory* containing kernel.json.
46 Pass the path to the *directory* containing kernel.json.
47 """
47 """
48 kernel_file = pjoin(resource_dir, 'kernel.json')
48 kernel_file = pjoin(resource_dir, 'kernel.json')
49 with io.open(kernel_file, 'r', encoding='utf-8') as f:
49 with io.open(kernel_file, 'r', encoding='utf-8') as f:
50 kernel_dict = json.load(f)
50 kernel_dict = json.load(f)
51 return cls(resource_dir=resource_dir, **kernel_dict)
51 return cls(resource_dir=resource_dir, **kernel_dict)
52
52
53 def to_dict(self):
53 def to_dict(self):
54 d = dict(argv=self.argv,
54 d = dict(argv=self.argv,
55 env=self.env,
55 env=self.env,
56 display_name=self.display_name,
56 display_name=self.display_name,
57 )
57 )
58
58
59 return d
59 return d
60
60
61 def to_json(self):
61 def to_json(self):
62 return json.dumps(self.to_dict())
62 return json.dumps(self.to_dict())
63
63
64 def _is_kernel_dir(path):
64 def _is_kernel_dir(path):
65 """Is ``path`` a kernel directory?"""
65 """Is ``path`` a kernel directory?"""
66 return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json'))
66 return os.path.isdir(path) and os.path.isfile(pjoin(path, 'kernel.json'))
67
67
68 def _list_kernels_in(dir):
68 def _list_kernels_in(dir):
69 """Return a mapping of kernel names to resource directories from dir.
69 """Return a mapping of kernel names to resource directories from dir.
70
70
71 If dir is None or does not exist, returns an empty dict.
71 If dir is None or does not exist, returns an empty dict.
72 """
72 """
73 if dir is None or not os.path.isdir(dir):
73 if dir is None or not os.path.isdir(dir):
74 return {}
74 return {}
75 return {f.lower(): pjoin(dir, f) for f in os.listdir(dir)
75 return {f.lower(): pjoin(dir, f) for f in os.listdir(dir)
76 if _is_kernel_dir(pjoin(dir, f))}
76 if _is_kernel_dir(pjoin(dir, f))}
77
77
78 class NoSuchKernel(KeyError):
78 class NoSuchKernel(KeyError):
79 def __init__(self, name):
79 def __init__(self, name):
80 self.name = name
80 self.name = name
81
81
82 class KernelSpecManager(HasTraits):
82 class KernelSpecManager(HasTraits):
83 ipython_dir = Unicode()
83 ipython_dir = Unicode()
84 def _ipython_dir_default(self):
84 def _ipython_dir_default(self):
85 return get_ipython_dir()
85 return get_ipython_dir()
86
86
87 user_kernel_dir = Unicode()
87 user_kernel_dir = Unicode()
88 def _user_kernel_dir_default(self):
88 def _user_kernel_dir_default(self):
89 return pjoin(self.ipython_dir, 'kernels')
89 return pjoin(self.ipython_dir, 'kernels')
90
90
91 @property
91 @property
92 def env_kernel_dir(self):
92 def env_kernel_dir(self):
93 return pjoin(sys.prefix, 'share', 'jupyter', 'kernels')
93 return pjoin(sys.prefix, 'share', 'jupyter', 'kernels')
94
94
95 kernel_dirs = List(
95 kernel_dirs = List(
96 help="List of kernel directories to search. Later ones take priority over earlier."
96 help="List of kernel directories to search. Later ones take priority over earlier."
97 )
97 )
98 def _kernel_dirs_default(self):
98 def _kernel_dirs_default(self):
99 dirs = SYSTEM_KERNEL_DIRS[:]
99 dirs = SYSTEM_KERNEL_DIRS[:]
100 if self.env_kernel_dir not in dirs:
100 if self.env_kernel_dir not in dirs:
101 dirs.append(self.env_kernel_dir)
101 dirs.append(self.env_kernel_dir)
102 dirs.append(self.user_kernel_dir)
102 dirs.append(self.user_kernel_dir)
103 return dirs
103 return dirs
104
104
105 @property
105 @property
106 def _native_kernel_dict(self):
106 def _native_kernel_dict(self):
107 """Makes a kernel directory for the native kernel.
107 """Makes a kernel directory for the native kernel.
108
108
109 The native kernel is the kernel using the same Python runtime as this
109 The native kernel is the kernel using the same Python runtime as this
110 process. This will put its information in the user kernels directory.
110 process. This will put its information in the user kernels directory.
111 """
111 """
112 return {'argv': make_ipkernel_cmd(),
112 return {'argv': make_ipkernel_cmd(),
113 'display_name': 'Python %i' % (3 if PY3 else 2),
113 'display_name': 'Python %i' % (3 if PY3 else 2),
114 }
114 }
115
115
116 @property
116 @property
117 def _native_kernel_resource_dir(self):
117 def _native_kernel_resource_dir(self):
118 return pjoin(os.path.dirname(__file__), 'resources')
118 return pjoin(os.path.dirname(__file__), 'resources')
119
119
120 def find_kernel_specs(self):
120 def find_kernel_specs(self):
121 """Returns a dict mapping kernel names to resource directories."""
121 """Returns a dict mapping kernel names to resource directories."""
122 d = {}
122 d = {}
123 for kernel_dir in self.kernel_dirs:
123 for kernel_dir in self.kernel_dirs:
124 d.update(_list_kernels_in(kernel_dir))
124 d.update(_list_kernels_in(kernel_dir))
125
125
126 d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir
126 d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir
127 return d
127 return d
128 # TODO: Caching?
128 # TODO: Caching?
129
129
130 def get_kernel_spec(self, kernel_name):
130 def get_kernel_spec(self, kernel_name):
131 """Returns a :class:`KernelSpec` instance for the given kernel_name.
131 """Returns a :class:`KernelSpec` instance for the given kernel_name.
132
132
133 Raises :exc:`NoSuchKernel` if the given kernel name is not found.
133 Raises :exc:`NoSuchKernel` if the given kernel name is not found.
134 """
134 """
135 if kernel_name in {'python', NATIVE_KERNEL_NAME}:
135 if kernel_name in {'python', NATIVE_KERNEL_NAME}:
136 return KernelSpec(resource_dir=self._native_kernel_resource_dir,
136 return KernelSpec(resource_dir=self._native_kernel_resource_dir,
137 **self._native_kernel_dict)
137 **self._native_kernel_dict)
138
138
139 d = self.find_kernel_specs()
139 d = self.find_kernel_specs()
140 try:
140 try:
141 resource_dir = d[kernel_name.lower()]
141 resource_dir = d[kernel_name.lower()]
142 except KeyError:
142 except KeyError:
143 raise NoSuchKernel(kernel_name)
143 raise NoSuchKernel(kernel_name)
144 return KernelSpec.from_resource_dir(resource_dir)
144 return KernelSpec.from_resource_dir(resource_dir)
145
145
146 def _get_destination_dir(self, kernel_name, user=False):
146 def _get_destination_dir(self, kernel_name, user=False):
147 if user:
147 if user:
148 return os.path.join(self.user_kernel_dir, kernel_name)
148 return os.path.join(self.user_kernel_dir, kernel_name)
149 else:
149 else:
150 if SYSTEM_KERNEL_DIRS:
150 if SYSTEM_KERNEL_DIRS:
151 return os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)
151 return os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)
152 else:
152 else:
153 raise EnvironmentError("No system kernel directory is available")
153 raise EnvironmentError("No system kernel directory is available")
154
154
155
155
156 def install_kernel_spec(self, source_dir, kernel_name=None, user=False,
156 def install_kernel_spec(self, source_dir, kernel_name=None, user=False,
157 replace=False):
157 replace=False):
158 """Install a kernel spec by copying its directory.
158 """Install a kernel spec by copying its directory.
159
159
160 If ``kernel_name`` is not given, the basename of ``source_dir`` will
160 If ``kernel_name`` is not given, the basename of ``source_dir`` will
161 be used.
161 be used.
162
162
163 If ``system`` is True, it will attempt to install into the systemwide
163 If ``user`` is False, it will attempt to install into the systemwide
164 kernel registry. If the process does not have appropriate permissions,
164 kernel registry. If the process does not have appropriate permissions,
165 an :exc:`OSError` will be raised.
165 an :exc:`OSError` will be raised.
166
166
167 If ``replace`` is True, this will replace an existing kernel of the same
167 If ``replace`` is True, this will replace an existing kernel of the same
168 name. Otherwise, if the destination already exists, an :exc:`OSError`
168 name. Otherwise, if the destination already exists, an :exc:`OSError`
169 will be raised.
169 will be raised.
170 """
170 """
171 if not kernel_name:
171 if not kernel_name:
172 kernel_name = os.path.basename(source_dir)
172 kernel_name = os.path.basename(source_dir)
173 kernel_name = kernel_name.lower()
173 kernel_name = kernel_name.lower()
174
174
175 destination = self._get_destination_dir(kernel_name, user=user)
175 destination = self._get_destination_dir(kernel_name, user=user)
176
176
177 if replace and os.path.isdir(destination):
177 if replace and os.path.isdir(destination):
178 shutil.rmtree(destination)
178 shutil.rmtree(destination)
179
179
180 shutil.copytree(source_dir, destination)
180 shutil.copytree(source_dir, destination)
181
181
182 def install_native_kernel_spec(self, user=False):
182 def install_native_kernel_spec(self, user=False):
183 """Install the native kernel spec to the filesystem
183 """Install the native kernel spec to the filesystem
184
184
185 This allows a Python 3 frontend to use a Python 2 kernel, or vice versa.
185 This allows a Python 3 frontend to use a Python 2 kernel, or vice versa.
186 The kernelspec will be written pointing to the Python executable on
186 The kernelspec will be written pointing to the Python executable on
187 which this is run.
187 which this is run.
188
188
189 If ``system`` is True, it will attempt to install into the systemwide
189 If ``user`` is False, it will attempt to install into the systemwide
190 kernel registry. If the process does not have appropriate permissions,
190 kernel registry. If the process does not have appropriate permissions,
191 an :exc:`OSError` will be raised.
191 an :exc:`OSError` will be raised.
192 """
192 """
193 path = self._get_destination_dir(NATIVE_KERNEL_NAME, user=user)
193 path = self._get_destination_dir(NATIVE_KERNEL_NAME, user=user)
194 os.makedirs(path, mode=0o755)
194 os.makedirs(path, mode=0o755)
195 with open(pjoin(path, 'kernel.json'), 'w') as f:
195 with open(pjoin(path, 'kernel.json'), 'w') as f:
196 json.dump(self._native_kernel_dict, f, indent=1)
196 json.dump(self._native_kernel_dict, f, indent=1)
197 copy_from = self._native_kernel_resource_dir
197 copy_from = self._native_kernel_resource_dir
198 for file in os.listdir(copy_from):
198 for file in os.listdir(copy_from):
199 shutil.copy(pjoin(copy_from, file), path)
199 shutil.copy(pjoin(copy_from, file), path)
200 return path
200 return path
201
201
202 def find_kernel_specs():
202 def find_kernel_specs():
203 """Returns a dict mapping kernel names to resource directories."""
203 """Returns a dict mapping kernel names to resource directories."""
204 return KernelSpecManager().find_kernel_specs()
204 return KernelSpecManager().find_kernel_specs()
205
205
206 def get_kernel_spec(kernel_name):
206 def get_kernel_spec(kernel_name):
207 """Returns a :class:`KernelSpec` instance for the given kernel_name.
207 """Returns a :class:`KernelSpec` instance for the given kernel_name.
208
208
209 Raises KeyError if the given kernel name is not found.
209 Raises KeyError if the given kernel name is not found.
210 """
210 """
211 return KernelSpecManager().get_kernel_spec(kernel_name)
211 return KernelSpecManager().get_kernel_spec(kernel_name)
212
212
213 def install_kernel_spec(source_dir, kernel_name=None, user=False, replace=False):
213 def install_kernel_spec(source_dir, kernel_name=None, user=False, replace=False):
214 return KernelSpecManager().install_kernel_spec(source_dir, kernel_name,
214 return KernelSpecManager().install_kernel_spec(source_dir, kernel_name,
215 user, replace)
215 user, replace)
216
216
217 install_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__
217 install_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__
218
218
219 def install_native_kernel_spec(user=False):
219 def install_native_kernel_spec(user=False):
220 return KernelSpecManager().install_native_kernel_spec(user=user)
220 return KernelSpecManager().install_native_kernel_spec(user=user)
221
221
222 install_native_kernel_spec.__doc__ = KernelSpecManager.install_native_kernel_spec.__doc__
222 install_native_kernel_spec.__doc__ = KernelSpecManager.install_native_kernel_spec.__doc__
General Comments 0
You need to be logged in to leave comments. Login now