##// END OF EJS Templates
Remove executable bit, this is a module.
Fernando Perez -
Show More
@@ -1,490 +1,489 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
1 # encoding: utf-8
3 """
2 """
4 An application for IPython.
3 An application for IPython.
5
4
6 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
7 handling configuration and creating componenets.
6 handling configuration and creating componenets.
8
7
9 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
10 object and then create the components, passing the config to them.
9 object and then create the components, passing the config to them.
11
10
12 Authors:
11 Authors:
13
12
14 * Brian Granger
13 * Brian Granger
15 * Fernando Perez
14 * Fernando Perez
16
15
17 Notes
16 Notes
18 -----
17 -----
19 """
18 """
20
19
21 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
22 # Copyright (C) 2008-2009 The IPython Development Team
21 # Copyright (C) 2008-2009 The IPython Development Team
23 #
22 #
24 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
25 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
26 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
27
26
28 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
29 # Imports
28 # Imports
30 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
31
30
32 import logging
31 import logging
33 import os
32 import os
34 import sys
33 import sys
35
34
36 from IPython.core import release, crashhandler
35 from IPython.core import release, crashhandler
37 from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir
36 from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir
38 from IPython.config.loader import (
37 from IPython.config.loader import (
39 PyFileConfigLoader,
38 PyFileConfigLoader,
40 ArgParseConfigLoader,
39 ArgParseConfigLoader,
41 Config,
40 Config,
42 )
41 )
43
42
44 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
45 # Classes and functions
44 # Classes and functions
46 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
47
46
48 class ApplicationError(Exception):
47 class ApplicationError(Exception):
49 pass
48 pass
50
49
51
50
52 app_cl_args = (
51 app_cl_args = (
53 (('--ipython-dir', ), dict(
52 (('--ipython-dir', ), dict(
54 dest='Global.ipython_dir',type=unicode,
53 dest='Global.ipython_dir',type=unicode,
55 help=
54 help=
56 """Set to override default location of the IPython directory
55 """Set to override default location of the IPython directory
57 IPYTHON_DIR, stored as Global.ipython_dir. This can also be specified
56 IPYTHON_DIR, stored as Global.ipython_dir. This can also be specified
58 through the environment variable IPYTHON_DIR.""",
57 through the environment variable IPYTHON_DIR.""",
59 metavar='Global.ipython_dir') ),
58 metavar='Global.ipython_dir') ),
60 (('-p', '--profile',), dict(
59 (('-p', '--profile',), dict(
61 dest='Global.profile',type=unicode,
60 dest='Global.profile',type=unicode,
62 help=
61 help=
63 """The string name of the ipython profile to be used. Assume that your
62 """The string name of the ipython profile to be used. Assume that your
64 config file is ipython_config-<name>.py (looks in current dir first,
63 config file is ipython_config-<name>.py (looks in current dir first,
65 then in IPYTHON_DIR). This is a quick way to keep and load multiple
64 then in IPYTHON_DIR). This is a quick way to keep and load multiple
66 config files for different tasks, especially if include your basic one
65 config files for different tasks, especially if include your basic one
67 in your more specialized ones. You can keep a basic
66 in your more specialized ones. You can keep a basic
68 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
67 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
69 include this one and load extra things for particular tasks.""",
68 include this one and load extra things for particular tasks.""",
70 metavar='Global.profile') ),
69 metavar='Global.profile') ),
71 (('--log-level',), dict(
70 (('--log-level',), dict(
72 dest="Global.log_level",type=int,
71 dest="Global.log_level",type=int,
73 help='Set the log level (0,10,20,30,40,50). Default is 30.',
72 help='Set the log level (0,10,20,30,40,50). Default is 30.',
74 metavar='Global.log_level')),
73 metavar='Global.log_level')),
75 (('--config-file',), dict(
74 (('--config-file',), dict(
76 dest='Global.config_file',type=unicode,
75 dest='Global.config_file',type=unicode,
77 help=
76 help=
78 """Set the config file name to override default. Normally IPython
77 """Set the config file name to override default. Normally IPython
79 loads ipython_config.py (from current directory) or
78 loads ipython_config.py (from current directory) or
80 IPYTHON_DIR/ipython_config.py. If the loading of your config file
79 IPYTHON_DIR/ipython_config.py. If the loading of your config file
81 fails, IPython starts with a bare bones configuration (no modules
80 fails, IPython starts with a bare bones configuration (no modules
82 loaded at all).""",
81 loaded at all).""",
83 metavar='Global.config_file')),
82 metavar='Global.config_file')),
84 )
83 )
85
84
86 class Application(object):
85 class Application(object):
87 """Load a config, construct components and set them running.
86 """Load a config, construct components and set them running.
88
87
89 The configuration of an application can be done via four different Config
88 The configuration of an application can be done via four different Config
90 objects, which are loaded and ultimately merged into a single one used from
89 objects, which are loaded and ultimately merged into a single one used from
91 that point on by the app. These are:
90 that point on by the app. These are:
92
91
93 1. default_config: internal defaults, implemented in code.
92 1. default_config: internal defaults, implemented in code.
94 2. file_config: read from the filesystem.
93 2. file_config: read from the filesystem.
95 3. command_line_config: read from the system's command line flags.
94 3. command_line_config: read from the system's command line flags.
96 4. constructor_config: passed parametrically to the constructor.
95 4. constructor_config: passed parametrically to the constructor.
97
96
98 During initialization, 3 is actually read before 2, since at the
97 During initialization, 3 is actually read before 2, since at the
99 command-line one may override the location of the file to be read. But the
98 command-line one may override the location of the file to be read. But the
100 above is the order in which the merge is made.
99 above is the order in which the merge is made.
101
100
102 There is a final config object can be created and passed to the
101 There is a final config object can be created and passed to the
103 constructor: override_config. If it exists, this completely overrides the
102 constructor: override_config. If it exists, this completely overrides the
104 configs 2-4 above (the default is still used to ensure that all needed
103 configs 2-4 above (the default is still used to ensure that all needed
105 fields at least are created). This makes it easier to create
104 fields at least are created). This makes it easier to create
106 parametrically (e.g. in testing or sphinx plugins) objects with a known
105 parametrically (e.g. in testing or sphinx plugins) objects with a known
107 configuration, that are unaffected by whatever arguments may be present in
106 configuration, that are unaffected by whatever arguments may be present in
108 sys.argv or files in the user's various directories.
107 sys.argv or files in the user's various directories.
109 """
108 """
110
109
111 name = u'ipython'
110 name = u'ipython'
112 description = 'IPython: an enhanced interactive Python shell.'
111 description = 'IPython: an enhanced interactive Python shell.'
113 #: usage message printed by argparse. If None, auto-generate
112 #: usage message printed by argparse. If None, auto-generate
114 usage = None
113 usage = None
115 config_file_name = u'ipython_config.py'
114 config_file_name = u'ipython_config.py'
116 #: Track the default and actual separately because some messages are
115 #: Track the default and actual separately because some messages are
117 #: only printed if we aren't using the default.
116 #: only printed if we aren't using the default.
118 default_config_file_name = config_file_name
117 default_config_file_name = config_file_name
119 default_log_level = logging.WARN
118 default_log_level = logging.WARN
120 #: Set by --profile option
119 #: Set by --profile option
121 profile_name = None
120 profile_name = None
122 #: User's ipython directory, typically ~/.ipython/
121 #: User's ipython directory, typically ~/.ipython/
123 ipython_dir = None
122 ipython_dir = None
124 #: internal defaults, implemented in code.
123 #: internal defaults, implemented in code.
125 default_config = None
124 default_config = None
126 #: read from the filesystem
125 #: read from the filesystem
127 file_config = None
126 file_config = None
128 #: read from the system's command line flags
127 #: read from the system's command line flags
129 command_line_config = None
128 command_line_config = None
130 #: passed parametrically to the constructor.
129 #: passed parametrically to the constructor.
131 constructor_config = None
130 constructor_config = None
132 #: final override, if given supercedes file/command/constructor configs
131 #: final override, if given supercedes file/command/constructor configs
133 override_config = None
132 override_config = None
134 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
133 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
135 argv = None
134 argv = None
136 #: Default command line arguments. Subclasses should create a new tuple
135 #: Default command line arguments. Subclasses should create a new tuple
137 #: that *includes* these.
136 #: that *includes* these.
138 cl_arguments = app_cl_args
137 cl_arguments = app_cl_args
139
138
140 #: extra arguments computed by the command-line loader
139 #: extra arguments computed by the command-line loader
141 extra_args = None
140 extra_args = None
142
141
143 # Private attributes
142 # Private attributes
144 _exiting = False
143 _exiting = False
145 _initialized = False
144 _initialized = False
146
145
147 # Class choices for things that will be instantiated at runtime.
146 # Class choices for things that will be instantiated at runtime.
148 _CrashHandler = crashhandler.CrashHandler
147 _CrashHandler = crashhandler.CrashHandler
149
148
150 def __init__(self, argv=None, constructor_config=None, override_config=None):
149 def __init__(self, argv=None, constructor_config=None, override_config=None):
151 self.argv = sys.argv[1:] if argv is None else argv
150 self.argv = sys.argv[1:] if argv is None else argv
152 self.constructor_config = constructor_config
151 self.constructor_config = constructor_config
153 self.override_config = override_config
152 self.override_config = override_config
154 self.init_logger()
153 self.init_logger()
155
154
156 def init_logger(self):
155 def init_logger(self):
157 self.log = logging.getLogger(self.__class__.__name__)
156 self.log = logging.getLogger(self.__class__.__name__)
158 # This is used as the default until the command line arguments are read.
157 # This is used as the default until the command line arguments are read.
159 self.log.setLevel(self.default_log_level)
158 self.log.setLevel(self.default_log_level)
160 self._log_handler = logging.StreamHandler()
159 self._log_handler = logging.StreamHandler()
161 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
160 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
162 self._log_handler.setFormatter(self._log_formatter)
161 self._log_handler.setFormatter(self._log_formatter)
163 self.log.addHandler(self._log_handler)
162 self.log.addHandler(self._log_handler)
164
163
165 def _set_log_level(self, level):
164 def _set_log_level(self, level):
166 self.log.setLevel(level)
165 self.log.setLevel(level)
167
166
168 def _get_log_level(self):
167 def _get_log_level(self):
169 return self.log.level
168 return self.log.level
170
169
171 log_level = property(_get_log_level, _set_log_level)
170 log_level = property(_get_log_level, _set_log_level)
172
171
173 def initialize(self):
172 def initialize(self):
174 """Initialize the application.
173 """Initialize the application.
175
174
176 Loads all configuration information and sets all application state, but
175 Loads all configuration information and sets all application state, but
177 does not start any relevant processing (typically some kind of event
176 does not start any relevant processing (typically some kind of event
178 loop).
177 loop).
179
178
180 Once this method has been called, the application is flagged as
179 Once this method has been called, the application is flagged as
181 initialized and the method becomes a no-op."""
180 initialized and the method becomes a no-op."""
182
181
183 if self._initialized:
182 if self._initialized:
184 return
183 return
185
184
186 # The first part is protected with an 'attempt' wrapper, that will log
185 # The first part is protected with an 'attempt' wrapper, that will log
187 # failures with the basic system traceback machinery. Once our crash
186 # failures with the basic system traceback machinery. Once our crash
188 # handler is in place, we can let any subsequent exception propagate,
187 # handler is in place, we can let any subsequent exception propagate,
189 # as our handler will log it with much better detail than the default.
188 # as our handler will log it with much better detail than the default.
190 self.attempt(self.create_crash_handler)
189 self.attempt(self.create_crash_handler)
191
190
192 # Configuration phase
191 # Configuration phase
193 # Default config (internally hardwired in application code)
192 # Default config (internally hardwired in application code)
194 self.create_default_config()
193 self.create_default_config()
195 self.log_default_config()
194 self.log_default_config()
196 self.set_default_config_log_level()
195 self.set_default_config_log_level()
197
196
198 if self.override_config is None:
197 if self.override_config is None:
199 # Command-line config
198 # Command-line config
200 self.pre_load_command_line_config()
199 self.pre_load_command_line_config()
201 self.load_command_line_config()
200 self.load_command_line_config()
202 self.set_command_line_config_log_level()
201 self.set_command_line_config_log_level()
203 self.post_load_command_line_config()
202 self.post_load_command_line_config()
204 self.log_command_line_config()
203 self.log_command_line_config()
205
204
206 # Find resources needed for filesystem access, using information from
205 # Find resources needed for filesystem access, using information from
207 # the above two
206 # the above two
208 self.find_ipython_dir()
207 self.find_ipython_dir()
209 self.find_resources()
208 self.find_resources()
210 self.find_config_file_name()
209 self.find_config_file_name()
211 self.find_config_file_paths()
210 self.find_config_file_paths()
212
211
213 if self.override_config is None:
212 if self.override_config is None:
214 # File-based config
213 # File-based config
215 self.pre_load_file_config()
214 self.pre_load_file_config()
216 self.load_file_config()
215 self.load_file_config()
217 self.set_file_config_log_level()
216 self.set_file_config_log_level()
218 self.post_load_file_config()
217 self.post_load_file_config()
219 self.log_file_config()
218 self.log_file_config()
220
219
221 # Merge all config objects into a single one the app can then use
220 # Merge all config objects into a single one the app can then use
222 self.merge_configs()
221 self.merge_configs()
223 self.log_master_config()
222 self.log_master_config()
224
223
225 # Construction phase
224 # Construction phase
226 self.pre_construct()
225 self.pre_construct()
227 self.construct()
226 self.construct()
228 self.post_construct()
227 self.post_construct()
229
228
230 # Done, flag as such and
229 # Done, flag as such and
231 self._initialized = True
230 self._initialized = True
232
231
233 def start(self):
232 def start(self):
234 """Start the application."""
233 """Start the application."""
235 self.initialize()
234 self.initialize()
236 self.start_app()
235 self.start_app()
237
236
238 #-------------------------------------------------------------------------
237 #-------------------------------------------------------------------------
239 # Various stages of Application creation
238 # Various stages of Application creation
240 #-------------------------------------------------------------------------
239 #-------------------------------------------------------------------------
241
240
242 def create_crash_handler(self):
241 def create_crash_handler(self):
243 """Create a crash handler, typically setting sys.excepthook to it."""
242 """Create a crash handler, typically setting sys.excepthook to it."""
244 self.crash_handler = self._CrashHandler(self, self.name)
243 self.crash_handler = self._CrashHandler(self, self.name)
245 sys.excepthook = self.crash_handler
244 sys.excepthook = self.crash_handler
246
245
247 def create_default_config(self):
246 def create_default_config(self):
248 """Create defaults that can't be set elsewhere.
247 """Create defaults that can't be set elsewhere.
249
248
250 For the most part, we try to set default in the class attributes
249 For the most part, we try to set default in the class attributes
251 of Components. But, defaults the top-level Application (which is
250 of Components. But, defaults the top-level Application (which is
252 not a HasTraitlets or Component) are not set in this way. Instead
251 not a HasTraitlets or Component) are not set in this way. Instead
253 we set them here. The Global section is for variables like this that
252 we set them here. The Global section is for variables like this that
254 don't belong to a particular component.
253 don't belong to a particular component.
255 """
254 """
256 c = Config()
255 c = Config()
257 c.Global.ipython_dir = get_ipython_dir()
256 c.Global.ipython_dir = get_ipython_dir()
258 c.Global.log_level = self.log_level
257 c.Global.log_level = self.log_level
259 self.default_config = c
258 self.default_config = c
260
259
261 def log_default_config(self):
260 def log_default_config(self):
262 self.log.debug('Default config loaded:')
261 self.log.debug('Default config loaded:')
263 self.log.debug(repr(self.default_config))
262 self.log.debug(repr(self.default_config))
264
263
265 def set_default_config_log_level(self):
264 def set_default_config_log_level(self):
266 try:
265 try:
267 self.log_level = self.default_config.Global.log_level
266 self.log_level = self.default_config.Global.log_level
268 except AttributeError:
267 except AttributeError:
269 # Fallback to the default_log_level class attribute
268 # Fallback to the default_log_level class attribute
270 pass
269 pass
271
270
272 def create_command_line_config(self):
271 def create_command_line_config(self):
273 """Create and return a command line config loader."""
272 """Create and return a command line config loader."""
274 return ArgParseConfigLoader(self.argv, self.cl_arguments,
273 return ArgParseConfigLoader(self.argv, self.cl_arguments,
275 description=self.description,
274 description=self.description,
276 version=release.version,
275 version=release.version,
277 usage=self.usage,
276 usage=self.usage,
278 )
277 )
279
278
280 def pre_load_command_line_config(self):
279 def pre_load_command_line_config(self):
281 """Do actions just before loading the command line config."""
280 """Do actions just before loading the command line config."""
282 pass
281 pass
283
282
284 def load_command_line_config(self):
283 def load_command_line_config(self):
285 """Load the command line config."""
284 """Load the command line config."""
286 loader = self.create_command_line_config()
285 loader = self.create_command_line_config()
287 self.command_line_config = loader.load_config()
286 self.command_line_config = loader.load_config()
288 self.extra_args = loader.get_extra_args()
287 self.extra_args = loader.get_extra_args()
289
288
290 def set_command_line_config_log_level(self):
289 def set_command_line_config_log_level(self):
291 try:
290 try:
292 self.log_level = self.command_line_config.Global.log_level
291 self.log_level = self.command_line_config.Global.log_level
293 except AttributeError:
292 except AttributeError:
294 pass
293 pass
295
294
296 def post_load_command_line_config(self):
295 def post_load_command_line_config(self):
297 """Do actions just after loading the command line config."""
296 """Do actions just after loading the command line config."""
298 pass
297 pass
299
298
300 def log_command_line_config(self):
299 def log_command_line_config(self):
301 self.log.debug("Command line config loaded:")
300 self.log.debug("Command line config loaded:")
302 self.log.debug(repr(self.command_line_config))
301 self.log.debug(repr(self.command_line_config))
303
302
304 def find_ipython_dir(self):
303 def find_ipython_dir(self):
305 """Set the IPython directory.
304 """Set the IPython directory.
306
305
307 This sets ``self.ipython_dir``, but the actual value that is passed to
306 This sets ``self.ipython_dir``, but the actual value that is passed to
308 the application is kept in either ``self.default_config`` or
307 the application is kept in either ``self.default_config`` or
309 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
308 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
310 ``sys.path`` so config files there can be referenced by other config
309 ``sys.path`` so config files there can be referenced by other config
311 files.
310 files.
312 """
311 """
313
312
314 try:
313 try:
315 self.ipython_dir = self.command_line_config.Global.ipython_dir
314 self.ipython_dir = self.command_line_config.Global.ipython_dir
316 except AttributeError:
315 except AttributeError:
317 self.ipython_dir = self.default_config.Global.ipython_dir
316 self.ipython_dir = self.default_config.Global.ipython_dir
318 sys.path.append(os.path.abspath(self.ipython_dir))
317 sys.path.append(os.path.abspath(self.ipython_dir))
319 if not os.path.isdir(self.ipython_dir):
318 if not os.path.isdir(self.ipython_dir):
320 os.makedirs(self.ipython_dir, mode=0777)
319 os.makedirs(self.ipython_dir, mode=0777)
321 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
320 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
322
321
323 def find_resources(self):
322 def find_resources(self):
324 """Find other resources that need to be in place.
323 """Find other resources that need to be in place.
325
324
326 Things like cluster directories need to be in place to find the
325 Things like cluster directories need to be in place to find the
327 config file. These happen right after the IPython directory has
326 config file. These happen right after the IPython directory has
328 been set.
327 been set.
329 """
328 """
330 pass
329 pass
331
330
332 def find_config_file_name(self):
331 def find_config_file_name(self):
333 """Find the config file name for this application.
332 """Find the config file name for this application.
334
333
335 This must set ``self.config_file_name`` to the filename of the
334 This must set ``self.config_file_name`` to the filename of the
336 config file to use (just the filename). The search paths for the
335 config file to use (just the filename). The search paths for the
337 config file are set in :meth:`find_config_file_paths` and then passed
336 config file are set in :meth:`find_config_file_paths` and then passed
338 to the config file loader where they are resolved to an absolute path.
337 to the config file loader where they are resolved to an absolute path.
339
338
340 If a profile has been set at the command line, this will resolve it.
339 If a profile has been set at the command line, this will resolve it.
341 """
340 """
342
341
343 try:
342 try:
344 self.config_file_name = self.command_line_config.Global.config_file
343 self.config_file_name = self.command_line_config.Global.config_file
345 except AttributeError:
344 except AttributeError:
346 pass
345 pass
347
346
348 try:
347 try:
349 self.profile_name = self.command_line_config.Global.profile
348 self.profile_name = self.command_line_config.Global.profile
350 except AttributeError:
349 except AttributeError:
351 pass
350 pass
352 else:
351 else:
353 name_parts = self.config_file_name.split('.')
352 name_parts = self.config_file_name.split('.')
354 name_parts.insert(1, u'_' + self.profile_name + u'.')
353 name_parts.insert(1, u'_' + self.profile_name + u'.')
355 self.config_file_name = ''.join(name_parts)
354 self.config_file_name = ''.join(name_parts)
356
355
357 def find_config_file_paths(self):
356 def find_config_file_paths(self):
358 """Set the search paths for resolving the config file.
357 """Set the search paths for resolving the config file.
359
358
360 This must set ``self.config_file_paths`` to a sequence of search
359 This must set ``self.config_file_paths`` to a sequence of search
361 paths to pass to the config file loader.
360 paths to pass to the config file loader.
362 """
361 """
363 # Include our own profiles directory last, so that users can still find
362 # Include our own profiles directory last, so that users can still find
364 # our shipped copies of builtin profiles even if they don't have them
363 # our shipped copies of builtin profiles even if they don't have them
365 # in their local ipython directory.
364 # in their local ipython directory.
366 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
365 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
367 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
366 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
368
367
369 def pre_load_file_config(self):
368 def pre_load_file_config(self):
370 """Do actions before the config file is loaded."""
369 """Do actions before the config file is loaded."""
371 pass
370 pass
372
371
373 def load_file_config(self):
372 def load_file_config(self):
374 """Load the config file.
373 """Load the config file.
375
374
376 This tries to load the config file from disk. If successful, the
375 This tries to load the config file from disk. If successful, the
377 ``CONFIG_FILE`` config variable is set to the resolved config file
376 ``CONFIG_FILE`` config variable is set to the resolved config file
378 location. If not successful, an empty config is used.
377 location. If not successful, an empty config is used.
379 """
378 """
380 self.log.debug("Attempting to load config file: %s" %
379 self.log.debug("Attempting to load config file: %s" %
381 self.config_file_name)
380 self.config_file_name)
382 loader = PyFileConfigLoader(self.config_file_name,
381 loader = PyFileConfigLoader(self.config_file_name,
383 path=self.config_file_paths)
382 path=self.config_file_paths)
384 try:
383 try:
385 self.file_config = loader.load_config()
384 self.file_config = loader.load_config()
386 self.file_config.Global.config_file = loader.full_filename
385 self.file_config.Global.config_file = loader.full_filename
387 except IOError:
386 except IOError:
388 # Only warn if the default config file was NOT being used.
387 # Only warn if the default config file was NOT being used.
389 if not self.config_file_name==self.default_config_file_name:
388 if not self.config_file_name==self.default_config_file_name:
390 self.log.warn("Config file not found, skipping: %s" %
389 self.log.warn("Config file not found, skipping: %s" %
391 self.config_file_name, exc_info=True)
390 self.config_file_name, exc_info=True)
392 self.file_config = Config()
391 self.file_config = Config()
393 except:
392 except:
394 self.log.warn("Error loading config file: %s" %
393 self.log.warn("Error loading config file: %s" %
395 self.config_file_name, exc_info=True)
394 self.config_file_name, exc_info=True)
396 self.file_config = Config()
395 self.file_config = Config()
397
396
398 def set_file_config_log_level(self):
397 def set_file_config_log_level(self):
399 # We need to keeep self.log_level updated. But we only use the value
398 # We need to keeep self.log_level updated. But we only use the value
400 # of the file_config if a value was not specified at the command
399 # of the file_config if a value was not specified at the command
401 # line, because the command line overrides everything.
400 # line, because the command line overrides everything.
402 if not hasattr(self.command_line_config.Global, 'log_level'):
401 if not hasattr(self.command_line_config.Global, 'log_level'):
403 try:
402 try:
404 self.log_level = self.file_config.Global.log_level
403 self.log_level = self.file_config.Global.log_level
405 except AttributeError:
404 except AttributeError:
406 pass # Use existing value
405 pass # Use existing value
407
406
408 def post_load_file_config(self):
407 def post_load_file_config(self):
409 """Do actions after the config file is loaded."""
408 """Do actions after the config file is loaded."""
410 pass
409 pass
411
410
412 def log_file_config(self):
411 def log_file_config(self):
413 if hasattr(self.file_config.Global, 'config_file'):
412 if hasattr(self.file_config.Global, 'config_file'):
414 self.log.debug("Config file loaded: %s" %
413 self.log.debug("Config file loaded: %s" %
415 self.file_config.Global.config_file)
414 self.file_config.Global.config_file)
416 self.log.debug(repr(self.file_config))
415 self.log.debug(repr(self.file_config))
417
416
418 def merge_configs(self):
417 def merge_configs(self):
419 """Merge the default, command line and file config objects."""
418 """Merge the default, command line and file config objects."""
420 config = Config()
419 config = Config()
421 config._merge(self.default_config)
420 config._merge(self.default_config)
422 if self.override_config is None:
421 if self.override_config is None:
423 config._merge(self.file_config)
422 config._merge(self.file_config)
424 config._merge(self.command_line_config)
423 config._merge(self.command_line_config)
425 if self.constructor_config is not None:
424 if self.constructor_config is not None:
426 config._merge(self.constructor_config)
425 config._merge(self.constructor_config)
427 else:
426 else:
428 config._merge(self.override_config)
427 config._merge(self.override_config)
429 # XXX fperez - propose to Brian we rename master_config to simply
428 # XXX fperez - propose to Brian we rename master_config to simply
430 # config, I think this is going to be heavily used in examples and
429 # config, I think this is going to be heavily used in examples and
431 # application code and the name is shorter/easier to find/remember.
430 # application code and the name is shorter/easier to find/remember.
432 # For now, just alias it...
431 # For now, just alias it...
433 self.master_config = config
432 self.master_config = config
434 self.config = config
433 self.config = config
435
434
436 def log_master_config(self):
435 def log_master_config(self):
437 self.log.debug("Master config created:")
436 self.log.debug("Master config created:")
438 self.log.debug(repr(self.master_config))
437 self.log.debug(repr(self.master_config))
439
438
440 def pre_construct(self):
439 def pre_construct(self):
441 """Do actions after the config has been built, but before construct."""
440 """Do actions after the config has been built, but before construct."""
442 pass
441 pass
443
442
444 def construct(self):
443 def construct(self):
445 """Construct the main components that make up this app."""
444 """Construct the main components that make up this app."""
446 self.log.debug("Constructing components for application")
445 self.log.debug("Constructing components for application")
447
446
448 def post_construct(self):
447 def post_construct(self):
449 """Do actions after construct, but before starting the app."""
448 """Do actions after construct, but before starting the app."""
450 pass
449 pass
451
450
452 def start_app(self):
451 def start_app(self):
453 """Actually start the app."""
452 """Actually start the app."""
454 self.log.debug("Starting application")
453 self.log.debug("Starting application")
455
454
456 #-------------------------------------------------------------------------
455 #-------------------------------------------------------------------------
457 # Utility methods
456 # Utility methods
458 #-------------------------------------------------------------------------
457 #-------------------------------------------------------------------------
459
458
460 def abort(self):
459 def abort(self):
461 """Abort the starting of the application."""
460 """Abort the starting of the application."""
462 if self._exiting:
461 if self._exiting:
463 pass
462 pass
464 else:
463 else:
465 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
464 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
466 self._exiting = True
465 self._exiting = True
467 sys.exit(1)
466 sys.exit(1)
468
467
469 def exit(self, exit_status=0):
468 def exit(self, exit_status=0):
470 if self._exiting:
469 if self._exiting:
471 pass
470 pass
472 else:
471 else:
473 self.log.debug("Exiting application: %s" % self.name)
472 self.log.debug("Exiting application: %s" % self.name)
474 self._exiting = True
473 self._exiting = True
475 sys.exit(exit_status)
474 sys.exit(exit_status)
476
475
477 def attempt(self, func, action='abort'):
476 def attempt(self, func, action='abort'):
478 try:
477 try:
479 func()
478 func()
480 except SystemExit:
479 except SystemExit:
481 raise
480 raise
482 except:
481 except:
483 if action == 'abort':
482 if action == 'abort':
484 self.log.critical("Aborting application: %s" % self.name,
483 self.log.critical("Aborting application: %s" % self.name,
485 exc_info=True)
484 exc_info=True)
486 self.abort()
485 self.abort()
487 raise
486 raise
488 elif action == 'exit':
487 elif action == 'exit':
489 self.exit(0)
488 self.exit(0)
490
489
General Comments 0
You need to be logged in to leave comments. Login now