##// END OF EJS Templates
quickfix for #9317
Paul Ivanov -
Show More
@@ -1,407 +1,407 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 deprecated_subcommands = {}
198 deprecated_subcommands = {}
199
199
200 def initialize_subcommand(self, subc, argv=None):
200 def initialize_subcommand(self, subc, argv=None):
201 if subc in self.deprecated_subcommands:
201 if subc in self.deprecated_subcommands:
202 import time
202 import time
203 self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed "
203 self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed "
204 "in future versions.".format(sub=subc))
204 "in future versions.".format(sub=subc))
205 self.log.warning("You likely want to use `jupyter {sub}`... in the"
205 self.log.warning("You likely want to use `jupyter {sub}` in the "
206 "future".format(sub=subc))
206 "future".format(sub=subc))
207 return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv)
207 return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv)
208
208
209 def init_crash_handler(self):
209 def init_crash_handler(self):
210 """Create a crash handler, typically setting sys.excepthook to it."""
210 """Create a crash handler, typically setting sys.excepthook to it."""
211 self.crash_handler = self.crash_handler_class(self)
211 self.crash_handler = self.crash_handler_class(self)
212 sys.excepthook = self.excepthook
212 sys.excepthook = self.excepthook
213 def unset_crashhandler():
213 def unset_crashhandler():
214 sys.excepthook = sys.__excepthook__
214 sys.excepthook = sys.__excepthook__
215 atexit.register(unset_crashhandler)
215 atexit.register(unset_crashhandler)
216
216
217 def excepthook(self, etype, evalue, tb):
217 def excepthook(self, etype, evalue, tb):
218 """this is sys.excepthook after init_crashhandler
218 """this is sys.excepthook after init_crashhandler
219
219
220 set self.verbose_crash=True to use our full crashhandler, instead of
220 set self.verbose_crash=True to use our full crashhandler, instead of
221 a regular traceback with a short message (crash_handler_lite)
221 a regular traceback with a short message (crash_handler_lite)
222 """
222 """
223
223
224 if self.verbose_crash:
224 if self.verbose_crash:
225 return self.crash_handler(etype, evalue, tb)
225 return self.crash_handler(etype, evalue, tb)
226 else:
226 else:
227 return crashhandler.crash_handler_lite(etype, evalue, tb)
227 return crashhandler.crash_handler_lite(etype, evalue, tb)
228
228
229 def _ipython_dir_changed(self, name, old, new):
229 def _ipython_dir_changed(self, name, old, new):
230 if old is not Undefined:
230 if old is not Undefined:
231 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
231 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
232 sys.getfilesystemencoding()
232 sys.getfilesystemencoding()
233 )
233 )
234 if str_old in sys.path:
234 if str_old in sys.path:
235 sys.path.remove(str_old)
235 sys.path.remove(str_old)
236 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
236 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
237 sys.getfilesystemencoding()
237 sys.getfilesystemencoding()
238 )
238 )
239 sys.path.append(str_path)
239 sys.path.append(str_path)
240 ensure_dir_exists(new)
240 ensure_dir_exists(new)
241 readme = os.path.join(new, 'README')
241 readme = os.path.join(new, 'README')
242 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
242 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
243 if not os.path.exists(readme) and os.path.exists(readme_src):
243 if not os.path.exists(readme) and os.path.exists(readme_src):
244 shutil.copy(readme_src, readme)
244 shutil.copy(readme_src, readme)
245 for d in ('extensions', 'nbextensions'):
245 for d in ('extensions', 'nbextensions'):
246 path = os.path.join(new, d)
246 path = os.path.join(new, d)
247 try:
247 try:
248 ensure_dir_exists(path)
248 ensure_dir_exists(path)
249 except OSError as e:
249 except OSError as e:
250 # this will not be EEXIST
250 # this will not be EEXIST
251 self.log.error("couldn't create path %s: %s", path, e)
251 self.log.error("couldn't create path %s: %s", path, e)
252 self.log.debug("IPYTHONDIR set to: %s" % new)
252 self.log.debug("IPYTHONDIR set to: %s" % new)
253
253
254 def load_config_file(self, suppress_errors=True):
254 def load_config_file(self, suppress_errors=True):
255 """Load the config file.
255 """Load the config file.
256
256
257 By default, errors in loading config are handled, and a warning
257 By default, errors in loading config are handled, and a warning
258 printed on screen. For testing, the suppress_errors option is set
258 printed on screen. For testing, the suppress_errors option is set
259 to False, so errors will make tests fail.
259 to False, so errors will make tests fail.
260 """
260 """
261 self.log.debug("Searching path %s for config files", self.config_file_paths)
261 self.log.debug("Searching path %s for config files", self.config_file_paths)
262 base_config = 'ipython_config.py'
262 base_config = 'ipython_config.py'
263 self.log.debug("Attempting to load config file: %s" %
263 self.log.debug("Attempting to load config file: %s" %
264 base_config)
264 base_config)
265 try:
265 try:
266 Application.load_config_file(
266 Application.load_config_file(
267 self,
267 self,
268 base_config,
268 base_config,
269 path=self.config_file_paths
269 path=self.config_file_paths
270 )
270 )
271 except ConfigFileNotFound:
271 except ConfigFileNotFound:
272 # ignore errors loading parent
272 # ignore errors loading parent
273 self.log.debug("Config file %s not found", base_config)
273 self.log.debug("Config file %s not found", base_config)
274 pass
274 pass
275
275
276 for config_file_name in self.config_files:
276 for config_file_name in self.config_files:
277 if not config_file_name or config_file_name == base_config:
277 if not config_file_name or config_file_name == base_config:
278 continue
278 continue
279 self.log.debug("Attempting to load config file: %s" %
279 self.log.debug("Attempting to load config file: %s" %
280 self.config_file_name)
280 self.config_file_name)
281 try:
281 try:
282 Application.load_config_file(
282 Application.load_config_file(
283 self,
283 self,
284 config_file_name,
284 config_file_name,
285 path=self.config_file_paths
285 path=self.config_file_paths
286 )
286 )
287 except ConfigFileNotFound:
287 except ConfigFileNotFound:
288 # Only warn if the default config file was NOT being used.
288 # Only warn if the default config file was NOT being used.
289 if config_file_name in self.config_file_specified:
289 if config_file_name in self.config_file_specified:
290 msg = self.log.warning
290 msg = self.log.warning
291 else:
291 else:
292 msg = self.log.debug
292 msg = self.log.debug
293 msg("Config file not found, skipping: %s", config_file_name)
293 msg("Config file not found, skipping: %s", config_file_name)
294 except Exception:
294 except Exception:
295 # For testing purposes.
295 # For testing purposes.
296 if not suppress_errors:
296 if not suppress_errors:
297 raise
297 raise
298 self.log.warning("Error loading config file: %s" %
298 self.log.warning("Error loading config file: %s" %
299 self.config_file_name, exc_info=True)
299 self.config_file_name, exc_info=True)
300
300
301 def init_profile_dir(self):
301 def init_profile_dir(self):
302 """initialize the profile dir"""
302 """initialize the profile dir"""
303 self._in_init_profile_dir = True
303 self._in_init_profile_dir = True
304 if self.profile_dir is not None:
304 if self.profile_dir is not None:
305 # already ran
305 # already ran
306 return
306 return
307 if 'ProfileDir.location' not in self.config:
307 if 'ProfileDir.location' not in self.config:
308 # location not specified, find by profile name
308 # location not specified, find by profile name
309 try:
309 try:
310 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
310 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
311 except ProfileDirError:
311 except ProfileDirError:
312 # not found, maybe create it (always create default profile)
312 # not found, maybe create it (always create default profile)
313 if self.auto_create or self.profile == 'default':
313 if self.auto_create or self.profile == 'default':
314 try:
314 try:
315 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
315 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
316 except ProfileDirError:
316 except ProfileDirError:
317 self.log.fatal("Could not create profile: %r"%self.profile)
317 self.log.fatal("Could not create profile: %r"%self.profile)
318 self.exit(1)
318 self.exit(1)
319 else:
319 else:
320 self.log.info("Created profile dir: %r"%p.location)
320 self.log.info("Created profile dir: %r"%p.location)
321 else:
321 else:
322 self.log.fatal("Profile %r not found."%self.profile)
322 self.log.fatal("Profile %r not found."%self.profile)
323 self.exit(1)
323 self.exit(1)
324 else:
324 else:
325 self.log.debug("Using existing profile dir: %r"%p.location)
325 self.log.debug("Using existing profile dir: %r"%p.location)
326 else:
326 else:
327 location = self.config.ProfileDir.location
327 location = self.config.ProfileDir.location
328 # location is fully specified
328 # location is fully specified
329 try:
329 try:
330 p = ProfileDir.find_profile_dir(location, self.config)
330 p = ProfileDir.find_profile_dir(location, self.config)
331 except ProfileDirError:
331 except ProfileDirError:
332 # not found, maybe create it
332 # not found, maybe create it
333 if self.auto_create:
333 if self.auto_create:
334 try:
334 try:
335 p = ProfileDir.create_profile_dir(location, self.config)
335 p = ProfileDir.create_profile_dir(location, self.config)
336 except ProfileDirError:
336 except ProfileDirError:
337 self.log.fatal("Could not create profile directory: %r"%location)
337 self.log.fatal("Could not create profile directory: %r"%location)
338 self.exit(1)
338 self.exit(1)
339 else:
339 else:
340 self.log.debug("Creating new profile dir: %r"%location)
340 self.log.debug("Creating new profile dir: %r"%location)
341 else:
341 else:
342 self.log.fatal("Profile directory %r not found."%location)
342 self.log.fatal("Profile directory %r not found."%location)
343 self.exit(1)
343 self.exit(1)
344 else:
344 else:
345 self.log.info("Using existing profile dir: %r"%location)
345 self.log.info("Using existing profile dir: %r"%location)
346 # if profile_dir is specified explicitly, set profile name
346 # if profile_dir is specified explicitly, set profile name
347 dir_name = os.path.basename(p.location)
347 dir_name = os.path.basename(p.location)
348 if dir_name.startswith('profile_'):
348 if dir_name.startswith('profile_'):
349 self.profile = dir_name[8:]
349 self.profile = dir_name[8:]
350
350
351 self.profile_dir = p
351 self.profile_dir = p
352 self.config_file_paths.append(p.location)
352 self.config_file_paths.append(p.location)
353 self._in_init_profile_dir = False
353 self._in_init_profile_dir = False
354
354
355 def init_config_files(self):
355 def init_config_files(self):
356 """[optionally] copy default config files into profile dir."""
356 """[optionally] copy default config files into profile dir."""
357 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
357 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
358 # copy config files
358 # copy config files
359 path = self.builtin_profile_dir
359 path = self.builtin_profile_dir
360 if self.copy_config_files:
360 if self.copy_config_files:
361 src = self.profile
361 src = self.profile
362
362
363 cfg = self.config_file_name
363 cfg = self.config_file_name
364 if path and os.path.exists(os.path.join(path, cfg)):
364 if path and os.path.exists(os.path.join(path, cfg)):
365 self.log.warning("Staging %r from %s into %r [overwrite=%s]"%(
365 self.log.warning("Staging %r from %s into %r [overwrite=%s]"%(
366 cfg, src, self.profile_dir.location, self.overwrite)
366 cfg, src, self.profile_dir.location, self.overwrite)
367 )
367 )
368 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
368 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
369 else:
369 else:
370 self.stage_default_config_file()
370 self.stage_default_config_file()
371 else:
371 else:
372 # Still stage *bundled* config files, but not generated ones
372 # Still stage *bundled* config files, but not generated ones
373 # This is necessary for `ipython profile=sympy` to load the profile
373 # This is necessary for `ipython profile=sympy` to load the profile
374 # on the first go
374 # on the first go
375 files = glob.glob(os.path.join(path, '*.py'))
375 files = glob.glob(os.path.join(path, '*.py'))
376 for fullpath in files:
376 for fullpath in files:
377 cfg = os.path.basename(fullpath)
377 cfg = os.path.basename(fullpath)
378 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
378 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
379 # file was copied
379 # file was copied
380 self.log.warning("Staging bundled %s from %s into %r"%(
380 self.log.warning("Staging bundled %s from %s into %r"%(
381 cfg, self.profile, self.profile_dir.location)
381 cfg, self.profile, self.profile_dir.location)
382 )
382 )
383
383
384
384
385 def stage_default_config_file(self):
385 def stage_default_config_file(self):
386 """auto generate default config file, and stage it into the profile."""
386 """auto generate default config file, and stage it into the profile."""
387 s = self.generate_config_file()
387 s = self.generate_config_file()
388 fname = os.path.join(self.profile_dir.location, self.config_file_name)
388 fname = os.path.join(self.profile_dir.location, self.config_file_name)
389 if self.overwrite or not os.path.exists(fname):
389 if self.overwrite or not os.path.exists(fname):
390 self.log.warning("Generating default config file: %r"%(fname))
390 self.log.warning("Generating default config file: %r"%(fname))
391 with open(fname, 'w') as f:
391 with open(fname, 'w') as f:
392 f.write(s)
392 f.write(s)
393
393
394 @catch_config_error
394 @catch_config_error
395 def initialize(self, argv=None):
395 def initialize(self, argv=None):
396 # don't hook up crash handler before parsing command-line
396 # don't hook up crash handler before parsing command-line
397 self.parse_command_line(argv)
397 self.parse_command_line(argv)
398 self.init_crash_handler()
398 self.init_crash_handler()
399 if self.subapp is not None:
399 if self.subapp is not None:
400 # stop here if subapp is taking over
400 # stop here if subapp is taking over
401 return
401 return
402 cl_config = self.config
402 cl_config = self.config
403 self.init_profile_dir()
403 self.init_profile_dir()
404 self.init_config_files()
404 self.init_config_files()
405 self.load_config_file()
405 self.load_config_file()
406 # enforce cl-opts override configfile opts:
406 # enforce cl-opts override configfile opts:
407 self.update_config(cl_config)
407 self.update_config(cl_config)
General Comments 0
You need to be logged in to leave comments. Login now