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