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