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