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