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