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