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