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