##// END OF EJS Templates
Merge pull request #6291 from takluyver/explicit-install-native-kernelspec...
Min RK -
r17758:2ecbf779 merge
parent child Browse files
Show More
@@ -0,0 +1,2 b''
1 - :meth:`~.KernelManager.start_kernel` and :meth:`~.KernelManager.format_kernel_cmd`
2 no longer accept a ``executable`` parameter. Use the kernelspec machinery instead.
@@ -9,6 +9,7 b' pjoin = os.path.join'
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, Any
11 from IPython.utils.traitlets import HasTraits, List, Unicode, Dict, Any
12 from .launcher import make_ipkernel_cmd
12
13
13 if os.name == 'nt':
14 if os.name == 'nt':
14 programdata = os.environ.get('PROGRAMDATA', None)
15 programdata = os.environ.get('PROGRAMDATA', None)
@@ -100,51 +101,59 b' class KernelSpecManager(HasTraits):'
100 self.user_kernel_dir,
101 self.user_kernel_dir,
101 ]
102 ]
102
103
103 def _make_native_kernel_dir(self):
104 @property
105 def _native_kernel_dict(self):
104 """Makes a kernel directory for the native kernel.
106 """Makes a kernel directory for the native kernel.
105
107
106 The native kernel is the kernel using the same Python runtime as this
108 The native kernel is the kernel using the same Python runtime as this
107 process. This will put its informatino in the user kernels directory.
109 process. This will put its informatino in the user kernels directory.
108 """
110 """
109 path = pjoin(self.user_kernel_dir, NATIVE_KERNEL_NAME)
111 return {'argv':make_ipkernel_cmd(
110 os.makedirs(path, mode=0o755)
112 'from IPython.kernel.zmq.kernelapp import main; main()'),
111 with open(pjoin(path, 'kernel.json'), 'w') as f:
113 'display_name': 'IPython (Python %d)' % (3 if PY3 else 2),
112 json.dump({'argv':[NATIVE_KERNEL_NAME, '-c',
114 'language': 'python',
113 'from IPython.kernel.zmq.kernelapp import main; main()',
115 'codemirror_mode': {'name': 'ipython',
114 '-f', '{connection_file}'],
116 'version': sys.version_info[0]},
115 'display_name': 'IPython (Python %d)' % (3 if PY3 else 2),
117 }
116 'language': 'python',
118
117 'codemirror_mode': {'name': 'ipython',
119 @property
118 'version': sys.version_info[0]},
120 def _native_kernel_resource_dir(self):
119 },
121 # TODO: This may be different when we actually have any resources
120 f, indent=1)
122 return os.path.dirname(__file__)
121 # TODO: Copy icons into directory
123
122 return path
123
124 def find_kernel_specs(self):
124 def find_kernel_specs(self):
125 """Returns a dict mapping kernel names to resource directories."""
125 """Returns a dict mapping kernel names to resource directories."""
126 d = {}
126 d = {}
127 for kernel_dir in self.kernel_dirs:
127 for kernel_dir in self.kernel_dirs:
128 d.update(_list_kernels_in(kernel_dir))
128 d.update(_list_kernels_in(kernel_dir))
129
129
130 if NATIVE_KERNEL_NAME not in d:
130 d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir
131 d[NATIVE_KERNEL_NAME] = self._make_native_kernel_dir()
132 return d
131 return d
133 # TODO: Caching?
132 # TODO: Caching?
134
133
135 def get_kernel_spec(self, kernel_name):
134 def get_kernel_spec(self, kernel_name):
136 """Returns a :class:`KernelSpec` instance for the given kernel_name.
135 """Returns a :class:`KernelSpec` instance for the given kernel_name.
137
136
138 Raises :exc:`NoSuchKernel` if the given kernel name is not found.
137 Raises :exc:`NoSuchKernel` if the given kernel name is not found.
139 """
138 """
140 if kernel_name == 'python':
139 if kernel_name in {'python', NATIVE_KERNEL_NAME}:
141 kernel_name = NATIVE_KERNEL_NAME
140 return KernelSpec(self._native_kernel_resource_dir, **self._native_kernel_dict)
141
142 d = self.find_kernel_specs()
142 d = self.find_kernel_specs()
143 try:
143 try:
144 resource_dir = d[kernel_name.lower()]
144 resource_dir = d[kernel_name.lower()]
145 except KeyError:
145 except KeyError:
146 raise NoSuchKernel(kernel_name)
146 raise NoSuchKernel(kernel_name)
147 return KernelSpec.from_resource_dir(resource_dir)
147 return KernelSpec.from_resource_dir(resource_dir)
148
149 def _get_destination_dir(self, kernel_name, system=False):
150 if system:
151 if SYSTEM_KERNEL_DIRS:
152 return os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)
153 else:
154 raise EnvironmentError("No system kernel directory is available")
155 else:
156 return os.path.join(self.user_kernel_dir, kernel_name)
148
157
149 def install_kernel_spec(self, source_dir, kernel_name=None, system=False,
158 def install_kernel_spec(self, source_dir, kernel_name=None, system=False,
150 replace=False):
159 replace=False):
@@ -164,20 +173,32 b' class KernelSpecManager(HasTraits):'
164 if not kernel_name:
173 if not kernel_name:
165 kernel_name = os.path.basename(source_dir)
174 kernel_name = os.path.basename(source_dir)
166 kernel_name = kernel_name.lower()
175 kernel_name = kernel_name.lower()
167
176
168 if system:
177 destination = self._get_destination_dir(kernel_name, system=system)
169 if SYSTEM_KERNEL_DIRS:
170 destination = os.path.join(SYSTEM_KERNEL_DIRS[-1], kernel_name)
171 else:
172 raise EnvironmentError("No system kernel directory is available")
173 else:
174 destination = os.path.join(self.user_kernel_dir, kernel_name)
175
178
176 if replace and os.path.isdir(destination):
179 if replace and os.path.isdir(destination):
177 shutil.rmtree(destination)
180 shutil.rmtree(destination)
178
181
179 shutil.copytree(source_dir, destination)
182 shutil.copytree(source_dir, destination)
180
183
184 def install_native_kernel_spec(self, system=False):
185 """Install the native kernel spec to the filesystem
186
187 This allows a Python 3 frontend to use a Python 2 kernel, or vice versa.
188 The kernelspec will be written pointing to the Python executable on
189 which this is run.
190
191 If ``system`` is True, it will attempt to install into the systemwide
192 kernel registry. If the process does not have appropriate permissions,
193 an :exc:`OSError` will be raised.
194 """
195 path = self._get_destination_dir(NATIVE_KERNEL_NAME, system=system)
196 os.makedirs(path, mode=0o755)
197 with open(pjoin(path, 'kernel.json'), 'w') as f:
198 json.dump(self._native_kernel_dict, f, indent=1)
199 # TODO: Copy icons into directory
200 return path
201
181 def find_kernel_specs():
202 def find_kernel_specs():
182 """Returns a dict mapping kernel names to resource directories."""
203 """Returns a dict mapping kernel names to resource directories."""
183 return KernelSpecManager().find_kernel_specs()
204 return KernelSpecManager().find_kernel_specs()
@@ -194,3 +215,8 b' def install_kernel_spec(source_dir, kernel_name=None, system=False, replace=Fals'
194 system, replace)
215 system, replace)
195
216
196 install_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__
217 install_kernel_spec.__doc__ = KernelSpecManager.install_kernel_spec.__doc__
218
219 def install_native_kernel_spec(self, system=False):
220 return KernelSpecManager().install_native_kernel_spec(system=system)
221
222 install_native_kernel_spec.__doc__ = KernelSpecManager.install_native_kernel_spec.__doc__
@@ -91,15 +91,46 b' class InstallKernelSpec(BaseIPythonApplication):'
91 self.exit(1)
91 self.exit(1)
92 raise
92 raise
93
93
94 class InstallNativeKernelSpec(BaseIPythonApplication):
95 description = """Install the native kernel spec directory for this Python."""
96 kernel_spec_manager = Instance(KernelSpecManager)
97
98 def _kernel_spec_manager_default(self):
99 return KernelSpecManager(ipython_dir=self.ipython_dir)
100
101 system = Bool(False, config=True,
102 help="""
103 Try to install the kernel spec to the systemwide directory instead of
104 the per-user directory.
105 """
106 )
107
108 # Not all of the base aliases are meaningful (e.g. profile)
109 aliases = {k: base_aliases[k] for k in ['ipython-dir', 'log-level']}
110 flags = {'system': ({'InstallOwnKernelSpec': {'system': True}},
111 "Install to the systemwide kernel registry"),
112 'debug': base_flags['debug'],
113 }
114
115 def start(self):
116 try:
117 self.kernel_spec_manager.install_native_kernel_spec(system=self.system)
118 except OSError as e:
119 if e.errno == errno.EACCES:
120 print("Permission denied")
121 self.exit(1)
122 raise
123
94 class KernelSpecApp(Application):
124 class KernelSpecApp(Application):
95 name = "ipython kernelspec"
125 name = "ipython kernelspec"
96 description = """Manage IPython kernel specifications."""
126 description = """Manage IPython kernel specifications."""
97
127
98 subcommands = Dict(dict(
128 subcommands = Dict({
99 list = (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
129 'list': (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
100 install = (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0])
130 'install': (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0]),
101 ))
131 'install-self': (InstallNativeKernelSpec, InstallNativeKernelSpec.description.splitlines()[0]),
102
132 })
133
103 aliases = {}
134 aliases = {}
104 flags = {}
135 flags = {}
105
136
@@ -97,14 +97,11 b' def make_ipkernel_cmd(code, executable=None, extra_arguments=[], **kw):'
97
97
98 A Popen command list
98 A Popen command list
99 """
99 """
100
101 # Build the kernel launch command.
102 if executable is None:
100 if executable is None:
103 executable = sys.executable
101 executable = sys.executable
104 arguments = [ executable, '-c', code, '-f', '{connection_file}' ]
102 arguments = [ executable, '-c', code, '-f', '{connection_file}' ]
105 arguments.extend(extra_arguments)
103 arguments.extend(extra_arguments)
106
104
107 # Spawn a kernel.
108 if sys.platform == 'win32':
105 if sys.platform == 'win32':
109
106
110 # If the kernel is running on pythonw and stdout/stderr are not been
107 # If the kernel is running on pythonw and stdout/stderr are not been
@@ -159,18 +159,13 b' class KernelManager(ConnectionFileMixin):'
159 # Kernel management
159 # Kernel management
160 #--------------------------------------------------------------------------
160 #--------------------------------------------------------------------------
161
161
162 def format_kernel_cmd(self, **kw):
162 def format_kernel_cmd(self, extra_arguments=None):
163 """replace templated args (e.g. {connection_file})"""
163 """replace templated args (e.g. {connection_file})"""
164 extra_arguments = extra_arguments or []
164 if self.kernel_cmd:
165 if self.kernel_cmd:
165 cmd = self.kernel_cmd
166 cmd = self.kernel_cmd + extra_arguments
166 elif self.kernel_name == kernelspec.NATIVE_KERNEL_NAME:
167 # The native kernel gets special handling
168 cmd = make_ipkernel_cmd(
169 'from IPython.kernel.zmq.kernelapp import main; main()',
170 **kw
171 )
172 else:
167 else:
173 cmd = self.kernel_spec.argv
168 cmd = self.kernel_spec.argv + extra_arguments
174
169
175 ns = dict(connection_file=self.connection_file)
170 ns = dict(connection_file=self.connection_file)
176 ns.update(self._launch_args)
171 ns.update(self._launch_args)
@@ -227,7 +222,8 b' class KernelManager(ConnectionFileMixin):'
227 # save kwargs for use in restart
222 # save kwargs for use in restart
228 self._launch_args = kw.copy()
223 self._launch_args = kw.copy()
229 # build the Popen cmd
224 # build the Popen cmd
230 kernel_cmd = self.format_kernel_cmd(**kw)
225 extra_arguments = kw.pop('extra_arguments', [])
226 kernel_cmd = self.format_kernel_cmd(extra_arguments=extra_arguments)
231 if self.kernel_cmd:
227 if self.kernel_cmd:
232 # If kernel_cmd has been set manually, don't refer to a kernel spec
228 # If kernel_cmd has been set manually, don't refer to a kernel spec
233 env = os.environ
229 env = os.environ
General Comments 0
You need to be logged in to leave comments. Login now