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