##// END OF EJS Templates
Don't warn the user if the default config file is missing....
Brian Granger -
Show More
@@ -1,295 +1,298 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 An application for IPython
4 An application for IPython
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10
10
11 Notes
11 Notes
12 -----
12 -----
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2009 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 import logging
26 import logging
27 import os
27 import os
28 import sys
28 import sys
29 import traceback
29 import traceback
30 from copy import deepcopy
30 from copy import deepcopy
31
31
32 from IPython.utils.genutils import get_ipython_dir, filefind
32 from IPython.utils.genutils import get_ipython_dir, filefind
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 PyFileConfigLoader,
34 PyFileConfigLoader,
35 ArgParseConfigLoader,
35 ArgParseConfigLoader,
36 Config,
36 Config,
37 NoConfigDefault
37 NoConfigDefault
38 )
38 )
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Classes and functions
41 # Classes and functions
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44
44
45 class IPythonArgParseConfigLoader(ArgParseConfigLoader):
45 class IPythonArgParseConfigLoader(ArgParseConfigLoader):
46 """Default command line options for IPython based applications."""
46 """Default command line options for IPython based applications."""
47
47
48 def _add_other_arguments(self):
48 def _add_other_arguments(self):
49 self.parser.add_argument('-ipythondir',dest='Global.ipythondir',type=str,
49 self.parser.add_argument('-ipythondir',dest='Global.ipythondir',type=str,
50 help='Set to override default location of Global.ipythondir.',
50 help='Set to override default location of Global.ipythondir.',
51 default=NoConfigDefault,
51 default=NoConfigDefault,
52 metavar='Global.ipythondir')
52 metavar='Global.ipythondir')
53 self.parser.add_argument('-p','-profile',dest='Global.profile',type=str,
53 self.parser.add_argument('-p','-profile',dest='Global.profile',type=str,
54 help='The string name of the ipython profile to be used.',
54 help='The string name of the ipython profile to be used.',
55 default=NoConfigDefault,
55 default=NoConfigDefault,
56 metavar='Global.profile')
56 metavar='Global.profile')
57 self.parser.add_argument('-log_level',dest="Global.log_level",type=int,
57 self.parser.add_argument('-log_level',dest="Global.log_level",type=int,
58 help='Set the log level (0,10,20,30,40,50). Default is 30.',
58 help='Set the log level (0,10,20,30,40,50). Default is 30.',
59 default=NoConfigDefault)
59 default=NoConfigDefault)
60 self.parser.add_argument('-config_file',dest='Global.config_file',type=str,
60 self.parser.add_argument('-config_file',dest='Global.config_file',type=str,
61 help='Set the config file name to override default.',
61 help='Set the config file name to override default.',
62 default=NoConfigDefault,
62 default=NoConfigDefault,
63 metavar='Global.config_file')
63 metavar='Global.config_file')
64
64
65
65
66 class ApplicationError(Exception):
66 class ApplicationError(Exception):
67 pass
67 pass
68
68
69
69
70 class Application(object):
70 class Application(object):
71 """Load a config, construct an app and run it.
71 """Load a config, construct an app and run it.
72 """
72 """
73
73
74 config_file_name = 'ipython_config.py'
74 config_file_name = 'ipython_config.py'
75 name = 'ipython'
75 name = 'ipython'
76
76
77 def __init__(self):
77 def __init__(self):
78 self.init_logger()
78 self.init_logger()
79 self.default_config_file_name = self.config_file_name
79
80
80 def init_logger(self):
81 def init_logger(self):
81 self.log = logging.getLogger(self.__class__.__name__)
82 self.log = logging.getLogger(self.__class__.__name__)
82 # This is used as the default until the command line arguments are read.
83 # This is used as the default until the command line arguments are read.
83 self.log.setLevel(logging.WARN)
84 self.log.setLevel(logging.WARN)
84 self._log_handler = logging.StreamHandler()
85 self._log_handler = logging.StreamHandler()
85 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
86 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
86 self._log_handler.setFormatter(self._log_formatter)
87 self._log_handler.setFormatter(self._log_formatter)
87 self.log.addHandler(self._log_handler)
88 self.log.addHandler(self._log_handler)
88
89
89 def _set_log_level(self, level):
90 def _set_log_level(self, level):
90 self.log.setLevel(level)
91 self.log.setLevel(level)
91
92
92 def _get_log_level(self):
93 def _get_log_level(self):
93 return self.log.level
94 return self.log.level
94
95
95 log_level = property(_get_log_level, _set_log_level)
96 log_level = property(_get_log_level, _set_log_level)
96
97
97 def start(self):
98 def start(self):
98 """Start the application."""
99 """Start the application."""
99 self.attempt(self.create_default_config)
100 self.attempt(self.create_default_config)
100 self.attempt(self.pre_load_command_line_config)
101 self.attempt(self.pre_load_command_line_config)
101 self.attempt(self.load_command_line_config, action='abort')
102 self.attempt(self.load_command_line_config, action='abort')
102 self.attempt(self.post_load_command_line_config)
103 self.attempt(self.post_load_command_line_config)
103 self.attempt(self.find_ipythondir)
104 self.attempt(self.find_ipythondir)
104 self.attempt(self.find_config_file_name)
105 self.attempt(self.find_config_file_name)
105 self.attempt(self.find_config_file_paths)
106 self.attempt(self.find_config_file_paths)
106 self.attempt(self.pre_load_file_config)
107 self.attempt(self.pre_load_file_config)
107 self.attempt(self.load_file_config)
108 self.attempt(self.load_file_config)
108 self.attempt(self.post_load_file_config)
109 self.attempt(self.post_load_file_config)
109 self.attempt(self.merge_configs)
110 self.attempt(self.merge_configs)
110 self.attempt(self.pre_construct)
111 self.attempt(self.pre_construct)
111 self.attempt(self.construct)
112 self.attempt(self.construct)
112 self.attempt(self.post_construct)
113 self.attempt(self.post_construct)
113 self.attempt(self.start_app)
114 self.attempt(self.start_app)
114
115
115 #-------------------------------------------------------------------------
116 #-------------------------------------------------------------------------
116 # Various stages of Application creation
117 # Various stages of Application creation
117 #-------------------------------------------------------------------------
118 #-------------------------------------------------------------------------
118
119
119 def create_default_config(self):
120 def create_default_config(self):
120 """Create defaults that can't be set elsewhere.
121 """Create defaults that can't be set elsewhere.
121
122
122 For the most part, we try to set default in the class attributes
123 For the most part, we try to set default in the class attributes
123 of Components. But, defaults the top-level Application (which is
124 of Components. But, defaults the top-level Application (which is
124 not a HasTraitlets or Component) are not set in this way. Instead
125 not a HasTraitlets or Component) are not set in this way. Instead
125 we set them here. The Global section is for variables like this that
126 we set them here. The Global section is for variables like this that
126 don't belong to a particular component.
127 don't belong to a particular component.
127 """
128 """
128 self.default_config = Config()
129 self.default_config = Config()
129 self.default_config.Global.ipythondir = get_ipython_dir()
130 self.default_config.Global.ipythondir = get_ipython_dir()
130 self.log.debug('Default config loaded:')
131 self.log.debug('Default config loaded:')
131 self.log.debug(repr(self.default_config))
132 self.log.debug(repr(self.default_config))
132
133
133 def create_command_line_config(self):
134 def create_command_line_config(self):
134 """Create and return a command line config loader."""
135 """Create and return a command line config loader."""
135 return IPythonArgParseConfigLoader(description=self.name)
136 return IPythonArgParseConfigLoader(description=self.name)
136
137
137 def pre_load_command_line_config(self):
138 def pre_load_command_line_config(self):
138 """Do actions just before loading the command line config."""
139 """Do actions just before loading the command line config."""
139 pass
140 pass
140
141
141 def load_command_line_config(self):
142 def load_command_line_config(self):
142 """Load the command line config.
143 """Load the command line config.
143
144
144 This method also sets ``self.debug``.
145 This method also sets ``self.debug``.
145 """
146 """
146
147
147 loader = self.create_command_line_config()
148 loader = self.create_command_line_config()
148 self.command_line_config = loader.load_config()
149 self.command_line_config = loader.load_config()
149 self.extra_args = loader.get_extra_args()
150 self.extra_args = loader.get_extra_args()
150
151
151 try:
152 try:
152 self.log_level = self.command_line_config.Global.log_level
153 self.log_level = self.command_line_config.Global.log_level
153 except AttributeError:
154 except AttributeError:
154 pass # Use existing value which is set in Application.init_logger.
155 pass # Use existing value which is set in Application.init_logger.
155
156
156 self.log.debug("Command line config loaded:")
157 self.log.debug("Command line config loaded:")
157 self.log.debug(repr(self.command_line_config))
158 self.log.debug(repr(self.command_line_config))
158
159
159 def post_load_command_line_config(self):
160 def post_load_command_line_config(self):
160 """Do actions just after loading the command line config."""
161 """Do actions just after loading the command line config."""
161 pass
162 pass
162
163
163 def find_ipythondir(self):
164 def find_ipythondir(self):
164 """Set the IPython directory.
165 """Set the IPython directory.
165
166
166 This sets ``self.ipythondir``, but the actual value that is passed
167 This sets ``self.ipythondir``, but the actual value that is passed
167 to the application is kept in either ``self.default_config`` or
168 to the application is kept in either ``self.default_config`` or
168 ``self.command_line_config``. This also added ``self.ipythondir`` to
169 ``self.command_line_config``. This also added ``self.ipythondir`` to
169 ``sys.path`` so config files there can be references by other config
170 ``sys.path`` so config files there can be references by other config
170 files.
171 files.
171 """
172 """
172
173
173 try:
174 try:
174 self.ipythondir = self.command_line_config.Global.ipythondir
175 self.ipythondir = self.command_line_config.Global.ipythondir
175 except AttributeError:
176 except AttributeError:
176 self.ipythondir = self.default_config.Global.ipythondir
177 self.ipythondir = self.default_config.Global.ipythondir
177 sys.path.append(os.path.abspath(self.ipythondir))
178 sys.path.append(os.path.abspath(self.ipythondir))
178 if not os.path.isdir(self.ipythondir):
179 if not os.path.isdir(self.ipythondir):
179 os.makedirs(self.ipythondir, mode = 0777)
180 os.makedirs(self.ipythondir, mode = 0777)
180 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)
181 self.log.debug("IPYTHONDIR set to: %s" % self.ipythondir)
181
182
182 def find_config_file_name(self):
183 def find_config_file_name(self):
183 """Find the config file name for this application.
184 """Find the config file name for this application.
184
185
185 If a profile has been set at the command line, this will resolve
186 If a profile has been set at the command line, this will resolve
186 it. The search paths for the config file are set in
187 it. The search paths for the config file are set in
187 :meth:`find_config_file_paths` and then passed to the config file
188 :meth:`find_config_file_paths` and then passed to the config file
188 loader where they are resolved to an absolute path.
189 loader where they are resolved to an absolute path.
189 """
190 """
190
191
191 try:
192 try:
192 self.config_file_name = self.command_line_config.Global.config_file
193 self.config_file_name = self.command_line_config.Global.config_file
193 except AttributeError:
194 except AttributeError:
194 pass
195 pass
195
196
196 try:
197 try:
197 self.profile_name = self.command_line_config.Global.profile
198 self.profile_name = self.command_line_config.Global.profile
198 name_parts = self.config_file_name.split('.')
199 name_parts = self.config_file_name.split('.')
199 name_parts.insert(1, '_' + self.profile_name + '.')
200 name_parts.insert(1, '_' + self.profile_name + '.')
200 self.config_file_name = ''.join(name_parts)
201 self.config_file_name = ''.join(name_parts)
201 except AttributeError:
202 except AttributeError:
202 pass
203 pass
203
204
204 def find_config_file_paths(self):
205 def find_config_file_paths(self):
205 """Set the search paths for resolving the config file."""
206 """Set the search paths for resolving the config file."""
206 self.config_file_paths = (os.getcwd(), self.ipythondir)
207 self.config_file_paths = (os.getcwd(), self.ipythondir)
207
208
208 def pre_load_file_config(self):
209 def pre_load_file_config(self):
209 """Do actions before the config file is loaded."""
210 """Do actions before the config file is loaded."""
210 pass
211 pass
211
212
212 def load_file_config(self):
213 def load_file_config(self):
213 """Load the config file.
214 """Load the config file.
214
215
215 This tries to load the config file from disk. If successful, the
216 This tries to load the config file from disk. If successful, the
216 ``CONFIG_FILE`` config variable is set to the resolved config file
217 ``CONFIG_FILE`` config variable is set to the resolved config file
217 location. If not successful, an empty config is used.
218 location. If not successful, an empty config is used.
218 """
219 """
219 self.log.debug("Attempting to load config file: <%s>" % self.config_file_name)
220 self.log.debug("Attempting to load config file: <%s>" % self.config_file_name)
220 loader = PyFileConfigLoader(self.config_file_name,
221 loader = PyFileConfigLoader(self.config_file_name,
221 path=self.config_file_paths)
222 path=self.config_file_paths)
222 try:
223 try:
223 self.file_config = loader.load_config()
224 self.file_config = loader.load_config()
224 self.file_config.Global.config_file = loader.full_filename
225 self.file_config.Global.config_file = loader.full_filename
225 except IOError:
226 except IOError:
226 self.log.warn("Config file not found, skipping: <%s>" % \
227 # Only warn if the default config file was NOT being used.
227 self.config_file_name, exc_info=True)
228 if not self.config_file_name==self.default_config_file_name:
229 self.log.warn("Config file not found, skipping: <%s>" % \
230 self.config_file_name, exc_info=True)
228 self.file_config = Config()
231 self.file_config = Config()
229 except:
232 except:
230 self.log.warn("Error loading config file: <%s>" % \
233 self.log.warn("Error loading config file: <%s>" % \
231 self.config_file_name, exc_info=True)
234 self.config_file_name, exc_info=True)
232 self.file_config = Config()
235 self.file_config = Config()
233 else:
236 else:
234 self.log.debug("Config file loaded: <%s>" % loader.full_filename)
237 self.log.debug("Config file loaded: <%s>" % loader.full_filename)
235 self.log.debug(repr(self.file_config))
238 self.log.debug(repr(self.file_config))
236 # We need to keeep self.log_level updated.
239 # We need to keeep self.log_level updated.
237 try:
240 try:
238 self.log_level = self.file_config.Global.log_level
241 self.log_level = self.file_config.Global.log_level
239 except AttributeError:
242 except AttributeError:
240 pass # Use existing value
243 pass # Use existing value
241
244
242 def post_load_file_config(self):
245 def post_load_file_config(self):
243 """Do actions after the config file is loaded."""
246 """Do actions after the config file is loaded."""
244 pass
247 pass
245
248
246 def merge_configs(self):
249 def merge_configs(self):
247 """Merge the default, command line and file config objects."""
250 """Merge the default, command line and file config objects."""
248 config = Config()
251 config = Config()
249 config._merge(self.default_config)
252 config._merge(self.default_config)
250 config._merge(self.file_config)
253 config._merge(self.file_config)
251 config._merge(self.command_line_config)
254 config._merge(self.command_line_config)
252 self.master_config = config
255 self.master_config = config
253 self.log.debug("Master config created:")
256 self.log.debug("Master config created:")
254 self.log.debug(repr(self.master_config))
257 self.log.debug(repr(self.master_config))
255
258
256 def pre_construct(self):
259 def pre_construct(self):
257 """Do actions after the config has been built, but before construct."""
260 """Do actions after the config has been built, but before construct."""
258 pass
261 pass
259
262
260 def construct(self):
263 def construct(self):
261 """Construct the main components that make up this app."""
264 """Construct the main components that make up this app."""
262 self.log.debug("Constructing components for application")
265 self.log.debug("Constructing components for application")
263
266
264 def post_construct(self):
267 def post_construct(self):
265 """Do actions after construct, but before starting the app."""
268 """Do actions after construct, but before starting the app."""
266 pass
269 pass
267
270
268 def start_app(self):
271 def start_app(self):
269 """Actually start the app."""
272 """Actually start the app."""
270 self.log.debug("Starting application")
273 self.log.debug("Starting application")
271
274
272 #-------------------------------------------------------------------------
275 #-------------------------------------------------------------------------
273 # Utility methods
276 # Utility methods
274 #-------------------------------------------------------------------------
277 #-------------------------------------------------------------------------
275
278
276 def abort(self):
279 def abort(self):
277 """Abort the starting of the application."""
280 """Abort the starting of the application."""
278 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
281 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
279 sys.exit(1)
282 sys.exit(1)
280
283
281 def exit(self):
284 def exit(self):
282 self.log.critical("Aborting application: %s" % self.name)
285 self.log.critical("Aborting application: %s" % self.name)
283 sys.exit(1)
286 sys.exit(1)
284
287
285 def attempt(self, func, action='abort'):
288 def attempt(self, func, action='abort'):
286 try:
289 try:
287 func()
290 func()
288 except SystemExit:
291 except SystemExit:
289 self.exit()
292 self.exit()
290 except:
293 except:
291 if action == 'abort':
294 if action == 'abort':
292 self.abort()
295 self.abort()
293 elif action == 'exit':
296 elif action == 'exit':
294 self.exit()
297 self.exit()
295 No newline at end of file
298
General Comments 0
You need to be logged in to leave comments. Login now