##// END OF EJS Templates
prevent profile_dir from being undefined...
MinRK -
Show More
@@ -1,358 +1,369 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, Instance
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()
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 _in_init_profile_dir = False
137 profile_dir = Instance(ProfileDir)
138 def _profile_dir_default(self):
139 # avoid recursion
140 if self._in_init_profile_dir:
141 return
142 # profile_dir requested early, force initialization
143 self.init_profile_dir()
144 return self.profile_dir
136
145
137 overwrite = Bool(False, config=True,
146 overwrite = Bool(False, config=True,
138 help="""Whether to overwrite existing config files when copying""")
147 help="""Whether to overwrite existing config files when copying""")
139 auto_create = Bool(False, config=True,
148 auto_create = Bool(False, config=True,
140 help="""Whether to create profile dir if it doesn't exist""")
149 help="""Whether to create profile dir if it doesn't exist""")
141
150
142 config_files = List(Unicode)
151 config_files = List(Unicode)
143 def _config_files_default(self):
152 def _config_files_default(self):
144 return [self.config_file_name]
153 return [self.config_file_name]
145
154
146 copy_config_files = Bool(False, config=True,
155 copy_config_files = Bool(False, config=True,
147 help="""Whether to install the default config files into the profile dir.
156 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
157 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,
158 profile, then they will be staged into the new directory. Otherwise,
150 default config files will be automatically generated.
159 default config files will be automatically generated.
151 """)
160 """)
152
161
153 verbose_crash = Bool(False, config=True,
162 verbose_crash = Bool(False, config=True,
154 help="""Create a massive crash report when IPython encounters what may be an
163 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
164 internal error. The default is to append a short message to the
156 usual traceback""")
165 usual traceback""")
157
166
158 # The class to use as the crash handler.
167 # The class to use as the crash handler.
159 crash_handler_class = Type(crashhandler.CrashHandler)
168 crash_handler_class = Type(crashhandler.CrashHandler)
160
169
161 @catch_config_error
170 @catch_config_error
162 def __init__(self, **kwargs):
171 def __init__(self, **kwargs):
163 super(BaseIPythonApplication, self).__init__(**kwargs)
172 super(BaseIPythonApplication, self).__init__(**kwargs)
164 # ensure current working directory exists
173 # ensure current working directory exists
165 try:
174 try:
166 directory = os.getcwdu()
175 directory = os.getcwdu()
167 except:
176 except:
168 # raise exception
177 # raise exception
169 self.log.error("Current working directory doesn't exist.")
178 self.log.error("Current working directory doesn't exist.")
170 raise
179 raise
171
180
172 # ensure even default IPYTHONDIR exists
181 # ensure even default IPYTHONDIR exists
173 if not os.path.exists(self.ipython_dir):
182 if not os.path.exists(self.ipython_dir):
174 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
183 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
175
184
176 #-------------------------------------------------------------------------
185 #-------------------------------------------------------------------------
177 # Various stages of Application creation
186 # Various stages of Application creation
178 #-------------------------------------------------------------------------
187 #-------------------------------------------------------------------------
179
188
180 def init_crash_handler(self):
189 def init_crash_handler(self):
181 """Create a crash handler, typically setting sys.excepthook to it."""
190 """Create a crash handler, typically setting sys.excepthook to it."""
182 self.crash_handler = self.crash_handler_class(self)
191 self.crash_handler = self.crash_handler_class(self)
183 sys.excepthook = self.excepthook
192 sys.excepthook = self.excepthook
184 def unset_crashhandler():
193 def unset_crashhandler():
185 sys.excepthook = sys.__excepthook__
194 sys.excepthook = sys.__excepthook__
186 atexit.register(unset_crashhandler)
195 atexit.register(unset_crashhandler)
187
196
188 def excepthook(self, etype, evalue, tb):
197 def excepthook(self, etype, evalue, tb):
189 """this is sys.excepthook after init_crashhandler
198 """this is sys.excepthook after init_crashhandler
190
199
191 set self.verbose_crash=True to use our full crashhandler, instead of
200 set self.verbose_crash=True to use our full crashhandler, instead of
192 a regular traceback with a short message (crash_handler_lite)
201 a regular traceback with a short message (crash_handler_lite)
193 """
202 """
194
203
195 if self.verbose_crash:
204 if self.verbose_crash:
196 return self.crash_handler(etype, evalue, tb)
205 return self.crash_handler(etype, evalue, tb)
197 else:
206 else:
198 return crashhandler.crash_handler_lite(etype, evalue, tb)
207 return crashhandler.crash_handler_lite(etype, evalue, tb)
199
208
200 def _ipython_dir_changed(self, name, old, new):
209 def _ipython_dir_changed(self, name, old, new):
201 if old in sys.path:
210 if old in sys.path:
202 sys.path.remove(old)
211 sys.path.remove(old)
203 sys.path.append(os.path.abspath(new))
212 sys.path.append(os.path.abspath(new))
204 if not os.path.isdir(new):
213 if not os.path.isdir(new):
205 os.makedirs(new, mode=0o777)
214 os.makedirs(new, mode=0o777)
206 readme = os.path.join(new, 'README')
215 readme = os.path.join(new, 'README')
207 if not os.path.exists(readme):
216 if not os.path.exists(readme):
208 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
217 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
209 shutil.copy(os.path.join(path, 'README'), readme)
218 shutil.copy(os.path.join(path, 'README'), readme)
210 self.log.debug("IPYTHONDIR set to: %s" % new)
219 self.log.debug("IPYTHONDIR set to: %s" % new)
211
220
212 def load_config_file(self, suppress_errors=True):
221 def load_config_file(self, suppress_errors=True):
213 """Load the config file.
222 """Load the config file.
214
223
215 By default, errors in loading config are handled, and a warning
224 By default, errors in loading config are handled, and a warning
216 printed on screen. For testing, the suppress_errors option is set
225 printed on screen. For testing, the suppress_errors option is set
217 to False, so errors will make tests fail.
226 to False, so errors will make tests fail.
218 """
227 """
219 self.log.debug("Searching path %s for config files", self.config_file_paths)
228 self.log.debug("Searching path %s for config files", self.config_file_paths)
220 base_config = 'ipython_config.py'
229 base_config = 'ipython_config.py'
221 self.log.debug("Attempting to load config file: %s" %
230 self.log.debug("Attempting to load config file: %s" %
222 base_config)
231 base_config)
223 try:
232 try:
224 Application.load_config_file(
233 Application.load_config_file(
225 self,
234 self,
226 base_config,
235 base_config,
227 path=self.config_file_paths
236 path=self.config_file_paths
228 )
237 )
229 except ConfigFileNotFound:
238 except ConfigFileNotFound:
230 # ignore errors loading parent
239 # ignore errors loading parent
231 self.log.debug("Config file %s not found", base_config)
240 self.log.debug("Config file %s not found", base_config)
232 pass
241 pass
233
242
234 for config_file_name in self.config_files:
243 for config_file_name in self.config_files:
235 if not config_file_name or config_file_name == base_config:
244 if not config_file_name or config_file_name == base_config:
236 continue
245 continue
237 self.log.debug("Attempting to load config file: %s" %
246 self.log.debug("Attempting to load config file: %s" %
238 self.config_file_name)
247 self.config_file_name)
239 try:
248 try:
240 Application.load_config_file(
249 Application.load_config_file(
241 self,
250 self,
242 config_file_name,
251 config_file_name,
243 path=self.config_file_paths
252 path=self.config_file_paths
244 )
253 )
245 except ConfigFileNotFound:
254 except ConfigFileNotFound:
246 # Only warn if the default config file was NOT being used.
255 # Only warn if the default config file was NOT being used.
247 if config_file_name in self.config_file_specified:
256 if config_file_name in self.config_file_specified:
248 msg = self.log.warn
257 msg = self.log.warn
249 else:
258 else:
250 msg = self.log.debug
259 msg = self.log.debug
251 msg("Config file not found, skipping: %s", config_file_name)
260 msg("Config file not found, skipping: %s", config_file_name)
252 except:
261 except:
253 # For testing purposes.
262 # For testing purposes.
254 if not suppress_errors:
263 if not suppress_errors:
255 raise
264 raise
256 self.log.warn("Error loading config file: %s" %
265 self.log.warn("Error loading config file: %s" %
257 self.config_file_name, exc_info=True)
266 self.config_file_name, exc_info=True)
258
267
259 def init_profile_dir(self):
268 def init_profile_dir(self):
260 """initialize the profile dir"""
269 """initialize the profile dir"""
270 self._in_init_profile_dir = True
261 try:
271 try:
262 # location explicitly specified:
272 # location explicitly specified:
263 location = self.config.ProfileDir.location
273 location = self.config.ProfileDir.location
264 except AttributeError:
274 except AttributeError:
265 # location not specified, find by profile name
275 # location not specified, find by profile name
266 try:
276 try:
267 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
277 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
268 except ProfileDirError:
278 except ProfileDirError:
269 # not found, maybe create it (always create default profile)
279 # not found, maybe create it (always create default profile)
270 if self.auto_create or self.profile == 'default':
280 if self.auto_create or self.profile == 'default':
271 try:
281 try:
272 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
282 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
273 except ProfileDirError:
283 except ProfileDirError:
274 self.log.fatal("Could not create profile: %r"%self.profile)
284 self.log.fatal("Could not create profile: %r"%self.profile)
275 self.exit(1)
285 self.exit(1)
276 else:
286 else:
277 self.log.info("Created profile dir: %r"%p.location)
287 self.log.info("Created profile dir: %r"%p.location)
278 else:
288 else:
279 self.log.fatal("Profile %r not found."%self.profile)
289 self.log.fatal("Profile %r not found."%self.profile)
280 self.exit(1)
290 self.exit(1)
281 else:
291 else:
282 self.log.info("Using existing profile dir: %r"%p.location)
292 self.log.info("Using existing profile dir: %r"%p.location)
283 else:
293 else:
284 # location is fully specified
294 # location is fully specified
285 try:
295 try:
286 p = ProfileDir.find_profile_dir(location, self.config)
296 p = ProfileDir.find_profile_dir(location, self.config)
287 except ProfileDirError:
297 except ProfileDirError:
288 # not found, maybe create it
298 # not found, maybe create it
289 if self.auto_create:
299 if self.auto_create:
290 try:
300 try:
291 p = ProfileDir.create_profile_dir(location, self.config)
301 p = ProfileDir.create_profile_dir(location, self.config)
292 except ProfileDirError:
302 except ProfileDirError:
293 self.log.fatal("Could not create profile directory: %r"%location)
303 self.log.fatal("Could not create profile directory: %r"%location)
294 self.exit(1)
304 self.exit(1)
295 else:
305 else:
296 self.log.info("Creating new profile dir: %r"%location)
306 self.log.info("Creating new profile dir: %r"%location)
297 else:
307 else:
298 self.log.fatal("Profile directory %r not found."%location)
308 self.log.fatal("Profile directory %r not found."%location)
299 self.exit(1)
309 self.exit(1)
300 else:
310 else:
301 self.log.info("Using existing profile dir: %r"%location)
311 self.log.info("Using existing profile dir: %r"%location)
302
312
303 self.profile_dir = p
313 self.profile_dir = p
304 self.config_file_paths.append(p.location)
314 self.config_file_paths.append(p.location)
315 self._in_init_profile_dir = False
305
316
306 def init_config_files(self):
317 def init_config_files(self):
307 """[optionally] copy default config files into profile dir."""
318 """[optionally] copy default config files into profile dir."""
308 # copy config files
319 # copy config files
309 path = self.builtin_profile_dir
320 path = self.builtin_profile_dir
310 if self.copy_config_files:
321 if self.copy_config_files:
311 src = self.profile
322 src = self.profile
312
323
313 cfg = self.config_file_name
324 cfg = self.config_file_name
314 if path and os.path.exists(os.path.join(path, cfg)):
325 if path and os.path.exists(os.path.join(path, cfg)):
315 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
326 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
316 cfg, src, self.profile_dir.location, self.overwrite)
327 cfg, src, self.profile_dir.location, self.overwrite)
317 )
328 )
318 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
329 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
319 else:
330 else:
320 self.stage_default_config_file()
331 self.stage_default_config_file()
321 else:
332 else:
322 # Still stage *bundled* config files, but not generated ones
333 # Still stage *bundled* config files, but not generated ones
323 # This is necessary for `ipython profile=sympy` to load the profile
334 # This is necessary for `ipython profile=sympy` to load the profile
324 # on the first go
335 # on the first go
325 files = glob.glob(os.path.join(path, '*.py'))
336 files = glob.glob(os.path.join(path, '*.py'))
326 for fullpath in files:
337 for fullpath in files:
327 cfg = os.path.basename(fullpath)
338 cfg = os.path.basename(fullpath)
328 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
339 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
329 # file was copied
340 # file was copied
330 self.log.warn("Staging bundled %s from %s into %r"%(
341 self.log.warn("Staging bundled %s from %s into %r"%(
331 cfg, self.profile, self.profile_dir.location)
342 cfg, self.profile, self.profile_dir.location)
332 )
343 )
333
344
334
345
335 def stage_default_config_file(self):
346 def stage_default_config_file(self):
336 """auto generate default config file, and stage it into the profile."""
347 """auto generate default config file, and stage it into the profile."""
337 s = self.generate_config_file()
348 s = self.generate_config_file()
338 fname = os.path.join(self.profile_dir.location, self.config_file_name)
349 fname = os.path.join(self.profile_dir.location, self.config_file_name)
339 if self.overwrite or not os.path.exists(fname):
350 if self.overwrite or not os.path.exists(fname):
340 self.log.warn("Generating default config file: %r"%(fname))
351 self.log.warn("Generating default config file: %r"%(fname))
341 with open(fname, 'w') as f:
352 with open(fname, 'w') as f:
342 f.write(s)
353 f.write(s)
343
354
344 @catch_config_error
355 @catch_config_error
345 def initialize(self, argv=None):
356 def initialize(self, argv=None):
346 # don't hook up crash handler before parsing command-line
357 # don't hook up crash handler before parsing command-line
347 self.parse_command_line(argv)
358 self.parse_command_line(argv)
348 self.init_crash_handler()
359 self.init_crash_handler()
349 if self.subapp is not None:
360 if self.subapp is not None:
350 # stop here if subapp is taking over
361 # stop here if subapp is taking over
351 return
362 return
352 cl_config = self.config
363 cl_config = self.config
353 self.init_profile_dir()
364 self.init_profile_dir()
354 self.init_config_files()
365 self.init_config_files()
355 self.load_config_file()
366 self.load_config_file()
356 # enforce cl-opts override configfile opts:
367 # enforce cl-opts override configfile opts:
357 self.update_config(cl_config)
368 self.update_config(cl_config)
358
369
General Comments 0
You need to be logged in to leave comments. Login now