##// END OF EJS Templates
Move “Using existing profile dir” from info to debug:...
Matthias Bussonnier -
Show More
@@ -1,380 +1,380 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 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 # exit if cwd doesn't exist
174 174 self.log.error("Current working directory doesn't exist.")
175 175 self.exit(1)
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 if old is not None:
203 203 str_old = py3compat.cast_bytes_py2(os.path.abspath(old),
204 204 sys.getfilesystemencoding()
205 205 )
206 206 if str_old in sys.path:
207 207 sys.path.remove(str_old)
208 208 str_path = py3compat.cast_bytes_py2(os.path.abspath(new),
209 209 sys.getfilesystemencoding()
210 210 )
211 211 sys.path.append(str_path)
212 212 ensure_dir_exists(new)
213 213 readme = os.path.join(new, 'README')
214 214 readme_src = os.path.join(get_ipython_package_dir(), u'config', u'profile', 'README')
215 215 if not os.path.exists(readme) and os.path.exists(readme_src):
216 216 shutil.copy(readme_src, readme)
217 217 for d in ('extensions', 'nbextensions'):
218 218 path = os.path.join(new, d)
219 219 try:
220 220 ensure_dir_exists(path)
221 221 except OSError:
222 222 # this will not be EEXIST
223 223 self.log.error("couldn't create path %s: %s", path, e)
224 224 self.log.debug("IPYTHONDIR set to: %s" % new)
225 225
226 226 def load_config_file(self, suppress_errors=True):
227 227 """Load the config file.
228 228
229 229 By default, errors in loading config are handled, and a warning
230 230 printed on screen. For testing, the suppress_errors option is set
231 231 to False, so errors will make tests fail.
232 232 """
233 233 self.log.debug("Searching path %s for config files", self.config_file_paths)
234 234 base_config = 'ipython_config.py'
235 235 self.log.debug("Attempting to load config file: %s" %
236 236 base_config)
237 237 try:
238 238 Application.load_config_file(
239 239 self,
240 240 base_config,
241 241 path=self.config_file_paths
242 242 )
243 243 except ConfigFileNotFound:
244 244 # ignore errors loading parent
245 245 self.log.debug("Config file %s not found", base_config)
246 246 pass
247 247
248 248 for config_file_name in self.config_files:
249 249 if not config_file_name or config_file_name == base_config:
250 250 continue
251 251 self.log.debug("Attempting to load config file: %s" %
252 252 self.config_file_name)
253 253 try:
254 254 Application.load_config_file(
255 255 self,
256 256 config_file_name,
257 257 path=self.config_file_paths
258 258 )
259 259 except ConfigFileNotFound:
260 260 # Only warn if the default config file was NOT being used.
261 261 if config_file_name in self.config_file_specified:
262 262 msg = self.log.warn
263 263 else:
264 264 msg = self.log.debug
265 265 msg("Config file not found, skipping: %s", config_file_name)
266 266 except:
267 267 # For testing purposes.
268 268 if not suppress_errors:
269 269 raise
270 270 self.log.warn("Error loading config file: %s" %
271 271 self.config_file_name, exc_info=True)
272 272
273 273 def init_profile_dir(self):
274 274 """initialize the profile dir"""
275 275 self._in_init_profile_dir = True
276 276 if self.profile_dir is not None:
277 277 # already ran
278 278 return
279 279 if 'ProfileDir.location' not in self.config:
280 280 # location not specified, find by profile name
281 281 try:
282 282 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
283 283 except ProfileDirError:
284 284 # not found, maybe create it (always create default profile)
285 285 if self.auto_create or self.profile == 'default':
286 286 try:
287 287 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
288 288 except ProfileDirError:
289 289 self.log.fatal("Could not create profile: %r"%self.profile)
290 290 self.exit(1)
291 291 else:
292 292 self.log.info("Created profile dir: %r"%p.location)
293 293 else:
294 294 self.log.fatal("Profile %r not found."%self.profile)
295 295 self.exit(1)
296 296 else:
297 self.log.info("Using existing profile dir: %r"%p.location)
297 self.log.debug("Using existing profile dir: %r"%p.location)
298 298 else:
299 299 location = self.config.ProfileDir.location
300 300 # location is fully specified
301 301 try:
302 302 p = ProfileDir.find_profile_dir(location, self.config)
303 303 except ProfileDirError:
304 304 # not found, maybe create it
305 305 if self.auto_create:
306 306 try:
307 307 p = ProfileDir.create_profile_dir(location, self.config)
308 308 except ProfileDirError:
309 309 self.log.fatal("Could not create profile directory: %r"%location)
310 310 self.exit(1)
311 311 else:
312 self.log.info("Creating new profile dir: %r"%location)
312 self.log.debug("Creating new profile dir: %r"%location)
313 313 else:
314 314 self.log.fatal("Profile directory %r not found."%location)
315 315 self.exit(1)
316 316 else:
317 317 self.log.info("Using existing profile dir: %r"%location)
318 318 # if profile_dir is specified explicitly, set profile name
319 319 dir_name = os.path.basename(p.location)
320 320 if dir_name.startswith('profile_'):
321 321 self.profile = dir_name[8:]
322 322
323 323 self.profile_dir = p
324 324 self.config_file_paths.append(p.location)
325 325 self._in_init_profile_dir = False
326 326
327 327 def init_config_files(self):
328 328 """[optionally] copy default config files into profile dir."""
329 329 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
330 330 # copy config files
331 331 path = self.builtin_profile_dir
332 332 if self.copy_config_files:
333 333 src = self.profile
334 334
335 335 cfg = self.config_file_name
336 336 if path and os.path.exists(os.path.join(path, cfg)):
337 337 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
338 338 cfg, src, self.profile_dir.location, self.overwrite)
339 339 )
340 340 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
341 341 else:
342 342 self.stage_default_config_file()
343 343 else:
344 344 # Still stage *bundled* config files, but not generated ones
345 345 # This is necessary for `ipython profile=sympy` to load the profile
346 346 # on the first go
347 347 files = glob.glob(os.path.join(path, '*.py'))
348 348 for fullpath in files:
349 349 cfg = os.path.basename(fullpath)
350 350 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
351 351 # file was copied
352 352 self.log.warn("Staging bundled %s from %s into %r"%(
353 353 cfg, self.profile, self.profile_dir.location)
354 354 )
355 355
356 356
357 357 def stage_default_config_file(self):
358 358 """auto generate default config file, and stage it into the profile."""
359 359 s = self.generate_config_file()
360 360 fname = os.path.join(self.profile_dir.location, self.config_file_name)
361 361 if self.overwrite or not os.path.exists(fname):
362 362 self.log.warn("Generating default config file: %r"%(fname))
363 363 with open(fname, 'w') as f:
364 364 f.write(s)
365 365
366 366 @catch_config_error
367 367 def initialize(self, argv=None):
368 368 # don't hook up crash handler before parsing command-line
369 369 self.parse_command_line(argv)
370 370 self.init_crash_handler()
371 371 if self.subapp is not None:
372 372 # stop here if subapp is taking over
373 373 return
374 374 cl_config = self.config
375 375 self.init_profile_dir()
376 376 self.init_config_files()
377 377 self.load_config_file()
378 378 # enforce cl-opts override configfile opts:
379 379 self.update_config(cl_config)
380 380
General Comments 0
You need to be logged in to leave comments. Login now