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