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