##// 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 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, Any
12 from .launcher import make_ipkernel_cmd
12 13
13 14 if os.name == 'nt':
14 15 programdata = os.environ.get('PROGRAMDATA', None)
@@ -100,51 +101,59 b' class KernelSpecManager(HasTraits):'
100 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 106 """Makes a kernel directory for the native kernel.
105 107
106 108 The native kernel is the kernel using the same Python runtime as this
107 109 process. This will put its informatino in the user kernels directory.
108 110 """
109 path = pjoin(self.user_kernel_dir, NATIVE_KERNEL_NAME)
110 os.makedirs(path, mode=0o755)
111 with open(pjoin(path, 'kernel.json'), 'w') as f:
112 json.dump({'argv':[NATIVE_KERNEL_NAME, '-c',
113 'from IPython.kernel.zmq.kernelapp import main; main()',
114 '-f', '{connection_file}'],
115 'display_name': 'IPython (Python %d)' % (3 if PY3 else 2),
116 'language': 'python',
117 'codemirror_mode': {'name': 'ipython',
118 'version': sys.version_info[0]},
119 },
120 f, indent=1)
121 # TODO: Copy icons into directory
122 return path
123
111 return {'argv':make_ipkernel_cmd(
112 'from IPython.kernel.zmq.kernelapp import main; main()'),
113 'display_name': 'IPython (Python %d)' % (3 if PY3 else 2),
114 'language': 'python',
115 'codemirror_mode': {'name': 'ipython',
116 'version': sys.version_info[0]},
117 }
118
119 @property
120 def _native_kernel_resource_dir(self):
121 # TODO: This may be different when we actually have any resources
122 return os.path.dirname(__file__)
123
124 124 def find_kernel_specs(self):
125 125 """Returns a dict mapping kernel names to resource directories."""
126 126 d = {}
127 127 for kernel_dir in self.kernel_dirs:
128 128 d.update(_list_kernels_in(kernel_dir))
129
130 if NATIVE_KERNEL_NAME not in d:
131 d[NATIVE_KERNEL_NAME] = self._make_native_kernel_dir()
129
130 d[NATIVE_KERNEL_NAME] = self._native_kernel_resource_dir
132 131 return d
133 132 # TODO: Caching?
134
133
135 134 def get_kernel_spec(self, kernel_name):
136 135 """Returns a :class:`KernelSpec` instance for the given kernel_name.
137 136
138 137 Raises :exc:`NoSuchKernel` if the given kernel name is not found.
139 138 """
140 if kernel_name == 'python':
141 kernel_name = NATIVE_KERNEL_NAME
139 if kernel_name in {'python', NATIVE_KERNEL_NAME}:
140 return KernelSpec(self._native_kernel_resource_dir, **self._native_kernel_dict)
141
142 142 d = self.find_kernel_specs()
143 143 try:
144 144 resource_dir = d[kernel_name.lower()]
145 145 except KeyError:
146 146 raise NoSuchKernel(kernel_name)
147 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 158 def install_kernel_spec(self, source_dir, kernel_name=None, system=False,
150 159 replace=False):
@@ -164,20 +173,32 b' class KernelSpecManager(HasTraits):'
164 173 if not kernel_name:
165 174 kernel_name = os.path.basename(source_dir)
166 175 kernel_name = kernel_name.lower()
167
168 if 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)
176
177 destination = self._get_destination_dir(kernel_name, system=system)
175 178
176 179 if replace and os.path.isdir(destination):
177 180 shutil.rmtree(destination)
178 181
179 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 202 def find_kernel_specs():
182 203 """Returns a dict mapping kernel names to resource directories."""
183 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 215 system, replace)
195 216
196 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 91 self.exit(1)
92 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 124 class KernelSpecApp(Application):
95 125 name = "ipython kernelspec"
96 126 description = """Manage IPython kernel specifications."""
97 127
98 subcommands = Dict(dict(
99 list = (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
100 install = (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0])
101 ))
102
128 subcommands = Dict({
129 'list': (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
130 'install': (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0]),
131 'install-self': (InstallNativeKernelSpec, InstallNativeKernelSpec.description.splitlines()[0]),
132 })
133
103 134 aliases = {}
104 135 flags = {}
105 136
@@ -97,14 +97,11 b' def make_ipkernel_cmd(code, executable=None, extra_arguments=[], **kw):'
97 97
98 98 A Popen command list
99 99 """
100
101 # Build the kernel launch command.
102 100 if executable is None:
103 101 executable = sys.executable
104 102 arguments = [ executable, '-c', code, '-f', '{connection_file}' ]
105 103 arguments.extend(extra_arguments)
106 104
107 # Spawn a kernel.
108 105 if sys.platform == 'win32':
109 106
110 107 # If the kernel is running on pythonw and stdout/stderr are not been
@@ -159,18 +159,13 b' class KernelManager(ConnectionFileMixin):'
159 159 # Kernel management
160 160 #--------------------------------------------------------------------------
161 161
162 def format_kernel_cmd(self, **kw):
162 def format_kernel_cmd(self, extra_arguments=None):
163 163 """replace templated args (e.g. {connection_file})"""
164 extra_arguments = extra_arguments or []
164 165 if self.kernel_cmd:
165 cmd = self.kernel_cmd
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 )
166 cmd = self.kernel_cmd + extra_arguments
172 167 else:
173 cmd = self.kernel_spec.argv
168 cmd = self.kernel_spec.argv + extra_arguments
174 169
175 170 ns = dict(connection_file=self.connection_file)
176 171 ns.update(self._launch_args)
@@ -227,7 +222,8 b' class KernelManager(ConnectionFileMixin):'
227 222 # save kwargs for use in restart
228 223 self._launch_args = kw.copy()
229 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 227 if self.kernel_cmd:
232 228 # If kernel_cmd has been set manually, don't refer to a kernel spec
233 229 env = os.environ
General Comments 0
You need to be logged in to leave comments. Login now