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