##// END OF EJS Templates
create [nb]extensions dirs in skeleton IPYTHONDIR
MinRK -
Show More
@@ -1,373 +1,383 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 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 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 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 errno
31 import glob
32 import glob
32 import logging
33 import logging
33 import os
34 import os
34 import shutil
35 import shutil
35 import sys
36 import sys
36
37
37 from IPython.config.application import Application, catch_config_error
38 from IPython.config.application import Application, catch_config_error
38 from IPython.config.loader import ConfigFileNotFound
39 from IPython.config.loader import ConfigFileNotFound
39 from IPython.core import release, crashhandler
40 from IPython.core import release, crashhandler
40 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
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(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 )
138 def _ipython_dir_default(self):
139 d = get_ipython_dir()
140 self._ipython_dir_changed('ipython_dir', '', d)
141 return d
142
137 _in_init_profile_dir = False
143 _in_init_profile_dir = False
138 profile_dir = Instance(ProfileDir)
144 profile_dir = Instance(ProfileDir)
139 def _profile_dir_default(self):
145 def _profile_dir_default(self):
140 # avoid recursion
146 # avoid recursion
141 if self._in_init_profile_dir:
147 if self._in_init_profile_dir:
142 return
148 return
143 # profile_dir requested early, force initialization
149 # profile_dir requested early, force initialization
144 self.init_profile_dir()
150 self.init_profile_dir()
145 return self.profile_dir
151 return self.profile_dir
146
152
147 overwrite = Bool(False, config=True,
153 overwrite = Bool(False, config=True,
148 help="""Whether to overwrite existing config files when copying""")
154 help="""Whether to overwrite existing config files when copying""")
149 auto_create = Bool(False, config=True,
155 auto_create = Bool(False, config=True,
150 help="""Whether to create profile dir if it doesn't exist""")
156 help="""Whether to create profile dir if it doesn't exist""")
151
157
152 config_files = List(Unicode)
158 config_files = List(Unicode)
153 def _config_files_default(self):
159 def _config_files_default(self):
154 return [self.config_file_name]
160 return [self.config_file_name]
155
161
156 copy_config_files = Bool(False, config=True,
162 copy_config_files = Bool(False, config=True,
157 help="""Whether to install the default config files into the profile dir.
163 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
164 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,
165 profile, then they will be staged into the new directory. Otherwise,
160 default config files will be automatically generated.
166 default config files will be automatically generated.
161 """)
167 """)
162
168
163 verbose_crash = Bool(False, config=True,
169 verbose_crash = Bool(False, config=True,
164 help="""Create a massive crash report when IPython encounters what may be an
170 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
171 internal error. The default is to append a short message to the
166 usual traceback""")
172 usual traceback""")
167
173
168 # The class to use as the crash handler.
174 # The class to use as the crash handler.
169 crash_handler_class = Type(crashhandler.CrashHandler)
175 crash_handler_class = Type(crashhandler.CrashHandler)
170
176
171 @catch_config_error
177 @catch_config_error
172 def __init__(self, **kwargs):
178 def __init__(self, **kwargs):
173 super(BaseIPythonApplication, self).__init__(**kwargs)
179 super(BaseIPythonApplication, self).__init__(**kwargs)
174 # ensure current working directory exists
180 # ensure current working directory exists
175 try:
181 try:
176 directory = os.getcwdu()
182 directory = os.getcwdu()
177 except:
183 except:
178 # raise exception
184 # raise exception
179 self.log.error("Current working directory doesn't exist.")
185 self.log.error("Current working directory doesn't exist.")
180 raise
186 raise
181
187
182 # ensure even default IPYTHONDIR exists
183 if not os.path.exists(self.ipython_dir):
184 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
185
186 #-------------------------------------------------------------------------
188 #-------------------------------------------------------------------------
187 # Various stages of Application creation
189 # Various stages of Application creation
188 #-------------------------------------------------------------------------
190 #-------------------------------------------------------------------------
189
191
190 def init_crash_handler(self):
192 def init_crash_handler(self):
191 """Create a crash handler, typically setting sys.excepthook to it."""
193 """Create a crash handler, typically setting sys.excepthook to it."""
192 self.crash_handler = self.crash_handler_class(self)
194 self.crash_handler = self.crash_handler_class(self)
193 sys.excepthook = self.excepthook
195 sys.excepthook = self.excepthook
194 def unset_crashhandler():
196 def unset_crashhandler():
195 sys.excepthook = sys.__excepthook__
197 sys.excepthook = sys.__excepthook__
196 atexit.register(unset_crashhandler)
198 atexit.register(unset_crashhandler)
197
199
198 def excepthook(self, etype, evalue, tb):
200 def excepthook(self, etype, evalue, tb):
199 """this is sys.excepthook after init_crashhandler
201 """this is sys.excepthook after init_crashhandler
200
202
201 set self.verbose_crash=True to use our full crashhandler, instead of
203 set self.verbose_crash=True to use our full crashhandler, instead of
202 a regular traceback with a short message (crash_handler_lite)
204 a regular traceback with a short message (crash_handler_lite)
203 """
205 """
204
206
205 if self.verbose_crash:
207 if self.verbose_crash:
206 return self.crash_handler(etype, evalue, tb)
208 return self.crash_handler(etype, evalue, tb)
207 else:
209 else:
208 return crashhandler.crash_handler_lite(etype, evalue, tb)
210 return crashhandler.crash_handler_lite(etype, evalue, tb)
209
211
210 def _ipython_dir_changed(self, name, old, new):
212 def _ipython_dir_changed(self, name, old, new):
211 if old in sys.path:
213 if old in sys.path:
212 sys.path.remove(old)
214 sys.path.remove(old)
213 sys.path.append(os.path.abspath(new))
215 sys.path.append(os.path.abspath(new))
214 if not os.path.isdir(new):
216 if not os.path.isdir(new):
215 os.makedirs(new, mode=0o777)
217 os.makedirs(new, mode=0o777)
216 readme = os.path.join(new, 'README')
218 readme = os.path.join(new, 'README')
217 if not os.path.exists(readme):
219 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
218 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
220 if not os.path.exists(readme) and os.path.exists(readme_src):
219 shutil.copy(os.path.join(path, 'README'), readme)
221 shutil.copy(readme_src, readme)
222 for d in ('extensions', 'nbextensions'):
223 path = os.path.join(new, d)
224 if not os.path.exists(path):
225 try:
226 os.mkdir(path)
227 except OSError as e:
228 if e.errno != errno.EEXIST:
229 self.log.error("couldn't create path %s: %s", path, e)
220 self.log.debug("IPYTHONDIR set to: %s" % new)
230 self.log.debug("IPYTHONDIR set to: %s" % new)
221
231
222 def load_config_file(self, suppress_errors=True):
232 def load_config_file(self, suppress_errors=True):
223 """Load the config file.
233 """Load the config file.
224
234
225 By default, errors in loading config are handled, and a warning
235 By default, errors in loading config are handled, and a warning
226 printed on screen. For testing, the suppress_errors option is set
236 printed on screen. For testing, the suppress_errors option is set
227 to False, so errors will make tests fail.
237 to False, so errors will make tests fail.
228 """
238 """
229 self.log.debug("Searching path %s for config files", self.config_file_paths)
239 self.log.debug("Searching path %s for config files", self.config_file_paths)
230 base_config = 'ipython_config.py'
240 base_config = 'ipython_config.py'
231 self.log.debug("Attempting to load config file: %s" %
241 self.log.debug("Attempting to load config file: %s" %
232 base_config)
242 base_config)
233 try:
243 try:
234 Application.load_config_file(
244 Application.load_config_file(
235 self,
245 self,
236 base_config,
246 base_config,
237 path=self.config_file_paths
247 path=self.config_file_paths
238 )
248 )
239 except ConfigFileNotFound:
249 except ConfigFileNotFound:
240 # ignore errors loading parent
250 # ignore errors loading parent
241 self.log.debug("Config file %s not found", base_config)
251 self.log.debug("Config file %s not found", base_config)
242 pass
252 pass
243
253
244 for config_file_name in self.config_files:
254 for config_file_name in self.config_files:
245 if not config_file_name or config_file_name == base_config:
255 if not config_file_name or config_file_name == base_config:
246 continue
256 continue
247 self.log.debug("Attempting to load config file: %s" %
257 self.log.debug("Attempting to load config file: %s" %
248 self.config_file_name)
258 self.config_file_name)
249 try:
259 try:
250 Application.load_config_file(
260 Application.load_config_file(
251 self,
261 self,
252 config_file_name,
262 config_file_name,
253 path=self.config_file_paths
263 path=self.config_file_paths
254 )
264 )
255 except ConfigFileNotFound:
265 except ConfigFileNotFound:
256 # Only warn if the default config file was NOT being used.
266 # Only warn if the default config file was NOT being used.
257 if config_file_name in self.config_file_specified:
267 if config_file_name in self.config_file_specified:
258 msg = self.log.warn
268 msg = self.log.warn
259 else:
269 else:
260 msg = self.log.debug
270 msg = self.log.debug
261 msg("Config file not found, skipping: %s", config_file_name)
271 msg("Config file not found, skipping: %s", config_file_name)
262 except:
272 except:
263 # For testing purposes.
273 # For testing purposes.
264 if not suppress_errors:
274 if not suppress_errors:
265 raise
275 raise
266 self.log.warn("Error loading config file: %s" %
276 self.log.warn("Error loading config file: %s" %
267 self.config_file_name, exc_info=True)
277 self.config_file_name, exc_info=True)
268
278
269 def init_profile_dir(self):
279 def init_profile_dir(self):
270 """initialize the profile dir"""
280 """initialize the profile dir"""
271 self._in_init_profile_dir = True
281 self._in_init_profile_dir = True
272 if self.profile_dir is not None:
282 if self.profile_dir is not None:
273 # already ran
283 # already ran
274 return
284 return
275 try:
285 try:
276 # location explicitly specified:
286 # location explicitly specified:
277 location = self.config.ProfileDir.location
287 location = self.config.ProfileDir.location
278 except AttributeError:
288 except AttributeError:
279 # location not specified, find by profile name
289 # location not specified, find by profile name
280 try:
290 try:
281 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
291 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
282 except ProfileDirError:
292 except ProfileDirError:
283 # not found, maybe create it (always create default profile)
293 # not found, maybe create it (always create default profile)
284 if self.auto_create or self.profile == 'default':
294 if self.auto_create or self.profile == 'default':
285 try:
295 try:
286 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
296 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
287 except ProfileDirError:
297 except ProfileDirError:
288 self.log.fatal("Could not create profile: %r"%self.profile)
298 self.log.fatal("Could not create profile: %r"%self.profile)
289 self.exit(1)
299 self.exit(1)
290 else:
300 else:
291 self.log.info("Created profile dir: %r"%p.location)
301 self.log.info("Created profile dir: %r"%p.location)
292 else:
302 else:
293 self.log.fatal("Profile %r not found."%self.profile)
303 self.log.fatal("Profile %r not found."%self.profile)
294 self.exit(1)
304 self.exit(1)
295 else:
305 else:
296 self.log.info("Using existing profile dir: %r"%p.location)
306 self.log.info("Using existing profile dir: %r"%p.location)
297 else:
307 else:
298 # location is fully specified
308 # location is fully specified
299 try:
309 try:
300 p = ProfileDir.find_profile_dir(location, self.config)
310 p = ProfileDir.find_profile_dir(location, self.config)
301 except ProfileDirError:
311 except ProfileDirError:
302 # not found, maybe create it
312 # not found, maybe create it
303 if self.auto_create:
313 if self.auto_create:
304 try:
314 try:
305 p = ProfileDir.create_profile_dir(location, self.config)
315 p = ProfileDir.create_profile_dir(location, self.config)
306 except ProfileDirError:
316 except ProfileDirError:
307 self.log.fatal("Could not create profile directory: %r"%location)
317 self.log.fatal("Could not create profile directory: %r"%location)
308 self.exit(1)
318 self.exit(1)
309 else:
319 else:
310 self.log.info("Creating new profile dir: %r"%location)
320 self.log.info("Creating new profile dir: %r"%location)
311 else:
321 else:
312 self.log.fatal("Profile directory %r not found."%location)
322 self.log.fatal("Profile directory %r not found."%location)
313 self.exit(1)
323 self.exit(1)
314 else:
324 else:
315 self.log.info("Using existing profile dir: %r"%location)
325 self.log.info("Using existing profile dir: %r"%location)
316
326
317 self.profile_dir = p
327 self.profile_dir = p
318 self.config_file_paths.append(p.location)
328 self.config_file_paths.append(p.location)
319 self._in_init_profile_dir = False
329 self._in_init_profile_dir = False
320
330
321 def init_config_files(self):
331 def init_config_files(self):
322 """[optionally] copy default config files into profile dir."""
332 """[optionally] copy default config files into profile dir."""
323 # copy config files
333 # copy config files
324 path = self.builtin_profile_dir
334 path = self.builtin_profile_dir
325 if self.copy_config_files:
335 if self.copy_config_files:
326 src = self.profile
336 src = self.profile
327
337
328 cfg = self.config_file_name
338 cfg = self.config_file_name
329 if path and os.path.exists(os.path.join(path, cfg)):
339 if path and os.path.exists(os.path.join(path, cfg)):
330 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
340 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
331 cfg, src, self.profile_dir.location, self.overwrite)
341 cfg, src, self.profile_dir.location, self.overwrite)
332 )
342 )
333 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
343 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
334 else:
344 else:
335 self.stage_default_config_file()
345 self.stage_default_config_file()
336 else:
346 else:
337 # Still stage *bundled* config files, but not generated ones
347 # Still stage *bundled* config files, but not generated ones
338 # This is necessary for `ipython profile=sympy` to load the profile
348 # This is necessary for `ipython profile=sympy` to load the profile
339 # on the first go
349 # on the first go
340 files = glob.glob(os.path.join(path, '*.py'))
350 files = glob.glob(os.path.join(path, '*.py'))
341 for fullpath in files:
351 for fullpath in files:
342 cfg = os.path.basename(fullpath)
352 cfg = os.path.basename(fullpath)
343 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
353 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
344 # file was copied
354 # file was copied
345 self.log.warn("Staging bundled %s from %s into %r"%(
355 self.log.warn("Staging bundled %s from %s into %r"%(
346 cfg, self.profile, self.profile_dir.location)
356 cfg, self.profile, self.profile_dir.location)
347 )
357 )
348
358
349
359
350 def stage_default_config_file(self):
360 def stage_default_config_file(self):
351 """auto generate default config file, and stage it into the profile."""
361 """auto generate default config file, and stage it into the profile."""
352 s = self.generate_config_file()
362 s = self.generate_config_file()
353 fname = os.path.join(self.profile_dir.location, self.config_file_name)
363 fname = os.path.join(self.profile_dir.location, self.config_file_name)
354 if self.overwrite or not os.path.exists(fname):
364 if self.overwrite or not os.path.exists(fname):
355 self.log.warn("Generating default config file: %r"%(fname))
365 self.log.warn("Generating default config file: %r"%(fname))
356 with open(fname, 'w') as f:
366 with open(fname, 'w') as f:
357 f.write(s)
367 f.write(s)
358
368
359 @catch_config_error
369 @catch_config_error
360 def initialize(self, argv=None):
370 def initialize(self, argv=None):
361 # don't hook up crash handler before parsing command-line
371 # don't hook up crash handler before parsing command-line
362 self.parse_command_line(argv)
372 self.parse_command_line(argv)
363 self.init_crash_handler()
373 self.init_crash_handler()
364 if self.subapp is not None:
374 if self.subapp is not None:
365 # stop here if subapp is taking over
375 # stop here if subapp is taking over
366 return
376 return
367 cl_config = self.config
377 cl_config = self.config
368 self.init_profile_dir()
378 self.init_profile_dir()
369 self.init_config_files()
379 self.init_config_files()
370 self.load_config_file()
380 self.load_config_file()
371 # enforce cl-opts override configfile opts:
381 # enforce cl-opts override configfile opts:
372 self.update_config(cl_config)
382 self.update_config(cl_config)
373
383
General Comments 0
You need to be logged in to leave comments. Login now