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