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