##// END OF EJS Templates
make config-loading debug messages more explicit...
MinRK -
Show More
@@ -1,431 +1,435 b''
1 1 # encoding: utf-8
2 2 """
3 3 A base class for a configurable application.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Min RK
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import logging
23 23 import os
24 24 import re
25 25 import sys
26 26 from copy import deepcopy
27 27
28 28 from IPython.config.configurable import SingletonConfigurable
29 29 from IPython.config.loader import (
30 30 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
31 31 )
32 32
33 33 from IPython.utils.traitlets import (
34 34 Unicode, List, Int, Enum, Dict, Instance, TraitError
35 35 )
36 36 from IPython.utils.importstring import import_item
37 37 from IPython.utils.text import indent, wrap_paragraphs, dedent
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # function for re-wrapping a helpstring
41 41 #-----------------------------------------------------------------------------
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Descriptions for the various sections
45 45 #-----------------------------------------------------------------------------
46 46
47 47 # merge flags&aliases into options
48 48 option_description = """
49 49 IPython command-line arguments are passed as '--<flag>', or '--<name>=<value>'.
50 50
51 51 Arguments that take values are actually convenience aliases to full
52 52 Configurables, whose aliases are listed on the help line. For more information
53 53 on full configurables, see '--help-all'.
54 54 """.strip() # trim newlines of front and back
55 55
56 56 keyvalue_description = """
57 57 Parameters are set from command-line arguments of the form:
58 58 `--Class.trait=value`.
59 59 This line is evaluated in Python, so simple expressions are allowed, e.g.::
60 60 `--C.a='range(3)'` For setting C.a=[0,1,2].
61 61 """.strip() # trim newlines of front and back
62 62
63 63 subcommand_description = """
64 64 Subcommands are launched as `{app} cmd [args]`. For information on using
65 65 subcommand 'cmd', do: `{app} cmd -h`.
66 66 """.strip().format(app=os.path.basename(sys.argv[0]))
67 67 # get running program name
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Application class
71 71 #-----------------------------------------------------------------------------
72 72
73 73
74 74 class ApplicationError(Exception):
75 75 pass
76 76
77 77
78 78 class Application(SingletonConfigurable):
79 79 """A singleton application with full configuration support."""
80 80
81 81 # The name of the application, will usually match the name of the command
82 82 # line application
83 83 name = Unicode(u'application')
84 84
85 85 # The description of the application that is printed at the beginning
86 86 # of the help.
87 87 description = Unicode(u'This is an application.')
88 88 # default section descriptions
89 89 option_description = Unicode(option_description)
90 90 keyvalue_description = Unicode(keyvalue_description)
91 91 subcommand_description = Unicode(subcommand_description)
92 92
93 93 # The usage and example string that goes at the end of the help string.
94 94 examples = Unicode()
95 95
96 96 # A sequence of Configurable subclasses whose config=True attributes will
97 97 # be exposed at the command line.
98 98 classes = List([])
99 99
100 100 # The version string of this application.
101 101 version = Unicode(u'0.0')
102 102
103 103 # The log level for the application
104 104 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
105 105 default_value=logging.WARN,
106 106 config=True,
107 107 help="Set the log level by value or name.")
108 108 def _log_level_changed(self, name, old, new):
109 109 """Adjust the log level when log_level is set."""
110 110 if isinstance(new, basestring):
111 111 new = getattr(logging, new)
112 112 self.log_level = new
113 113 self.log.setLevel(new)
114 114
115 115 # the alias map for configurables
116 116 aliases = Dict({'log-level' : 'Application.log_level'})
117 117
118 118 # flags for loading Configurables or store_const style flags
119 119 # flags are loaded from this dict by '--key' flags
120 120 # this must be a dict of two-tuples, the first element being the Config/dict
121 121 # and the second being the help string for the flag
122 122 flags = Dict()
123 123 def _flags_changed(self, name, old, new):
124 124 """ensure flags dict is valid"""
125 125 for key,value in new.iteritems():
126 126 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
127 127 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
128 128 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
129 129
130 130
131 131 # subcommands for launching other applications
132 132 # if this is not empty, this will be a parent Application
133 133 # this must be a dict of two-tuples,
134 134 # the first element being the application class/import string
135 135 # and the second being the help string for the subcommand
136 136 subcommands = Dict()
137 137 # parse_command_line will initialize a subapp, if requested
138 138 subapp = Instance('IPython.config.application.Application', allow_none=True)
139 139
140 140 # extra command-line arguments that don't set config values
141 141 extra_args = List(Unicode)
142 142
143 143
144 144 def __init__(self, **kwargs):
145 145 SingletonConfigurable.__init__(self, **kwargs)
146 146 # Ensure my class is in self.classes, so my attributes appear in command line
147 147 # options and config files.
148 148 if self.__class__ not in self.classes:
149 149 self.classes.insert(0, self.__class__)
150 150
151 151 self.init_logging()
152 152
153 153 def _config_changed(self, name, old, new):
154 154 SingletonConfigurable._config_changed(self, name, old, new)
155 155 self.log.debug('Config changed:')
156 156 self.log.debug(repr(new))
157 157
158 158 def init_logging(self):
159 159 """Start logging for this application.
160 160
161 161 The default is to log to stdout using a StreaHandler. The log level
162 162 starts at loggin.WARN, but this can be adjusted by setting the
163 163 ``log_level`` attribute.
164 164 """
165 165 self.log = logging.getLogger(self.__class__.__name__)
166 166 self.log.setLevel(self.log_level)
167 167 if sys.executable.endswith('pythonw.exe'):
168 168 # this should really go to a file, but file-logging is only
169 169 # hooked up in parallel applications
170 170 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
171 171 else:
172 172 self._log_handler = logging.StreamHandler()
173 173 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
174 174 self._log_handler.setFormatter(self._log_formatter)
175 175 self.log.addHandler(self._log_handler)
176 176
177 177 def initialize(self, argv=None):
178 178 """Do the basic steps to configure me.
179 179
180 180 Override in subclasses.
181 181 """
182 182 self.parse_command_line(argv)
183 183
184 184
185 185 def start(self):
186 186 """Start the app mainloop.
187 187
188 188 Override in subclasses.
189 189 """
190 190 if self.subapp is not None:
191 191 return self.subapp.start()
192 192
193 193 def print_alias_help(self):
194 194 """Print the alias part of the help."""
195 195 if not self.aliases:
196 196 return
197 197
198 198 lines = []
199 199 classdict = {}
200 200 for cls in self.classes:
201 201 # include all parents (up to, but excluding Configurable) in available names
202 202 for c in cls.mro()[:-3]:
203 203 classdict[c.__name__] = c
204 204
205 205 for alias, longname in self.aliases.iteritems():
206 206 classname, traitname = longname.split('.',1)
207 207 cls = classdict[classname]
208 208
209 209 trait = cls.class_traits(config=True)[traitname]
210 210 help = cls.class_get_trait_help(trait).splitlines()
211 211 # reformat first line
212 212 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
213 213 lines.extend(help)
214 214 # lines.append('')
215 215 print os.linesep.join(lines)
216 216
217 217 def print_flag_help(self):
218 218 """Print the flag part of the help."""
219 219 if not self.flags:
220 220 return
221 221
222 222 lines = []
223 223 for m, (cfg,help) in self.flags.iteritems():
224 224 lines.append('--'+m)
225 225 lines.append(indent(dedent(help.strip())))
226 226 # lines.append('')
227 227 print os.linesep.join(lines)
228 228
229 229 def print_options(self):
230 230 if not self.flags and not self.aliases:
231 231 return
232 232 lines = ['Options']
233 233 lines.append('-'*len(lines[0]))
234 234 lines.append('')
235 235 for p in wrap_paragraphs(self.option_description):
236 236 lines.append(p)
237 237 lines.append('')
238 238 print os.linesep.join(lines)
239 239 self.print_flag_help()
240 240 self.print_alias_help()
241 241 print
242 242
243 243 def print_subcommands(self):
244 244 """Print the subcommand part of the help."""
245 245 if not self.subcommands:
246 246 return
247 247
248 248 lines = ["Subcommands"]
249 249 lines.append('-'*len(lines[0]))
250 250 lines.append('')
251 251 for p in wrap_paragraphs(self.subcommand_description):
252 252 lines.append(p)
253 253 lines.append('')
254 254 for subc, (cls, help) in self.subcommands.iteritems():
255 255 lines.append(subc)
256 256 if help:
257 257 lines.append(indent(dedent(help.strip())))
258 258 lines.append('')
259 259 print os.linesep.join(lines)
260 260
261 261 def print_help(self, classes=False):
262 262 """Print the help for each Configurable class in self.classes.
263 263
264 264 If classes=False (the default), only flags and aliases are printed.
265 265 """
266 266 self.print_subcommands()
267 267 self.print_options()
268 268
269 269 if classes:
270 270 if self.classes:
271 271 print "Class parameters"
272 272 print "----------------"
273 273 print
274 274 for p in wrap_paragraphs(self.keyvalue_description):
275 275 print p
276 276 print
277 277
278 278 for cls in self.classes:
279 279 cls.class_print_help()
280 280 print
281 281 else:
282 282 print "To see all available configurables, use `--help-all`"
283 283 print
284 284
285 285 def print_description(self):
286 286 """Print the application description."""
287 287 for p in wrap_paragraphs(self.description):
288 288 print p
289 289 print
290 290
291 291 def print_examples(self):
292 292 """Print usage and examples.
293 293
294 294 This usage string goes at the end of the command line help string
295 295 and should contain examples of the application's usage.
296 296 """
297 297 if self.examples:
298 298 print "Examples"
299 299 print "--------"
300 300 print
301 301 print indent(dedent(self.examples.strip()))
302 302 print
303 303
304 304 def print_version(self):
305 305 """Print the version string."""
306 306 print self.version
307 307
308 308 def update_config(self, config):
309 309 """Fire the traits events when the config is updated."""
310 310 # Save a copy of the current config.
311 311 newconfig = deepcopy(self.config)
312 312 # Merge the new config into the current one.
313 313 newconfig._merge(config)
314 314 # Save the combined config as self.config, which triggers the traits
315 315 # events.
316 316 self.config = newconfig
317 317
318 318 def initialize_subcommand(self, subc, argv=None):
319 319 """Initialize a subcommand with argv."""
320 320 subapp,help = self.subcommands.get(subc)
321 321
322 322 if isinstance(subapp, basestring):
323 323 subapp = import_item(subapp)
324 324
325 325 # clear existing instances
326 326 self.__class__.clear_instance()
327 327 # instantiate
328 328 self.subapp = subapp.instance()
329 329 # and initialize subapp
330 330 self.subapp.initialize(argv)
331 331
332 332 def parse_command_line(self, argv=None):
333 333 """Parse the command line arguments."""
334 334 argv = sys.argv[1:] if argv is None else argv
335 335
336 336 if self.subcommands and len(argv) > 0:
337 337 # we have subcommands, and one may have been specified
338 338 subc, subargv = argv[0], argv[1:]
339 339 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
340 340 # it's a subcommand, and *not* a flag or class parameter
341 341 return self.initialize_subcommand(subc, subargv)
342 342
343 343 if '-h' in argv or '--help' in argv or '--help-all' in argv:
344 344 self.print_description()
345 345 self.print_help('--help-all' in argv)
346 346 self.print_examples()
347 347 self.exit(0)
348 348
349 349 if '--version' in argv:
350 350 self.print_version()
351 351 self.exit(0)
352 352
353 353 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
354 354 flags=self.flags)
355 355 try:
356 356 config = loader.load_config()
357 357 self.update_config(config)
358 358 except (TraitError, ArgumentError) as e:
359 359 self.print_description()
360 360 self.print_help()
361 361 self.print_examples()
362 362 self.log.fatal(str(e))
363 363 self.exit(1)
364 364 # store unparsed args in extra_args
365 365 self.extra_args = loader.extra_args
366 366
367 367 def load_config_file(self, filename, path=None):
368 368 """Load a .py based config file by filename and path."""
369 369 loader = PyFileConfigLoader(filename, path=path)
370 370 try:
371 371 config = loader.load_config()
372 372 except IOError:
373 373 # problem with the file (probably doesn't exist), raise
374 374 raise
375 375 except Exception:
376 # try to get the full filename, but it will be empty in the
377 # unlikely event that the error raised before filefind finished
378 filename = loader.full_filename or filename
376 379 # problem while running the file
377 self.log.error("Exception while loading config file %s [path=%s]"%
378 (filename, path), exc_info=True)
380 self.log.error("Exception while loading config file %s",
381 filename, exc_info=True)
379 382 else:
383 self.log.debug("Loaded config file: %s", loader.full_filename)
380 384 self.update_config(config)
381 385
382 386 def generate_config_file(self):
383 387 """generate default config file from Configurables"""
384 388 lines = ["# Configuration file for %s."%self.name]
385 389 lines.append('')
386 390 lines.append('c = get_config()')
387 391 lines.append('')
388 392 for cls in self.classes:
389 393 lines.append(cls.class_config_section())
390 394 return '\n'.join(lines)
391 395
392 396 def exit(self, exit_status=0):
393 397 self.log.debug("Exiting application: %s" % self.name)
394 398 sys.exit(exit_status)
395 399
396 400 #-----------------------------------------------------------------------------
397 401 # utility functions, for convenience
398 402 #-----------------------------------------------------------------------------
399 403
400 404 def boolean_flag(name, configurable, set_help='', unset_help=''):
401 405 """Helper for building basic --trait, --no-trait flags.
402 406
403 407 Parameters
404 408 ----------
405 409
406 410 name : str
407 411 The name of the flag.
408 412 configurable : str
409 413 The 'Class.trait' string of the trait to be set/unset with the flag
410 414 set_help : unicode
411 415 help string for --name flag
412 416 unset_help : unicode
413 417 help string for --no-name flag
414 418
415 419 Returns
416 420 -------
417 421
418 422 cfg : dict
419 423 A dict with two keys: 'name', and 'no-name', for setting and unsetting
420 424 the trait, respectively.
421 425 """
422 426 # default helpstrings
423 427 set_help = set_help or "set %s=True"%configurable
424 428 unset_help = unset_help or "set %s=False"%configurable
425 429
426 430 cls,trait = configurable.split('.')
427 431
428 432 setter = {cls : {trait : True}}
429 433 unsetter = {cls : {trait : False}}
430 434 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
431 435
@@ -1,309 +1,313 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 glob
31 31 import logging
32 32 import os
33 33 import shutil
34 34 import sys
35 35
36 36 from IPython.config.application import Application
37 37 from IPython.config.configurable import Configurable
38 38 from IPython.config.loader import Config
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 42 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict
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 }
60 60
61 61 base_flags = dict(
62 62 debug = ({'Application' : {'log_level' : logging.DEBUG}},
63 63 "set log level to logging.DEBUG (maximize logging output)"),
64 64 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
65 65 "set log level to logging.CRITICAL (minimize logging output)"),
66 66 init = ({'BaseIPythonApplication' : {
67 67 'copy_config_files' : True,
68 68 'auto_create' : True}
69 69 }, """Initialize profile with default config files. This is equivalent
70 70 to running `ipython profile create <profile>` prior to startup.
71 71 """)
72 72 )
73 73
74 74
75 75 class BaseIPythonApplication(Application):
76 76
77 77 name = Unicode(u'ipython')
78 78 description = Unicode(u'IPython: an enhanced interactive Python shell.')
79 79 version = Unicode(release.version)
80 80
81 81 aliases = Dict(base_aliases)
82 82 flags = Dict(base_flags)
83 83 classes = List([ProfileDir])
84 84
85 85 # Track whether the config_file has changed,
86 86 # because some logic happens only if we aren't using the default.
87 87 config_file_specified = Bool(False)
88 88
89 89 config_file_name = Unicode(u'ipython_config.py')
90 90 def _config_file_name_default(self):
91 91 return self.name.replace('-','_') + u'_config.py'
92 92 def _config_file_name_changed(self, name, old, new):
93 93 if new != old:
94 94 self.config_file_specified = True
95 95
96 96 # The directory that contains IPython's builtin profiles.
97 97 builtin_profile_dir = Unicode(
98 98 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
99 99 )
100 100
101 101 config_file_paths = List(Unicode)
102 102 def _config_file_paths_default(self):
103 103 return [os.getcwdu()]
104 104
105 105 profile = Unicode(u'default', config=True,
106 106 help="""The IPython profile to use."""
107 107 )
108 108 def _profile_changed(self, name, old, new):
109 109 self.builtin_profile_dir = os.path.join(
110 110 get_ipython_package_dir(), u'config', u'profile', new
111 111 )
112 112
113 113 ipython_dir = Unicode(get_ipython_dir(), config=True,
114 114 help="""
115 115 The name of the IPython directory. This directory is used for logging
116 116 configuration (through profiles), history storage, etc. The default
117 117 is usually $HOME/.ipython. This options can also be specified through
118 118 the environment variable IPYTHON_DIR.
119 119 """
120 120 )
121 121
122 122 overwrite = Bool(False, config=True,
123 123 help="""Whether to overwrite existing config files when copying""")
124 124 auto_create = Bool(False, config=True,
125 125 help="""Whether to create profile dir if it doesn't exist""")
126 126
127 127 config_files = List(Unicode)
128 128 def _config_files_default(self):
129 129 return [u'ipython_config.py']
130 130
131 131 copy_config_files = Bool(False, config=True,
132 132 help="""Whether to install the default config files into the profile dir.
133 133 If a new profile is being created, and IPython contains config files for that
134 134 profile, then they will be staged into the new directory. Otherwise,
135 135 default config files will be automatically generated.
136 136 """)
137 137
138 138 # The class to use as the crash handler.
139 139 crash_handler_class = Type(crashhandler.CrashHandler)
140 140
141 141 def __init__(self, **kwargs):
142 142 super(BaseIPythonApplication, self).__init__(**kwargs)
143 143 # ensure even default IPYTHON_DIR exists
144 144 if not os.path.exists(self.ipython_dir):
145 145 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
146 146
147 147 #-------------------------------------------------------------------------
148 148 # Various stages of Application creation
149 149 #-------------------------------------------------------------------------
150 150
151 151 def init_crash_handler(self):
152 152 """Create a crash handler, typically setting sys.excepthook to it."""
153 153 self.crash_handler = self.crash_handler_class(self)
154 154 sys.excepthook = self.crash_handler
155 155
156 156 def _ipython_dir_changed(self, name, old, new):
157 157 if old in sys.path:
158 158 sys.path.remove(old)
159 159 sys.path.append(os.path.abspath(new))
160 160 if not os.path.isdir(new):
161 161 os.makedirs(new, mode=0777)
162 162 readme = os.path.join(new, 'README')
163 163 if not os.path.exists(readme):
164 164 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
165 165 shutil.copy(os.path.join(path, 'README'), readme)
166 166 self.log.debug("IPYTHON_DIR set to: %s" % new)
167 167
168 168 def load_config_file(self, suppress_errors=True):
169 169 """Load the config file.
170 170
171 171 By default, errors in loading config are handled, and a warning
172 172 printed on screen. For testing, the suppress_errors option is set
173 173 to False, so errors will make tests fail.
174 174 """
175 self.log.debug("Searching path %s for config files", self.config_file_paths)
175 176 base_config = 'ipython_config.py'
176 177 self.log.debug("Attempting to load config file: %s" %
177 178 base_config)
178 179 try:
179 180 Application.load_config_file(
180 181 self,
181 182 base_config,
182 183 path=self.config_file_paths
183 184 )
184 185 except IOError:
185 186 # ignore errors loading parent
187 self.log.debug("Config file %s not found", base_config)
186 188 pass
187 189 if self.config_file_name == base_config:
188 190 # don't load secondary config
189 191 return
190 192 self.log.debug("Attempting to load config file: %s" %
191 193 self.config_file_name)
192 194 try:
193 195 Application.load_config_file(
194 196 self,
195 197 self.config_file_name,
196 198 path=self.config_file_paths
197 199 )
198 200 except IOError:
199 201 # Only warn if the default config file was NOT being used.
200 202 if self.config_file_specified:
201 self.log.warn("Config file not found, skipping: %s" %
202 self.config_file_name)
203 msg = self.log.warn
204 else:
205 msg = self.log.debug
206 msg("Config file not found, skipping: %s", self.config_file_name)
203 207 except:
204 208 # For testing purposes.
205 209 if not suppress_errors:
206 210 raise
207 211 self.log.warn("Error loading config file: %s" %
208 212 self.config_file_name, exc_info=True)
209 213
210 214 def init_profile_dir(self):
211 215 """initialize the profile dir"""
212 216 try:
213 217 # location explicitly specified:
214 218 location = self.config.ProfileDir.location
215 219 except AttributeError:
216 220 # location not specified, find by profile name
217 221 try:
218 222 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
219 223 except ProfileDirError:
220 224 # not found, maybe create it (always create default profile)
221 225 if self.auto_create or self.profile=='default':
222 226 try:
223 227 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
224 228 except ProfileDirError:
225 229 self.log.fatal("Could not create profile: %r"%self.profile)
226 230 self.exit(1)
227 231 else:
228 232 self.log.info("Created profile dir: %r"%p.location)
229 233 else:
230 234 self.log.fatal("Profile %r not found."%self.profile)
231 235 self.exit(1)
232 236 else:
233 237 self.log.info("Using existing profile dir: %r"%p.location)
234 238 else:
235 239 # location is fully specified
236 240 try:
237 241 p = ProfileDir.find_profile_dir(location, self.config)
238 242 except ProfileDirError:
239 243 # not found, maybe create it
240 244 if self.auto_create:
241 245 try:
242 246 p = ProfileDir.create_profile_dir(location, self.config)
243 247 except ProfileDirError:
244 248 self.log.fatal("Could not create profile directory: %r"%location)
245 249 self.exit(1)
246 250 else:
247 251 self.log.info("Creating new profile dir: %r"%location)
248 252 else:
249 253 self.log.fatal("Profile directory %r not found."%location)
250 254 self.exit(1)
251 255 else:
252 256 self.log.info("Using existing profile dir: %r"%location)
253 257
254 258 self.profile_dir = p
255 259 self.config_file_paths.append(p.location)
256 260
257 261 def init_config_files(self):
258 262 """[optionally] copy default config files into profile dir."""
259 263 # copy config files
260 264 path = self.builtin_profile_dir
261 265 if self.copy_config_files:
262 266 src = self.profile
263 267
264 268 cfg = self.config_file_name
265 269 if path and os.path.exists(os.path.join(path, cfg)):
266 270 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
267 271 cfg, src, self.profile_dir.location, self.overwrite)
268 272 )
269 273 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
270 274 else:
271 275 self.stage_default_config_file()
272 276 else:
273 277 # Still stage *bundled* config files, but not generated ones
274 278 # This is necessary for `ipython profile=sympy` to load the profile
275 279 # on the first go
276 280 files = glob.glob(os.path.join(path, '*.py'))
277 281 for fullpath in files:
278 282 cfg = os.path.basename(fullpath)
279 283 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
280 284 # file was copied
281 285 self.log.warn("Staging bundled %s from %s into %r"%(
282 286 cfg, self.profile, self.profile_dir.location)
283 287 )
284 288
285 289
286 290 def stage_default_config_file(self):
287 291 """auto generate default config file, and stage it into the profile."""
288 292 s = self.generate_config_file()
289 293 fname = os.path.join(self.profile_dir.location, self.config_file_name)
290 294 if self.overwrite or not os.path.exists(fname):
291 295 self.log.warn("Generating default config file: %r"%(fname))
292 296 with open(fname, 'w') as f:
293 297 f.write(s)
294 298
295 299
296 300 def initialize(self, argv=None):
297 301 # don't hook up crash handler before parsing command-line
298 302 self.parse_command_line(argv)
299 303 self.init_crash_handler()
300 304 if self.subapp is not None:
301 305 # stop here if subapp is taking over
302 306 return
303 307 cl_config = self.config
304 308 self.init_profile_dir()
305 309 self.init_config_files()
306 310 self.load_config_file()
307 311 # enforce cl-opts override configfile opts:
308 312 self.update_config(cl_config)
309 313
General Comments 0
You need to be logged in to leave comments. Login now