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