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