##// END OF EJS Templates
Add missing import of py3compat
Thomas Kluyver -
Show More
@@ -1,379 +1,380 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 componenets.
6 handling configuration and creating componenets.
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 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15 * Min RK
15 * Min RK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008-2011 The IPython Development Team
20 # Copyright (C) 2008-2011 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 import atexit
30 import atexit
31 import glob
31 import glob
32 import logging
32 import logging
33 import os
33 import os
34 import shutil
34 import shutil
35 import sys
35 import sys
36
36
37 from IPython.config.application import Application, catch_config_error
37 from IPython.config.application import Application, catch_config_error
38 from IPython.config.loader import ConfigFileNotFound
38 from IPython.config.loader import ConfigFileNotFound
39 from IPython.core import release, crashhandler
39 from IPython.core import release, crashhandler
40 from IPython.core.profiledir import ProfileDir, ProfileDirError
40 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 from IPython.utils import py3compat
41 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
42 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
43
44
44 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
45 # Classes and functions
46 # Classes and functions
46 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
47
48
48
49
49 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
50 # Base Application Class
51 # Base Application Class
51 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
52
53
53 # aliases and flags
54 # aliases and flags
54
55
55 base_aliases = {
56 base_aliases = {
56 'profile-dir' : 'ProfileDir.location',
57 'profile-dir' : 'ProfileDir.location',
57 'profile' : 'BaseIPythonApplication.profile',
58 'profile' : 'BaseIPythonApplication.profile',
58 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
59 'log-level' : 'Application.log_level',
60 'log-level' : 'Application.log_level',
60 'config' : 'BaseIPythonApplication.extra_config_file',
61 'config' : 'BaseIPythonApplication.extra_config_file',
61 }
62 }
62
63
63 base_flags = dict(
64 base_flags = dict(
64 debug = ({'Application' : {'log_level' : logging.DEBUG}},
65 debug = ({'Application' : {'log_level' : logging.DEBUG}},
65 "set log level to logging.DEBUG (maximize logging output)"),
66 "set log level to logging.DEBUG (maximize logging output)"),
66 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
67 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
67 "set log level to logging.CRITICAL (minimize logging output)"),
68 "set log level to logging.CRITICAL (minimize logging output)"),
68 init = ({'BaseIPythonApplication' : {
69 init = ({'BaseIPythonApplication' : {
69 'copy_config_files' : True,
70 'copy_config_files' : True,
70 'auto_create' : True}
71 'auto_create' : True}
71 }, """Initialize profile with default config files. This is equivalent
72 }, """Initialize profile with default config files. This is equivalent
72 to running `ipython profile create <profile>` prior to startup.
73 to running `ipython profile create <profile>` prior to startup.
73 """)
74 """)
74 )
75 )
75
76
76
77
77 class BaseIPythonApplication(Application):
78 class BaseIPythonApplication(Application):
78
79
79 name = Unicode(u'ipython')
80 name = Unicode(u'ipython')
80 description = Unicode(u'IPython: an enhanced interactive Python shell.')
81 description = Unicode(u'IPython: an enhanced interactive Python shell.')
81 version = Unicode(release.version)
82 version = Unicode(release.version)
82
83
83 aliases = Dict(base_aliases)
84 aliases = Dict(base_aliases)
84 flags = Dict(base_flags)
85 flags = Dict(base_flags)
85 classes = List([ProfileDir])
86 classes = List([ProfileDir])
86
87
87 # Track whether the config_file has changed,
88 # Track whether the config_file has changed,
88 # because some logic happens only if we aren't using the default.
89 # because some logic happens only if we aren't using the default.
89 config_file_specified = Set()
90 config_file_specified = Set()
90
91
91 config_file_name = Unicode()
92 config_file_name = Unicode()
92 def _config_file_name_default(self):
93 def _config_file_name_default(self):
93 return self.name.replace('-','_') + u'_config.py'
94 return self.name.replace('-','_') + u'_config.py'
94 def _config_file_name_changed(self, name, old, new):
95 def _config_file_name_changed(self, name, old, new):
95 if new != old:
96 if new != old:
96 self.config_file_specified.add(new)
97 self.config_file_specified.add(new)
97
98
98 # The directory that contains IPython's builtin profiles.
99 # The directory that contains IPython's builtin profiles.
99 builtin_profile_dir = Unicode(
100 builtin_profile_dir = Unicode(
100 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
101 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
101 )
102 )
102
103
103 config_file_paths = List(Unicode)
104 config_file_paths = List(Unicode)
104 def _config_file_paths_default(self):
105 def _config_file_paths_default(self):
105 return [os.getcwdu()]
106 return [os.getcwdu()]
106
107
107 extra_config_file = Unicode(config=True,
108 extra_config_file = Unicode(config=True,
108 help="""Path to an extra config file to load.
109 help="""Path to an extra config file to load.
109
110
110 If specified, load this config file in addition to any other IPython config.
111 If specified, load this config file in addition to any other IPython config.
111 """)
112 """)
112 def _extra_config_file_changed(self, name, old, new):
113 def _extra_config_file_changed(self, name, old, new):
113 try:
114 try:
114 self.config_files.remove(old)
115 self.config_files.remove(old)
115 except ValueError:
116 except ValueError:
116 pass
117 pass
117 self.config_file_specified.add(new)
118 self.config_file_specified.add(new)
118 self.config_files.append(new)
119 self.config_files.append(new)
119
120
120 profile = Unicode(u'default', config=True,
121 profile = Unicode(u'default', config=True,
121 help="""The IPython profile to use."""
122 help="""The IPython profile to use."""
122 )
123 )
123
124
124 def _profile_changed(self, name, old, new):
125 def _profile_changed(self, name, old, new):
125 self.builtin_profile_dir = os.path.join(
126 self.builtin_profile_dir = os.path.join(
126 get_ipython_package_dir(), u'config', u'profile', new
127 get_ipython_package_dir(), u'config', u'profile', new
127 )
128 )
128
129
129 ipython_dir = Unicode(get_ipython_dir(), config=True,
130 ipython_dir = Unicode(get_ipython_dir(), config=True,
130 help="""
131 help="""
131 The name of the IPython directory. This directory is used for logging
132 The name of the IPython directory. This directory is used for logging
132 configuration (through profiles), history storage, etc. The default
133 configuration (through profiles), history storage, etc. The default
133 is usually $HOME/.ipython. This options can also be specified through
134 is usually $HOME/.ipython. This options can also be specified through
134 the environment variable IPYTHONDIR.
135 the environment variable IPYTHONDIR.
135 """
136 """
136 )
137 )
137 _in_init_profile_dir = False
138 _in_init_profile_dir = False
138 profile_dir = Instance(ProfileDir)
139 profile_dir = Instance(ProfileDir)
139 def _profile_dir_default(self):
140 def _profile_dir_default(self):
140 # avoid recursion
141 # avoid recursion
141 if self._in_init_profile_dir:
142 if self._in_init_profile_dir:
142 return
143 return
143 # profile_dir requested early, force initialization
144 # profile_dir requested early, force initialization
144 self.init_profile_dir()
145 self.init_profile_dir()
145 return self.profile_dir
146 return self.profile_dir
146
147
147 overwrite = Bool(False, config=True,
148 overwrite = Bool(False, config=True,
148 help="""Whether to overwrite existing config files when copying""")
149 help="""Whether to overwrite existing config files when copying""")
149 auto_create = Bool(False, config=True,
150 auto_create = Bool(False, config=True,
150 help="""Whether to create profile dir if it doesn't exist""")
151 help="""Whether to create profile dir if it doesn't exist""")
151
152
152 config_files = List(Unicode)
153 config_files = List(Unicode)
153 def _config_files_default(self):
154 def _config_files_default(self):
154 return [self.config_file_name]
155 return [self.config_file_name]
155
156
156 copy_config_files = Bool(False, config=True,
157 copy_config_files = Bool(False, config=True,
157 help="""Whether to install the default config files into the profile dir.
158 help="""Whether to install the default config files into the profile dir.
158 If a new profile is being created, and IPython contains config files for that
159 If a new profile is being created, and IPython contains config files for that
159 profile, then they will be staged into the new directory. Otherwise,
160 profile, then they will be staged into the new directory. Otherwise,
160 default config files will be automatically generated.
161 default config files will be automatically generated.
161 """)
162 """)
162
163
163 verbose_crash = Bool(False, config=True,
164 verbose_crash = Bool(False, config=True,
164 help="""Create a massive crash report when IPython encounters what may be an
165 help="""Create a massive crash report when IPython encounters what may be an
165 internal error. The default is to append a short message to the
166 internal error. The default is to append a short message to the
166 usual traceback""")
167 usual traceback""")
167
168
168 # The class to use as the crash handler.
169 # The class to use as the crash handler.
169 crash_handler_class = Type(crashhandler.CrashHandler)
170 crash_handler_class = Type(crashhandler.CrashHandler)
170
171
171 @catch_config_error
172 @catch_config_error
172 def __init__(self, **kwargs):
173 def __init__(self, **kwargs):
173 super(BaseIPythonApplication, self).__init__(**kwargs)
174 super(BaseIPythonApplication, self).__init__(**kwargs)
174 # ensure current working directory exists
175 # ensure current working directory exists
175 try:
176 try:
176 directory = os.getcwdu()
177 directory = os.getcwdu()
177 except:
178 except:
178 # raise exception
179 # raise exception
179 self.log.error("Current working directory doesn't exist.")
180 self.log.error("Current working directory doesn't exist.")
180 raise
181 raise
181
182
182 # ensure even default IPYTHONDIR exists
183 # ensure even default IPYTHONDIR exists
183 if not os.path.exists(self.ipython_dir):
184 if not os.path.exists(self.ipython_dir):
184 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
185 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
185
186
186 #-------------------------------------------------------------------------
187 #-------------------------------------------------------------------------
187 # Various stages of Application creation
188 # Various stages of Application creation
188 #-------------------------------------------------------------------------
189 #-------------------------------------------------------------------------
189
190
190 def init_crash_handler(self):
191 def init_crash_handler(self):
191 """Create a crash handler, typically setting sys.excepthook to it."""
192 """Create a crash handler, typically setting sys.excepthook to it."""
192 self.crash_handler = self.crash_handler_class(self)
193 self.crash_handler = self.crash_handler_class(self)
193 sys.excepthook = self.excepthook
194 sys.excepthook = self.excepthook
194 def unset_crashhandler():
195 def unset_crashhandler():
195 sys.excepthook = sys.__excepthook__
196 sys.excepthook = sys.__excepthook__
196 atexit.register(unset_crashhandler)
197 atexit.register(unset_crashhandler)
197
198
198 def excepthook(self, etype, evalue, tb):
199 def excepthook(self, etype, evalue, tb):
199 """this is sys.excepthook after init_crashhandler
200 """this is sys.excepthook after init_crashhandler
200
201
201 set self.verbose_crash=True to use our full crashhandler, instead of
202 set self.verbose_crash=True to use our full crashhandler, instead of
202 a regular traceback with a short message (crash_handler_lite)
203 a regular traceback with a short message (crash_handler_lite)
203 """
204 """
204
205
205 if self.verbose_crash:
206 if self.verbose_crash:
206 return self.crash_handler(etype, evalue, tb)
207 return self.crash_handler(etype, evalue, tb)
207 else:
208 else:
208 return crashhandler.crash_handler_lite(etype, evalue, tb)
209 return crashhandler.crash_handler_lite(etype, evalue, tb)
209
210
210 def _ipython_dir_changed(self, name, old, new):
211 def _ipython_dir_changed(self, name, old, new):
211 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
212 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
212 sys.getfilesystemencoding()
213 sys.getfilesystemencoding()
213 )
214 )
214 if str_old in sys.path:
215 if str_old in sys.path:
215 sys.path.remove(str_old)
216 sys.path.remove(str_old)
216 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
217 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
217 sys.getfilesystemencoding()
218 sys.getfilesystemencoding()
218 )
219 )
219 sys.path.append(str_path)
220 sys.path.append(str_path)
220 if not os.path.isdir(new):
221 if not os.path.isdir(new):
221 os.makedirs(new, mode=0o777)
222 os.makedirs(new, mode=0o777)
222 readme = os.path.join(new, 'README')
223 readme = os.path.join(new, 'README')
223 if not os.path.exists(readme):
224 if not os.path.exists(readme):
224 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
225 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
225 shutil.copy(os.path.join(path, 'README'), readme)
226 shutil.copy(os.path.join(path, 'README'), readme)
226 self.log.debug("IPYTHONDIR set to: %s" % new)
227 self.log.debug("IPYTHONDIR set to: %s" % new)
227
228
228 def load_config_file(self, suppress_errors=True):
229 def load_config_file(self, suppress_errors=True):
229 """Load the config file.
230 """Load the config file.
230
231
231 By default, errors in loading config are handled, and a warning
232 By default, errors in loading config are handled, and a warning
232 printed on screen. For testing, the suppress_errors option is set
233 printed on screen. For testing, the suppress_errors option is set
233 to False, so errors will make tests fail.
234 to False, so errors will make tests fail.
234 """
235 """
235 self.log.debug("Searching path %s for config files", self.config_file_paths)
236 self.log.debug("Searching path %s for config files", self.config_file_paths)
236 base_config = 'ipython_config.py'
237 base_config = 'ipython_config.py'
237 self.log.debug("Attempting to load config file: %s" %
238 self.log.debug("Attempting to load config file: %s" %
238 base_config)
239 base_config)
239 try:
240 try:
240 Application.load_config_file(
241 Application.load_config_file(
241 self,
242 self,
242 base_config,
243 base_config,
243 path=self.config_file_paths
244 path=self.config_file_paths
244 )
245 )
245 except ConfigFileNotFound:
246 except ConfigFileNotFound:
246 # ignore errors loading parent
247 # ignore errors loading parent
247 self.log.debug("Config file %s not found", base_config)
248 self.log.debug("Config file %s not found", base_config)
248 pass
249 pass
249
250
250 for config_file_name in self.config_files:
251 for config_file_name in self.config_files:
251 if not config_file_name or config_file_name == base_config:
252 if not config_file_name or config_file_name == base_config:
252 continue
253 continue
253 self.log.debug("Attempting to load config file: %s" %
254 self.log.debug("Attempting to load config file: %s" %
254 self.config_file_name)
255 self.config_file_name)
255 try:
256 try:
256 Application.load_config_file(
257 Application.load_config_file(
257 self,
258 self,
258 config_file_name,
259 config_file_name,
259 path=self.config_file_paths
260 path=self.config_file_paths
260 )
261 )
261 except ConfigFileNotFound:
262 except ConfigFileNotFound:
262 # Only warn if the default config file was NOT being used.
263 # Only warn if the default config file was NOT being used.
263 if config_file_name in self.config_file_specified:
264 if config_file_name in self.config_file_specified:
264 msg = self.log.warn
265 msg = self.log.warn
265 else:
266 else:
266 msg = self.log.debug
267 msg = self.log.debug
267 msg("Config file not found, skipping: %s", config_file_name)
268 msg("Config file not found, skipping: %s", config_file_name)
268 except:
269 except:
269 # For testing purposes.
270 # For testing purposes.
270 if not suppress_errors:
271 if not suppress_errors:
271 raise
272 raise
272 self.log.warn("Error loading config file: %s" %
273 self.log.warn("Error loading config file: %s" %
273 self.config_file_name, exc_info=True)
274 self.config_file_name, exc_info=True)
274
275
275 def init_profile_dir(self):
276 def init_profile_dir(self):
276 """initialize the profile dir"""
277 """initialize the profile dir"""
277 self._in_init_profile_dir = True
278 self._in_init_profile_dir = True
278 if self.profile_dir is not None:
279 if self.profile_dir is not None:
279 # already ran
280 # already ran
280 return
281 return
281 try:
282 try:
282 # location explicitly specified:
283 # location explicitly specified:
283 location = self.config.ProfileDir.location
284 location = self.config.ProfileDir.location
284 except AttributeError:
285 except AttributeError:
285 # location not specified, find by profile name
286 # location not specified, find by profile name
286 try:
287 try:
287 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
288 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
288 except ProfileDirError:
289 except ProfileDirError:
289 # not found, maybe create it (always create default profile)
290 # not found, maybe create it (always create default profile)
290 if self.auto_create or self.profile == 'default':
291 if self.auto_create or self.profile == 'default':
291 try:
292 try:
292 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
293 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
293 except ProfileDirError:
294 except ProfileDirError:
294 self.log.fatal("Could not create profile: %r"%self.profile)
295 self.log.fatal("Could not create profile: %r"%self.profile)
295 self.exit(1)
296 self.exit(1)
296 else:
297 else:
297 self.log.info("Created profile dir: %r"%p.location)
298 self.log.info("Created profile dir: %r"%p.location)
298 else:
299 else:
299 self.log.fatal("Profile %r not found."%self.profile)
300 self.log.fatal("Profile %r not found."%self.profile)
300 self.exit(1)
301 self.exit(1)
301 else:
302 else:
302 self.log.info("Using existing profile dir: %r"%p.location)
303 self.log.info("Using existing profile dir: %r"%p.location)
303 else:
304 else:
304 # location is fully specified
305 # location is fully specified
305 try:
306 try:
306 p = ProfileDir.find_profile_dir(location, self.config)
307 p = ProfileDir.find_profile_dir(location, self.config)
307 except ProfileDirError:
308 except ProfileDirError:
308 # not found, maybe create it
309 # not found, maybe create it
309 if self.auto_create:
310 if self.auto_create:
310 try:
311 try:
311 p = ProfileDir.create_profile_dir(location, self.config)
312 p = ProfileDir.create_profile_dir(location, self.config)
312 except ProfileDirError:
313 except ProfileDirError:
313 self.log.fatal("Could not create profile directory: %r"%location)
314 self.log.fatal("Could not create profile directory: %r"%location)
314 self.exit(1)
315 self.exit(1)
315 else:
316 else:
316 self.log.info("Creating new profile dir: %r"%location)
317 self.log.info("Creating new profile dir: %r"%location)
317 else:
318 else:
318 self.log.fatal("Profile directory %r not found."%location)
319 self.log.fatal("Profile directory %r not found."%location)
319 self.exit(1)
320 self.exit(1)
320 else:
321 else:
321 self.log.info("Using existing profile dir: %r"%location)
322 self.log.info("Using existing profile dir: %r"%location)
322
323
323 self.profile_dir = p
324 self.profile_dir = p
324 self.config_file_paths.append(p.location)
325 self.config_file_paths.append(p.location)
325 self._in_init_profile_dir = False
326 self._in_init_profile_dir = False
326
327
327 def init_config_files(self):
328 def init_config_files(self):
328 """[optionally] copy default config files into profile dir."""
329 """[optionally] copy default config files into profile dir."""
329 # copy config files
330 # copy config files
330 path = self.builtin_profile_dir
331 path = self.builtin_profile_dir
331 if self.copy_config_files:
332 if self.copy_config_files:
332 src = self.profile
333 src = self.profile
333
334
334 cfg = self.config_file_name
335 cfg = self.config_file_name
335 if path and os.path.exists(os.path.join(path, cfg)):
336 if path and os.path.exists(os.path.join(path, cfg)):
336 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
337 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
337 cfg, src, self.profile_dir.location, self.overwrite)
338 cfg, src, self.profile_dir.location, self.overwrite)
338 )
339 )
339 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
340 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
340 else:
341 else:
341 self.stage_default_config_file()
342 self.stage_default_config_file()
342 else:
343 else:
343 # Still stage *bundled* config files, but not generated ones
344 # Still stage *bundled* config files, but not generated ones
344 # This is necessary for `ipython profile=sympy` to load the profile
345 # This is necessary for `ipython profile=sympy` to load the profile
345 # on the first go
346 # on the first go
346 files = glob.glob(os.path.join(path, '*.py'))
347 files = glob.glob(os.path.join(path, '*.py'))
347 for fullpath in files:
348 for fullpath in files:
348 cfg = os.path.basename(fullpath)
349 cfg = os.path.basename(fullpath)
349 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
350 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
350 # file was copied
351 # file was copied
351 self.log.warn("Staging bundled %s from %s into %r"%(
352 self.log.warn("Staging bundled %s from %s into %r"%(
352 cfg, self.profile, self.profile_dir.location)
353 cfg, self.profile, self.profile_dir.location)
353 )
354 )
354
355
355
356
356 def stage_default_config_file(self):
357 def stage_default_config_file(self):
357 """auto generate default config file, and stage it into the profile."""
358 """auto generate default config file, and stage it into the profile."""
358 s = self.generate_config_file()
359 s = self.generate_config_file()
359 fname = os.path.join(self.profile_dir.location, self.config_file_name)
360 fname = os.path.join(self.profile_dir.location, self.config_file_name)
360 if self.overwrite or not os.path.exists(fname):
361 if self.overwrite or not os.path.exists(fname):
361 self.log.warn("Generating default config file: %r"%(fname))
362 self.log.warn("Generating default config file: %r"%(fname))
362 with open(fname, 'w') as f:
363 with open(fname, 'w') as f:
363 f.write(s)
364 f.write(s)
364
365
365 @catch_config_error
366 @catch_config_error
366 def initialize(self, argv=None):
367 def initialize(self, argv=None):
367 # don't hook up crash handler before parsing command-line
368 # don't hook up crash handler before parsing command-line
368 self.parse_command_line(argv)
369 self.parse_command_line(argv)
369 self.init_crash_handler()
370 self.init_crash_handler()
370 if self.subapp is not None:
371 if self.subapp is not None:
371 # stop here if subapp is taking over
372 # stop here if subapp is taking over
372 return
373 return
373 cl_config = self.config
374 cl_config = self.config
374 self.init_profile_dir()
375 self.init_profile_dir()
375 self.init_config_files()
376 self.init_config_files()
376 self.load_config_file()
377 self.load_config_file()
377 # enforce cl-opts override configfile opts:
378 # enforce cl-opts override configfile opts:
378 self.update_config(cl_config)
379 self.update_config(cl_config)
379
380
General Comments 0
You need to be logged in to leave comments. Login now