##// END OF EJS Templates
Trim which options are exposed on kernelspec CLI
Thomas Kluyver -
Show More
@@ -1,389 +1,389 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating configurables.
6 handling configuration and creating configurables.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10
10
11 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15 * Min RK
15 * Min RK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008 The IPython Development Team
20 # Copyright (C) 2008 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 import atexit
30 import atexit
31 import glob
31 import glob
32 import logging
32 import logging
33 import os
33 import os
34 import shutil
34 import shutil
35 import sys
35 import sys
36
36
37 from IPython.config.application import Application, catch_config_error
37 from IPython.config.application import Application, catch_config_error
38 from IPython.config.loader import ConfigFileNotFound
38 from IPython.config.loader import ConfigFileNotFound
39 from IPython.core import release, crashhandler
39 from IPython.core import release, crashhandler
40 from IPython.core.profiledir import ProfileDir, ProfileDirError
40 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
41 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
42 from IPython.utils import py3compat
42 from IPython.utils import py3compat
43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Classes and functions
46 # Classes and functions
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Base Application Class
51 # Base Application Class
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 # aliases and flags
54 # aliases and flags
55
55
56 base_aliases = {
56 base_aliases = {
57 'profile-dir' : 'ProfileDir.location',
57 'profile-dir' : 'ProfileDir.location',
58 'profile' : 'BaseIPythonApplication.profile',
58 'profile' : 'BaseIPythonApplication.profile',
59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 'log-level' : 'Application.log_level',
60 'log-level' : 'Application.log_level',
61 'config' : 'BaseIPythonApplication.extra_config_file',
61 'config' : 'BaseIPythonApplication.extra_config_file',
62 }
62 }
63
63
64 base_flags = dict(
64 base_flags = dict(
65 debug = ({'Application' : {'log_level' : logging.DEBUG}},
65 debug = ({'Application' : {'log_level' : logging.DEBUG}},
66 "set log level to logging.DEBUG (maximize logging output)"),
66 "set log level to logging.DEBUG (maximize logging output)"),
67 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
67 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
68 "set log level to logging.CRITICAL (minimize logging output)"),
68 "set log level to logging.CRITICAL (minimize logging output)"),
69 init = ({'BaseIPythonApplication' : {
69 init = ({'BaseIPythonApplication' : {
70 'copy_config_files' : True,
70 'copy_config_files' : True,
71 'auto_create' : True}
71 'auto_create' : True}
72 }, """Initialize profile with default config files. This is equivalent
72 }, """Initialize profile with default config files. This is equivalent
73 to running `ipython profile create <profile>` prior to startup.
73 to running `ipython profile create <profile>` prior to startup.
74 """)
74 """)
75 )
75 )
76
76
77
77
78 class BaseIPythonApplication(Application):
78 class BaseIPythonApplication(Application):
79
79
80 name = Unicode(u'ipython')
80 name = Unicode(u'ipython')
81 description = Unicode(u'IPython: an enhanced interactive Python shell.')
81 description = Unicode(u'IPython: an enhanced interactive Python shell.')
82 version = Unicode(release.version)
82 version = Unicode(release.version)
83
83
84 aliases = Dict(base_aliases)
84 aliases = Dict(base_aliases)
85 flags = Dict(base_flags)
85 flags = Dict(base_flags)
86 classes = List([ProfileDir])
86 classes = List([ProfileDir])
87
87
88 # Track whether the config_file has changed,
88 # Track whether the config_file has changed,
89 # because some logic happens only if we aren't using the default.
89 # because some logic happens only if we aren't using the default.
90 config_file_specified = Set()
90 config_file_specified = Set()
91
91
92 config_file_name = Unicode()
92 config_file_name = Unicode()
93 def _config_file_name_default(self):
93 def _config_file_name_default(self):
94 return self.name.replace('-','_') + u'_config.py'
94 return self.name.replace('-','_') + u'_config.py'
95 def _config_file_name_changed(self, name, old, new):
95 def _config_file_name_changed(self, name, old, new):
96 if new != old:
96 if new != old:
97 self.config_file_specified.add(new)
97 self.config_file_specified.add(new)
98
98
99 # The directory that contains IPython's builtin profiles.
99 # The directory that contains IPython's builtin profiles.
100 builtin_profile_dir = Unicode(
100 builtin_profile_dir = Unicode(
101 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
101 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
102 )
102 )
103
103
104 config_file_paths = List(Unicode)
104 config_file_paths = List(Unicode)
105 def _config_file_paths_default(self):
105 def _config_file_paths_default(self):
106 return [py3compat.getcwd()]
106 return [py3compat.getcwd()]
107
107
108 extra_config_file = Unicode(config=True,
108 extra_config_file = Unicode(config=True,
109 help="""Path to an extra config file to load.
109 help="""Path to an extra config file to load.
110
110
111 If specified, load this config file in addition to any other IPython config.
111 If specified, load this config file in addition to any other IPython config.
112 """)
112 """)
113 def _extra_config_file_changed(self, name, old, new):
113 def _extra_config_file_changed(self, name, old, new):
114 try:
114 try:
115 self.config_files.remove(old)
115 self.config_files.remove(old)
116 except ValueError:
116 except ValueError:
117 pass
117 pass
118 self.config_file_specified.add(new)
118 self.config_file_specified.add(new)
119 self.config_files.append(new)
119 self.config_files.append(new)
120
120
121 profile = Unicode(u'default', config=True,
121 profile = Unicode(u'default', config=True,
122 help="""The IPython profile to use."""
122 help="""The IPython profile to use."""
123 )
123 )
124
124
125 def _profile_changed(self, name, old, new):
125 def _profile_changed(self, name, old, new):
126 self.builtin_profile_dir = os.path.join(
126 self.builtin_profile_dir = os.path.join(
127 get_ipython_package_dir(), u'config', u'profile', new
127 get_ipython_package_dir(), u'config', u'profile', new
128 )
128 )
129
129
130 ipython_dir = Unicode(config=True,
130 ipython_dir = Unicode(config=True,
131 help="""
131 help="""
132 The name of the IPython directory. This directory is used for logging
132 The name of the IPython directory. This directory is used for logging
133 configuration (through profiles), history storage, etc. The default
133 configuration (through profiles), history storage, etc. The default
134 is usually $HOME/.ipython. This options can also be specified through
134 is usually $HOME/.ipython. This option can also be specified through
135 the environment variable IPYTHONDIR.
135 the environment variable IPYTHONDIR.
136 """
136 """
137 )
137 )
138 def _ipython_dir_default(self):
138 def _ipython_dir_default(self):
139 d = get_ipython_dir()
139 d = get_ipython_dir()
140 self._ipython_dir_changed('ipython_dir', d, d)
140 self._ipython_dir_changed('ipython_dir', d, d)
141 return d
141 return d
142
142
143 _in_init_profile_dir = False
143 _in_init_profile_dir = False
144 profile_dir = Instance(ProfileDir)
144 profile_dir = Instance(ProfileDir)
145 def _profile_dir_default(self):
145 def _profile_dir_default(self):
146 # avoid recursion
146 # avoid recursion
147 if self._in_init_profile_dir:
147 if self._in_init_profile_dir:
148 return
148 return
149 # profile_dir requested early, force initialization
149 # profile_dir requested early, force initialization
150 self.init_profile_dir()
150 self.init_profile_dir()
151 return self.profile_dir
151 return self.profile_dir
152
152
153 overwrite = Bool(False, config=True,
153 overwrite = Bool(False, config=True,
154 help="""Whether to overwrite existing config files when copying""")
154 help="""Whether to overwrite existing config files when copying""")
155 auto_create = Bool(False, config=True,
155 auto_create = Bool(False, config=True,
156 help="""Whether to create profile dir if it doesn't exist""")
156 help="""Whether to create profile dir if it doesn't exist""")
157
157
158 config_files = List(Unicode)
158 config_files = List(Unicode)
159 def _config_files_default(self):
159 def _config_files_default(self):
160 return [self.config_file_name]
160 return [self.config_file_name]
161
161
162 copy_config_files = Bool(False, config=True,
162 copy_config_files = Bool(False, config=True,
163 help="""Whether to install the default config files into the profile dir.
163 help="""Whether to install the default config files into the profile dir.
164 If a new profile is being created, and IPython contains config files for that
164 If a new profile is being created, and IPython contains config files for that
165 profile, then they will be staged into the new directory. Otherwise,
165 profile, then they will be staged into the new directory. Otherwise,
166 default config files will be automatically generated.
166 default config files will be automatically generated.
167 """)
167 """)
168
168
169 verbose_crash = Bool(False, config=True,
169 verbose_crash = Bool(False, config=True,
170 help="""Create a massive crash report when IPython encounters what may be an
170 help="""Create a massive crash report when IPython encounters what may be an
171 internal error. The default is to append a short message to the
171 internal error. The default is to append a short message to the
172 usual traceback""")
172 usual traceback""")
173
173
174 # The class to use as the crash handler.
174 # The class to use as the crash handler.
175 crash_handler_class = Type(crashhandler.CrashHandler)
175 crash_handler_class = Type(crashhandler.CrashHandler)
176
176
177 @catch_config_error
177 @catch_config_error
178 def __init__(self, **kwargs):
178 def __init__(self, **kwargs):
179 super(BaseIPythonApplication, self).__init__(**kwargs)
179 super(BaseIPythonApplication, self).__init__(**kwargs)
180 # ensure current working directory exists
180 # ensure current working directory exists
181 try:
181 try:
182 directory = py3compat.getcwd()
182 directory = py3compat.getcwd()
183 except:
183 except:
184 # raise exception
184 # raise exception
185 self.log.error("Current working directory doesn't exist.")
185 self.log.error("Current working directory doesn't exist.")
186 raise
186 raise
187
187
188 #-------------------------------------------------------------------------
188 #-------------------------------------------------------------------------
189 # Various stages of Application creation
189 # Various stages of Application creation
190 #-------------------------------------------------------------------------
190 #-------------------------------------------------------------------------
191
191
192 def init_crash_handler(self):
192 def init_crash_handler(self):
193 """Create a crash handler, typically setting sys.excepthook to it."""
193 """Create a crash handler, typically setting sys.excepthook to it."""
194 self.crash_handler = self.crash_handler_class(self)
194 self.crash_handler = self.crash_handler_class(self)
195 sys.excepthook = self.excepthook
195 sys.excepthook = self.excepthook
196 def unset_crashhandler():
196 def unset_crashhandler():
197 sys.excepthook = sys.__excepthook__
197 sys.excepthook = sys.__excepthook__
198 atexit.register(unset_crashhandler)
198 atexit.register(unset_crashhandler)
199
199
200 def excepthook(self, etype, evalue, tb):
200 def excepthook(self, etype, evalue, tb):
201 """this is sys.excepthook after init_crashhandler
201 """this is sys.excepthook after init_crashhandler
202
202
203 set self.verbose_crash=True to use our full crashhandler, instead of
203 set self.verbose_crash=True to use our full crashhandler, instead of
204 a regular traceback with a short message (crash_handler_lite)
204 a regular traceback with a short message (crash_handler_lite)
205 """
205 """
206
206
207 if self.verbose_crash:
207 if self.verbose_crash:
208 return self.crash_handler(etype, evalue, tb)
208 return self.crash_handler(etype, evalue, tb)
209 else:
209 else:
210 return crashhandler.crash_handler_lite(etype, evalue, tb)
210 return crashhandler.crash_handler_lite(etype, evalue, tb)
211
211
212 def _ipython_dir_changed(self, name, old, new):
212 def _ipython_dir_changed(self, name, old, new):
213 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
213 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
214 sys.getfilesystemencoding()
214 sys.getfilesystemencoding()
215 )
215 )
216 if str_old in sys.path:
216 if str_old in sys.path:
217 sys.path.remove(str_old)
217 sys.path.remove(str_old)
218 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
218 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
219 sys.getfilesystemencoding()
219 sys.getfilesystemencoding()
220 )
220 )
221 sys.path.append(str_path)
221 sys.path.append(str_path)
222 ensure_dir_exists(new)
222 ensure_dir_exists(new)
223 readme = os.path.join(new, 'README')
223 readme = os.path.join(new, 'README')
224 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
224 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
225 if not os.path.exists(readme) and os.path.exists(readme_src):
225 if not os.path.exists(readme) and os.path.exists(readme_src):
226 shutil.copy(readme_src, readme)
226 shutil.copy(readme_src, readme)
227 for d in ('extensions', 'nbextensions'):
227 for d in ('extensions', 'nbextensions'):
228 path = os.path.join(new, d)
228 path = os.path.join(new, d)
229 try:
229 try:
230 ensure_dir_exists(path)
230 ensure_dir_exists(path)
231 except OSError:
231 except OSError:
232 # this will not be EEXIST
232 # this will not be EEXIST
233 self.log.error("couldn't create path %s: %s", path, e)
233 self.log.error("couldn't create path %s: %s", path, e)
234 self.log.debug("IPYTHONDIR set to: %s" % new)
234 self.log.debug("IPYTHONDIR set to: %s" % new)
235
235
236 def load_config_file(self, suppress_errors=True):
236 def load_config_file(self, suppress_errors=True):
237 """Load the config file.
237 """Load the config file.
238
238
239 By default, errors in loading config are handled, and a warning
239 By default, errors in loading config are handled, and a warning
240 printed on screen. For testing, the suppress_errors option is set
240 printed on screen. For testing, the suppress_errors option is set
241 to False, so errors will make tests fail.
241 to False, so errors will make tests fail.
242 """
242 """
243 self.log.debug("Searching path %s for config files", self.config_file_paths)
243 self.log.debug("Searching path %s for config files", self.config_file_paths)
244 base_config = 'ipython_config.py'
244 base_config = 'ipython_config.py'
245 self.log.debug("Attempting to load config file: %s" %
245 self.log.debug("Attempting to load config file: %s" %
246 base_config)
246 base_config)
247 try:
247 try:
248 Application.load_config_file(
248 Application.load_config_file(
249 self,
249 self,
250 base_config,
250 base_config,
251 path=self.config_file_paths
251 path=self.config_file_paths
252 )
252 )
253 except ConfigFileNotFound:
253 except ConfigFileNotFound:
254 # ignore errors loading parent
254 # ignore errors loading parent
255 self.log.debug("Config file %s not found", base_config)
255 self.log.debug("Config file %s not found", base_config)
256 pass
256 pass
257
257
258 for config_file_name in self.config_files:
258 for config_file_name in self.config_files:
259 if not config_file_name or config_file_name == base_config:
259 if not config_file_name or config_file_name == base_config:
260 continue
260 continue
261 self.log.debug("Attempting to load config file: %s" %
261 self.log.debug("Attempting to load config file: %s" %
262 self.config_file_name)
262 self.config_file_name)
263 try:
263 try:
264 Application.load_config_file(
264 Application.load_config_file(
265 self,
265 self,
266 config_file_name,
266 config_file_name,
267 path=self.config_file_paths
267 path=self.config_file_paths
268 )
268 )
269 except ConfigFileNotFound:
269 except ConfigFileNotFound:
270 # Only warn if the default config file was NOT being used.
270 # Only warn if the default config file was NOT being used.
271 if config_file_name in self.config_file_specified:
271 if config_file_name in self.config_file_specified:
272 msg = self.log.warn
272 msg = self.log.warn
273 else:
273 else:
274 msg = self.log.debug
274 msg = self.log.debug
275 msg("Config file not found, skipping: %s", config_file_name)
275 msg("Config file not found, skipping: %s", config_file_name)
276 except:
276 except:
277 # For testing purposes.
277 # For testing purposes.
278 if not suppress_errors:
278 if not suppress_errors:
279 raise
279 raise
280 self.log.warn("Error loading config file: %s" %
280 self.log.warn("Error loading config file: %s" %
281 self.config_file_name, exc_info=True)
281 self.config_file_name, exc_info=True)
282
282
283 def init_profile_dir(self):
283 def init_profile_dir(self):
284 """initialize the profile dir"""
284 """initialize the profile dir"""
285 self._in_init_profile_dir = True
285 self._in_init_profile_dir = True
286 if self.profile_dir is not None:
286 if self.profile_dir is not None:
287 # already ran
287 # already ran
288 return
288 return
289 if 'ProfileDir.location' not in self.config:
289 if 'ProfileDir.location' not in self.config:
290 # location not specified, find by profile name
290 # location not specified, find by profile name
291 try:
291 try:
292 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
292 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
293 except ProfileDirError:
293 except ProfileDirError:
294 # not found, maybe create it (always create default profile)
294 # not found, maybe create it (always create default profile)
295 if self.auto_create or self.profile == 'default':
295 if self.auto_create or self.profile == 'default':
296 try:
296 try:
297 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
297 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
298 except ProfileDirError:
298 except ProfileDirError:
299 self.log.fatal("Could not create profile: %r"%self.profile)
299 self.log.fatal("Could not create profile: %r"%self.profile)
300 self.exit(1)
300 self.exit(1)
301 else:
301 else:
302 self.log.info("Created profile dir: %r"%p.location)
302 self.log.info("Created profile dir: %r"%p.location)
303 else:
303 else:
304 self.log.fatal("Profile %r not found."%self.profile)
304 self.log.fatal("Profile %r not found."%self.profile)
305 self.exit(1)
305 self.exit(1)
306 else:
306 else:
307 self.log.info("Using existing profile dir: %r"%p.location)
307 self.log.info("Using existing profile dir: %r"%p.location)
308 else:
308 else:
309 location = self.config.ProfileDir.location
309 location = self.config.ProfileDir.location
310 # location is fully specified
310 # location is fully specified
311 try:
311 try:
312 p = ProfileDir.find_profile_dir(location, self.config)
312 p = ProfileDir.find_profile_dir(location, self.config)
313 except ProfileDirError:
313 except ProfileDirError:
314 # not found, maybe create it
314 # not found, maybe create it
315 if self.auto_create:
315 if self.auto_create:
316 try:
316 try:
317 p = ProfileDir.create_profile_dir(location, self.config)
317 p = ProfileDir.create_profile_dir(location, self.config)
318 except ProfileDirError:
318 except ProfileDirError:
319 self.log.fatal("Could not create profile directory: %r"%location)
319 self.log.fatal("Could not create profile directory: %r"%location)
320 self.exit(1)
320 self.exit(1)
321 else:
321 else:
322 self.log.info("Creating new profile dir: %r"%location)
322 self.log.info("Creating new profile dir: %r"%location)
323 else:
323 else:
324 self.log.fatal("Profile directory %r not found."%location)
324 self.log.fatal("Profile directory %r not found."%location)
325 self.exit(1)
325 self.exit(1)
326 else:
326 else:
327 self.log.info("Using existing profile dir: %r"%location)
327 self.log.info("Using existing profile dir: %r"%location)
328 # if profile_dir is specified explicitly, set profile name
328 # if profile_dir is specified explicitly, set profile name
329 dir_name = os.path.basename(p.location)
329 dir_name = os.path.basename(p.location)
330 if dir_name.startswith('profile_'):
330 if dir_name.startswith('profile_'):
331 self.profile = dir_name[8:]
331 self.profile = dir_name[8:]
332
332
333 self.profile_dir = p
333 self.profile_dir = p
334 self.config_file_paths.append(p.location)
334 self.config_file_paths.append(p.location)
335 self._in_init_profile_dir = False
335 self._in_init_profile_dir = False
336
336
337 def init_config_files(self):
337 def init_config_files(self):
338 """[optionally] copy default config files into profile dir."""
338 """[optionally] copy default config files into profile dir."""
339 # copy config files
339 # copy config files
340 path = self.builtin_profile_dir
340 path = self.builtin_profile_dir
341 if self.copy_config_files:
341 if self.copy_config_files:
342 src = self.profile
342 src = self.profile
343
343
344 cfg = self.config_file_name
344 cfg = self.config_file_name
345 if path and os.path.exists(os.path.join(path, cfg)):
345 if path and os.path.exists(os.path.join(path, cfg)):
346 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
346 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
347 cfg, src, self.profile_dir.location, self.overwrite)
347 cfg, src, self.profile_dir.location, self.overwrite)
348 )
348 )
349 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
349 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
350 else:
350 else:
351 self.stage_default_config_file()
351 self.stage_default_config_file()
352 else:
352 else:
353 # Still stage *bundled* config files, but not generated ones
353 # Still stage *bundled* config files, but not generated ones
354 # This is necessary for `ipython profile=sympy` to load the profile
354 # This is necessary for `ipython profile=sympy` to load the profile
355 # on the first go
355 # on the first go
356 files = glob.glob(os.path.join(path, '*.py'))
356 files = glob.glob(os.path.join(path, '*.py'))
357 for fullpath in files:
357 for fullpath in files:
358 cfg = os.path.basename(fullpath)
358 cfg = os.path.basename(fullpath)
359 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
359 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
360 # file was copied
360 # file was copied
361 self.log.warn("Staging bundled %s from %s into %r"%(
361 self.log.warn("Staging bundled %s from %s into %r"%(
362 cfg, self.profile, self.profile_dir.location)
362 cfg, self.profile, self.profile_dir.location)
363 )
363 )
364
364
365
365
366 def stage_default_config_file(self):
366 def stage_default_config_file(self):
367 """auto generate default config file, and stage it into the profile."""
367 """auto generate default config file, and stage it into the profile."""
368 s = self.generate_config_file()
368 s = self.generate_config_file()
369 fname = os.path.join(self.profile_dir.location, self.config_file_name)
369 fname = os.path.join(self.profile_dir.location, self.config_file_name)
370 if self.overwrite or not os.path.exists(fname):
370 if self.overwrite or not os.path.exists(fname):
371 self.log.warn("Generating default config file: %r"%(fname))
371 self.log.warn("Generating default config file: %r"%(fname))
372 with open(fname, 'w') as f:
372 with open(fname, 'w') as f:
373 f.write(s)
373 f.write(s)
374
374
375 @catch_config_error
375 @catch_config_error
376 def initialize(self, argv=None):
376 def initialize(self, argv=None):
377 # don't hook up crash handler before parsing command-line
377 # don't hook up crash handler before parsing command-line
378 self.parse_command_line(argv)
378 self.parse_command_line(argv)
379 self.init_crash_handler()
379 self.init_crash_handler()
380 if self.subapp is not None:
380 if self.subapp is not None:
381 # stop here if subapp is taking over
381 # stop here if subapp is taking over
382 return
382 return
383 cl_config = self.config
383 cl_config = self.config
384 self.init_profile_dir()
384 self.init_profile_dir()
385 self.init_config_files()
385 self.init_config_files()
386 self.load_config_file()
386 self.load_config_file()
387 # enforce cl-opts override configfile opts:
387 # enforce cl-opts override configfile opts:
388 self.update_config(cl_config)
388 self.update_config(cl_config)
389
389
@@ -1,109 +1,120 b''
1
1
2 # Copyright (c) IPython Development Team.
2 # Copyright (c) IPython Development Team.
3 # Distributed under the terms of the Modified BSD License.
3 # Distributed under the terms of the Modified BSD License.
4
4
5 import errno
5 import errno
6 import os.path
6 import os.path
7
7
8 from IPython.config.application import Application
8 from IPython.config.application import Application
9 from IPython.core.application import BaseIPythonApplication, base_flags
9 from IPython.core.application import (
10 BaseIPythonApplication, base_flags, base_aliases
11 )
10 from IPython.utils.traitlets import Instance, Dict, Unicode, Bool
12 from IPython.utils.traitlets import Instance, Dict, Unicode, Bool
11
13
12 from .kernelspec import KernelSpecManager
14 from .kernelspec import KernelSpecManager
13
15
14 def _pythonfirst(s):
16 def _pythonfirst(s):
15 "Sort key function that will put strings starting with 'python' first."
17 "Sort key function that will put strings starting with 'python' first."
16 if s.startswith('python'):
18 if s.startswith('python'):
17 return ''
19 return ''
18 return s
20 return s
19
21
20 class ListKernelSpecs(BaseIPythonApplication):
22 class ListKernelSpecs(BaseIPythonApplication):
21 description = """List installed kernel specifications."""
23 description = """List installed kernel specifications."""
22 kernel_spec_manager = Instance(KernelSpecManager)
24 kernel_spec_manager = Instance(KernelSpecManager)
25
26 # Not all of the base aliases are meaningful (e.g. profile)
27 aliases = {k: base_aliases[k] for k in ['ipython-dir', 'log-level']}
28 flags = {'debug': base_flags['debug'],}
23
29
24 def _kernel_spec_manager_default(self):
30 def _kernel_spec_manager_default(self):
25 return KernelSpecManager(ipython_dir=self.ipython_dir)
31 return KernelSpecManager(ipython_dir=self.ipython_dir)
26
32
27 def start(self):
33 def start(self):
28 print("Available kernels:")
34 print("Available kernels:")
29 for kernelname in sorted(self.kernel_spec_manager.find_kernel_specs(),
35 for kernelname in sorted(self.kernel_spec_manager.find_kernel_specs(),
30 key=_pythonfirst):
36 key=_pythonfirst):
31 print(" %s" % kernelname)
37 print(" %s" % kernelname)
32
38
33
39
34 class InstallKernelSpec(BaseIPythonApplication):
40 class InstallKernelSpec(BaseIPythonApplication):
35 description = """Install a kernel specification directory."""
41 description = """Install a kernel specification directory."""
36 kernel_spec_manager = Instance(KernelSpecManager)
42 kernel_spec_manager = Instance(KernelSpecManager)
37
43
38 def _kernel_spec_manager_default(self):
44 def _kernel_spec_manager_default(self):
39 return KernelSpecManager(ipython_dir=self.ipython_dir)
45 return KernelSpecManager(ipython_dir=self.ipython_dir)
40
46
41 sourcedir = Unicode()
47 sourcedir = Unicode()
42 kernel_name = Unicode("", config=True,
48 kernel_name = Unicode("", config=True,
43 help="Install the kernel spec with this name"
49 help="Install the kernel spec with this name"
44 )
50 )
45 def _kernel_name_default(self):
51 def _kernel_name_default(self):
46 return os.path.basename(self.sourcedir)
52 return os.path.basename(self.sourcedir)
47
53
48 system = Bool(False, config=True,
54 system = Bool(False, config=True,
49 help="""
55 help="""
50 Try to install the kernel spec to the systemwide directory instead of
56 Try to install the kernel spec to the systemwide directory instead of
51 the per-user directory.
57 the per-user directory.
52 """
58 """
53 )
59 )
54 replace = Bool(False, config=True,
60 replace = Bool(False, config=True,
55 help="Replace any existing kernel spec with this name."
61 help="Replace any existing kernel spec with this name."
56 )
62 )
57
63
58 aliases = {'name': 'InstallKernelSpec.kernel_name'}
64 aliases = {'name': 'InstallKernelSpec.kernel_name'}
65 for k in ['ipython-dir', 'log-level']:
66 aliases[k] = base_aliases[k]
59
67
60 flags = {'system': ({'InstallKernelSpec': {'system': True}},
68 flags = {'system': ({'InstallKernelSpec': {'system': True}},
61 "Install to the systemwide kernel registry"),
69 "Install to the systemwide kernel registry"),
62 'replace': ({'InstallKernelSpec': {'replace': True}},
70 'replace': ({'InstallKernelSpec': {'replace': True}},
63 "Replace any existing kernel spec with this name."),
71 "Replace any existing kernel spec with this name."),
72 'debug': base_flags['debug'],
64 }
73 }
65 flags.update(base_flags)
66
74
67 def parse_command_line(self, argv):
75 def parse_command_line(self, argv):
68 super(InstallKernelSpec, self).parse_command_line(argv)
76 super(InstallKernelSpec, self).parse_command_line(argv)
69 # accept positional arg as profile name
77 # accept positional arg as profile name
70 if self.extra_args:
78 if self.extra_args:
71 self.sourcedir = self.extra_args[0]
79 self.sourcedir = self.extra_args[0]
72 else:
80 else:
73 print("No source directory specified.")
81 print("No source directory specified.")
74 self.exit(1)
82 self.exit(1)
75
83
76 def start(self):
84 def start(self):
77 try:
85 try:
78 self.kernel_spec_manager.install_kernel_spec(self.sourcedir,
86 self.kernel_spec_manager.install_kernel_spec(self.sourcedir,
79 kernel_name=self.kernel_name,
87 kernel_name=self.kernel_name,
80 system=self.system,
88 system=self.system,
81 replace=self.replace,
89 replace=self.replace,
82 )
90 )
83 except OSError as e:
91 except OSError as e:
84 if e.errno == errno.EACCES:
92 if e.errno == errno.EACCES:
85 print("Permission denied")
93 print("Permission denied")
86 self.exit(1)
94 self.exit(1)
87 elif e.errno == errno.EEXIST:
95 elif e.errno == errno.EEXIST:
88 print("A kernel spec named %r is already present" % self.kernel_name)
96 print("A kernel spec named %r is already present" % self.kernel_name)
89 self.exit(1)
97 self.exit(1)
90 raise
98 raise
91
99
92 class KernelSpecApp(Application):
100 class KernelSpecApp(Application):
93 name = "ipython kernelspec"
101 name = "ipython kernelspec"
94 description = """Manage IPython kernel specifications."""
102 description = """Manage IPython kernel specifications."""
95
103
96 subcommands = Dict(dict(
104 subcommands = Dict(dict(
97 list = (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
105 list = (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
98 install = (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0])
106 install = (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0])
99 ))
107 ))
108
109 aliases = {}
110 flags = {}
100
111
101 def start(self):
112 def start(self):
102 if self.subapp is None:
113 if self.subapp is None:
103 print("No subcommand specified. Must specify one of: %s"% list(self.subcommands))
114 print("No subcommand specified. Must specify one of: %s"% list(self.subcommands))
104 print()
115 print()
105 self.print_description()
116 self.print_description()
106 self.print_subcommands()
117 self.print_subcommands()
107 self.exit(1)
118 self.exit(1)
108 else:
119 else:
109 return self.subapp.start()
120 return self.subapp.start()
General Comments 0
You need to be logged in to leave comments. Login now