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