##// END OF EJS Templates
allow to load config from json file...
Matthias BUSSONNIER -
Show More
@@ -0,0 +1,3 b''
1 * IPython config objects can be loaded from and serialized to JSON.
2 JSON config file have the same base name as their ``.py`` counterpart,
3 and will be loaded with higher priority if found.
@@ -1,582 +1,600 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A base class for a configurable application.
3 A base class for a configurable application.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Min RK
8 * Min RK
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2011 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import logging
23 import logging
24 import os
24 import os
25 import re
25 import re
26 import sys
26 import sys
27 from copy import deepcopy
27 from copy import deepcopy
28 from collections import defaultdict
28 from collections import defaultdict
29
29
30 from IPython.external.decorator import decorator
30 from IPython.external.decorator import decorator
31
31
32 from IPython.config.configurable import SingletonConfigurable
32 from IPython.config.configurable import SingletonConfigurable
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound,
34 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
35 )
35 )
36
36
37 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
38 Unicode, List, Enum, Dict, Instance, TraitError
38 Unicode, List, Enum, Dict, Instance, TraitError
39 )
39 )
40 from IPython.utils.importstring import import_item
40 from IPython.utils.importstring import import_item
41 from IPython.utils.text import indent, wrap_paragraphs, dedent
41 from IPython.utils.text import indent, wrap_paragraphs, dedent
42 from IPython.utils import py3compat
42 from IPython.utils import py3compat
43 from IPython.utils.py3compat import string_types, iteritems
43 from IPython.utils.py3compat import string_types, iteritems
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # function for re-wrapping a helpstring
46 # function for re-wrapping a helpstring
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Descriptions for the various sections
50 # Descriptions for the various sections
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 # merge flags&aliases into options
53 # merge flags&aliases into options
54 option_description = """
54 option_description = """
55 Arguments that take values are actually convenience aliases to full
55 Arguments that take values are actually convenience aliases to full
56 Configurables, whose aliases are listed on the help line. For more information
56 Configurables, whose aliases are listed on the help line. For more information
57 on full configurables, see '--help-all'.
57 on full configurables, see '--help-all'.
58 """.strip() # trim newlines of front and back
58 """.strip() # trim newlines of front and back
59
59
60 keyvalue_description = """
60 keyvalue_description = """
61 Parameters are set from command-line arguments of the form:
61 Parameters are set from command-line arguments of the form:
62 `--Class.trait=value`.
62 `--Class.trait=value`.
63 This line is evaluated in Python, so simple expressions are allowed, e.g.::
63 This line is evaluated in Python, so simple expressions are allowed, e.g.::
64 `--C.a='range(3)'` For setting C.a=[0,1,2].
64 `--C.a='range(3)'` For setting C.a=[0,1,2].
65 """.strip() # trim newlines of front and back
65 """.strip() # trim newlines of front and back
66
66
67 # sys.argv can be missing, for example when python is embedded. See the docs
67 # sys.argv can be missing, for example when python is embedded. See the docs
68 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
68 # for details: http://docs.python.org/2/c-api/intro.html#embedding-python
69 if not hasattr(sys, "argv"):
69 if not hasattr(sys, "argv"):
70 sys.argv = [""]
70 sys.argv = [""]
71
71
72 subcommand_description = """
72 subcommand_description = """
73 Subcommands are launched as `{app} cmd [args]`. For information on using
73 Subcommands are launched as `{app} cmd [args]`. For information on using
74 subcommand 'cmd', do: `{app} cmd -h`.
74 subcommand 'cmd', do: `{app} cmd -h`.
75 """.strip().format(app=os.path.basename(sys.argv[0]))
75 """.strip().format(app=os.path.basename(sys.argv[0]))
76 # get running program name
76 # get running program name
77
77
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79 # Application class
79 # Application class
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81
81
82 @decorator
82 @decorator
83 def catch_config_error(method, app, *args, **kwargs):
83 def catch_config_error(method, app, *args, **kwargs):
84 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
84 """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
85
85
86 On a TraitError (generally caused by bad config), this will print the trait's
86 On a TraitError (generally caused by bad config), this will print the trait's
87 message, and exit the app.
87 message, and exit the app.
88
88
89 For use on init methods, to prevent invoking excepthook on invalid input.
89 For use on init methods, to prevent invoking excepthook on invalid input.
90 """
90 """
91 try:
91 try:
92 return method(app, *args, **kwargs)
92 return method(app, *args, **kwargs)
93 except (TraitError, ArgumentError) as e:
93 except (TraitError, ArgumentError) as e:
94 app.print_help()
94 app.print_help()
95 app.log.fatal("Bad config encountered during initialization:")
95 app.log.fatal("Bad config encountered during initialization:")
96 app.log.fatal(str(e))
96 app.log.fatal(str(e))
97 app.log.debug("Config at the time: %s", app.config)
97 app.log.debug("Config at the time: %s", app.config)
98 app.exit(1)
98 app.exit(1)
99
99
100
100
101 class ApplicationError(Exception):
101 class ApplicationError(Exception):
102 pass
102 pass
103
103
104 class LevelFormatter(logging.Formatter):
104 class LevelFormatter(logging.Formatter):
105 """Formatter with additional `highlevel` record
105 """Formatter with additional `highlevel` record
106
106
107 This field is empty if log level is less than highlevel_limit,
107 This field is empty if log level is less than highlevel_limit,
108 otherwise it is formatted with self.highlevel_format.
108 otherwise it is formatted with self.highlevel_format.
109
109
110 Useful for adding 'WARNING' to warning messages,
110 Useful for adding 'WARNING' to warning messages,
111 without adding 'INFO' to info, etc.
111 without adding 'INFO' to info, etc.
112 """
112 """
113 highlevel_limit = logging.WARN
113 highlevel_limit = logging.WARN
114 highlevel_format = " %(levelname)s |"
114 highlevel_format = " %(levelname)s |"
115
115
116 def format(self, record):
116 def format(self, record):
117 if record.levelno >= self.highlevel_limit:
117 if record.levelno >= self.highlevel_limit:
118 record.highlevel = self.highlevel_format % record.__dict__
118 record.highlevel = self.highlevel_format % record.__dict__
119 else:
119 else:
120 record.highlevel = ""
120 record.highlevel = ""
121 return super(LevelFormatter, self).format(record)
121 return super(LevelFormatter, self).format(record)
122
122
123
123
124 class Application(SingletonConfigurable):
124 class Application(SingletonConfigurable):
125 """A singleton application with full configuration support."""
125 """A singleton application with full configuration support."""
126
126
127 # The name of the application, will usually match the name of the command
127 # The name of the application, will usually match the name of the command
128 # line application
128 # line application
129 name = Unicode(u'application')
129 name = Unicode(u'application')
130
130
131 # The description of the application that is printed at the beginning
131 # The description of the application that is printed at the beginning
132 # of the help.
132 # of the help.
133 description = Unicode(u'This is an application.')
133 description = Unicode(u'This is an application.')
134 # default section descriptions
134 # default section descriptions
135 option_description = Unicode(option_description)
135 option_description = Unicode(option_description)
136 keyvalue_description = Unicode(keyvalue_description)
136 keyvalue_description = Unicode(keyvalue_description)
137 subcommand_description = Unicode(subcommand_description)
137 subcommand_description = Unicode(subcommand_description)
138
138
139 # The usage and example string that goes at the end of the help string.
139 # The usage and example string that goes at the end of the help string.
140 examples = Unicode()
140 examples = Unicode()
141
141
142 # A sequence of Configurable subclasses whose config=True attributes will
142 # A sequence of Configurable subclasses whose config=True attributes will
143 # be exposed at the command line.
143 # be exposed at the command line.
144 classes = List([])
144 classes = List([])
145
145
146 # The version string of this application.
146 # The version string of this application.
147 version = Unicode(u'0.0')
147 version = Unicode(u'0.0')
148
148
149 # the argv used to initialize the application
149 # the argv used to initialize the application
150 argv = List()
150 argv = List()
151
151
152 # The log level for the application
152 # The log level for the application
153 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
153 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
154 default_value=logging.WARN,
154 default_value=logging.WARN,
155 config=True,
155 config=True,
156 help="Set the log level by value or name.")
156 help="Set the log level by value or name.")
157 def _log_level_changed(self, name, old, new):
157 def _log_level_changed(self, name, old, new):
158 """Adjust the log level when log_level is set."""
158 """Adjust the log level when log_level is set."""
159 if isinstance(new, string_types):
159 if isinstance(new, string_types):
160 new = getattr(logging, new)
160 new = getattr(logging, new)
161 self.log_level = new
161 self.log_level = new
162 self.log.setLevel(new)
162 self.log.setLevel(new)
163
163
164 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
164 log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True,
165 help="The date format used by logging formatters for %(asctime)s"
165 help="The date format used by logging formatters for %(asctime)s"
166 )
166 )
167 def _log_datefmt_changed(self, name, old, new):
167 def _log_datefmt_changed(self, name, old, new):
168 self._log_format_changed()
168 self._log_format_changed()
169
169
170 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
170 log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True,
171 help="The Logging format template",
171 help="The Logging format template",
172 )
172 )
173 def _log_format_changed(self, name, old, new):
173 def _log_format_changed(self, name, old, new):
174 """Change the log formatter when log_format is set."""
174 """Change the log formatter when log_format is set."""
175 _log_handler = self.log.handlers[0]
175 _log_handler = self.log.handlers[0]
176 _log_formatter = LevelFormatter(new, datefmt=self.log_datefmt)
176 _log_formatter = LevelFormatter(new, datefmt=self.log_datefmt)
177 _log_handler.setFormatter(_log_formatter)
177 _log_handler.setFormatter(_log_formatter)
178
178
179 log = Instance(logging.Logger)
179 log = Instance(logging.Logger)
180 def _log_default(self):
180 def _log_default(self):
181 """Start logging for this application.
181 """Start logging for this application.
182
182
183 The default is to log to stderr using a StreamHandler, if no default
183 The default is to log to stderr using a StreamHandler, if no default
184 handler already exists. The log level starts at logging.WARN, but this
184 handler already exists. The log level starts at logging.WARN, but this
185 can be adjusted by setting the ``log_level`` attribute.
185 can be adjusted by setting the ``log_level`` attribute.
186 """
186 """
187 log = logging.getLogger(self.__class__.__name__)
187 log = logging.getLogger(self.__class__.__name__)
188 log.setLevel(self.log_level)
188 log.setLevel(self.log_level)
189 log.propagate = False
189 log.propagate = False
190 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
190 _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
191 while _log:
191 while _log:
192 if _log.handlers:
192 if _log.handlers:
193 return log
193 return log
194 if not _log.propagate:
194 if not _log.propagate:
195 break
195 break
196 else:
196 else:
197 _log = _log.parent
197 _log = _log.parent
198 if sys.executable.endswith('pythonw.exe'):
198 if sys.executable.endswith('pythonw.exe'):
199 # this should really go to a file, but file-logging is only
199 # this should really go to a file, but file-logging is only
200 # hooked up in parallel applications
200 # hooked up in parallel applications
201 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
201 _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
202 else:
202 else:
203 _log_handler = logging.StreamHandler()
203 _log_handler = logging.StreamHandler()
204 _log_formatter = LevelFormatter(self.log_format, datefmt=self.log_datefmt)
204 _log_formatter = LevelFormatter(self.log_format, datefmt=self.log_datefmt)
205 _log_handler.setFormatter(_log_formatter)
205 _log_handler.setFormatter(_log_formatter)
206 log.addHandler(_log_handler)
206 log.addHandler(_log_handler)
207 return log
207 return log
208
208
209 # the alias map for configurables
209 # the alias map for configurables
210 aliases = Dict({'log-level' : 'Application.log_level'})
210 aliases = Dict({'log-level' : 'Application.log_level'})
211
211
212 # flags for loading Configurables or store_const style flags
212 # flags for loading Configurables or store_const style flags
213 # flags are loaded from this dict by '--key' flags
213 # flags are loaded from this dict by '--key' flags
214 # this must be a dict of two-tuples, the first element being the Config/dict
214 # this must be a dict of two-tuples, the first element being the Config/dict
215 # and the second being the help string for the flag
215 # and the second being the help string for the flag
216 flags = Dict()
216 flags = Dict()
217 def _flags_changed(self, name, old, new):
217 def _flags_changed(self, name, old, new):
218 """ensure flags dict is valid"""
218 """ensure flags dict is valid"""
219 for key,value in iteritems(new):
219 for key,value in iteritems(new):
220 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
220 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
221 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
221 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
222 assert isinstance(value[1], string_types), "Bad flag: %r:%s"%(key,value)
222 assert isinstance(value[1], string_types), "Bad flag: %r:%s"%(key,value)
223
223
224
224
225 # subcommands for launching other applications
225 # subcommands for launching other applications
226 # if this is not empty, this will be a parent Application
226 # if this is not empty, this will be a parent Application
227 # this must be a dict of two-tuples,
227 # this must be a dict of two-tuples,
228 # the first element being the application class/import string
228 # the first element being the application class/import string
229 # and the second being the help string for the subcommand
229 # and the second being the help string for the subcommand
230 subcommands = Dict()
230 subcommands = Dict()
231 # parse_command_line will initialize a subapp, if requested
231 # parse_command_line will initialize a subapp, if requested
232 subapp = Instance('IPython.config.application.Application', allow_none=True)
232 subapp = Instance('IPython.config.application.Application', allow_none=True)
233
233
234 # extra command-line arguments that don't set config values
234 # extra command-line arguments that don't set config values
235 extra_args = List(Unicode)
235 extra_args = List(Unicode)
236
236
237
237
238 def __init__(self, **kwargs):
238 def __init__(self, **kwargs):
239 SingletonConfigurable.__init__(self, **kwargs)
239 SingletonConfigurable.__init__(self, **kwargs)
240 # Ensure my class is in self.classes, so my attributes appear in command line
240 # Ensure my class is in self.classes, so my attributes appear in command line
241 # options and config files.
241 # options and config files.
242 if self.__class__ not in self.classes:
242 if self.__class__ not in self.classes:
243 self.classes.insert(0, self.__class__)
243 self.classes.insert(0, self.__class__)
244
244
245 def _config_changed(self, name, old, new):
245 def _config_changed(self, name, old, new):
246 SingletonConfigurable._config_changed(self, name, old, new)
246 SingletonConfigurable._config_changed(self, name, old, new)
247 self.log.debug('Config changed:')
247 self.log.debug('Config changed:')
248 self.log.debug(repr(new))
248 self.log.debug(repr(new))
249
249
250 @catch_config_error
250 @catch_config_error
251 def initialize(self, argv=None):
251 def initialize(self, argv=None):
252 """Do the basic steps to configure me.
252 """Do the basic steps to configure me.
253
253
254 Override in subclasses.
254 Override in subclasses.
255 """
255 """
256 self.parse_command_line(argv)
256 self.parse_command_line(argv)
257
257
258
258
259 def start(self):
259 def start(self):
260 """Start the app mainloop.
260 """Start the app mainloop.
261
261
262 Override in subclasses.
262 Override in subclasses.
263 """
263 """
264 if self.subapp is not None:
264 if self.subapp is not None:
265 return self.subapp.start()
265 return self.subapp.start()
266
266
267 def print_alias_help(self):
267 def print_alias_help(self):
268 """Print the alias part of the help."""
268 """Print the alias part of the help."""
269 if not self.aliases:
269 if not self.aliases:
270 return
270 return
271
271
272 lines = []
272 lines = []
273 classdict = {}
273 classdict = {}
274 for cls in self.classes:
274 for cls in self.classes:
275 # include all parents (up to, but excluding Configurable) in available names
275 # include all parents (up to, but excluding Configurable) in available names
276 for c in cls.mro()[:-3]:
276 for c in cls.mro()[:-3]:
277 classdict[c.__name__] = c
277 classdict[c.__name__] = c
278
278
279 for alias, longname in iteritems(self.aliases):
279 for alias, longname in iteritems(self.aliases):
280 classname, traitname = longname.split('.',1)
280 classname, traitname = longname.split('.',1)
281 cls = classdict[classname]
281 cls = classdict[classname]
282
282
283 trait = cls.class_traits(config=True)[traitname]
283 trait = cls.class_traits(config=True)[traitname]
284 help = cls.class_get_trait_help(trait).splitlines()
284 help = cls.class_get_trait_help(trait).splitlines()
285 # reformat first line
285 # reformat first line
286 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
286 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
287 if len(alias) == 1:
287 if len(alias) == 1:
288 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
288 help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
289 lines.extend(help)
289 lines.extend(help)
290 # lines.append('')
290 # lines.append('')
291 print(os.linesep.join(lines))
291 print(os.linesep.join(lines))
292
292
293 def print_flag_help(self):
293 def print_flag_help(self):
294 """Print the flag part of the help."""
294 """Print the flag part of the help."""
295 if not self.flags:
295 if not self.flags:
296 return
296 return
297
297
298 lines = []
298 lines = []
299 for m, (cfg,help) in iteritems(self.flags):
299 for m, (cfg,help) in iteritems(self.flags):
300 prefix = '--' if len(m) > 1 else '-'
300 prefix = '--' if len(m) > 1 else '-'
301 lines.append(prefix+m)
301 lines.append(prefix+m)
302 lines.append(indent(dedent(help.strip())))
302 lines.append(indent(dedent(help.strip())))
303 # lines.append('')
303 # lines.append('')
304 print(os.linesep.join(lines))
304 print(os.linesep.join(lines))
305
305
306 def print_options(self):
306 def print_options(self):
307 if not self.flags and not self.aliases:
307 if not self.flags and not self.aliases:
308 return
308 return
309 lines = ['Options']
309 lines = ['Options']
310 lines.append('-'*len(lines[0]))
310 lines.append('-'*len(lines[0]))
311 lines.append('')
311 lines.append('')
312 for p in wrap_paragraphs(self.option_description):
312 for p in wrap_paragraphs(self.option_description):
313 lines.append(p)
313 lines.append(p)
314 lines.append('')
314 lines.append('')
315 print(os.linesep.join(lines))
315 print(os.linesep.join(lines))
316 self.print_flag_help()
316 self.print_flag_help()
317 self.print_alias_help()
317 self.print_alias_help()
318 print()
318 print()
319
319
320 def print_subcommands(self):
320 def print_subcommands(self):
321 """Print the subcommand part of the help."""
321 """Print the subcommand part of the help."""
322 if not self.subcommands:
322 if not self.subcommands:
323 return
323 return
324
324
325 lines = ["Subcommands"]
325 lines = ["Subcommands"]
326 lines.append('-'*len(lines[0]))
326 lines.append('-'*len(lines[0]))
327 lines.append('')
327 lines.append('')
328 for p in wrap_paragraphs(self.subcommand_description):
328 for p in wrap_paragraphs(self.subcommand_description):
329 lines.append(p)
329 lines.append(p)
330 lines.append('')
330 lines.append('')
331 for subc, (cls, help) in iteritems(self.subcommands):
331 for subc, (cls, help) in iteritems(self.subcommands):
332 lines.append(subc)
332 lines.append(subc)
333 if help:
333 if help:
334 lines.append(indent(dedent(help.strip())))
334 lines.append(indent(dedent(help.strip())))
335 lines.append('')
335 lines.append('')
336 print(os.linesep.join(lines))
336 print(os.linesep.join(lines))
337
337
338 def print_help(self, classes=False):
338 def print_help(self, classes=False):
339 """Print the help for each Configurable class in self.classes.
339 """Print the help for each Configurable class in self.classes.
340
340
341 If classes=False (the default), only flags and aliases are printed.
341 If classes=False (the default), only flags and aliases are printed.
342 """
342 """
343 self.print_description()
343 self.print_description()
344 self.print_subcommands()
344 self.print_subcommands()
345 self.print_options()
345 self.print_options()
346
346
347 if classes:
347 if classes:
348 if self.classes:
348 if self.classes:
349 print("Class parameters")
349 print("Class parameters")
350 print("----------------")
350 print("----------------")
351 print()
351 print()
352 for p in wrap_paragraphs(self.keyvalue_description):
352 for p in wrap_paragraphs(self.keyvalue_description):
353 print(p)
353 print(p)
354 print()
354 print()
355
355
356 for cls in self.classes:
356 for cls in self.classes:
357 cls.class_print_help()
357 cls.class_print_help()
358 print()
358 print()
359 else:
359 else:
360 print("To see all available configurables, use `--help-all`")
360 print("To see all available configurables, use `--help-all`")
361 print()
361 print()
362
362
363 self.print_examples()
363 self.print_examples()
364
364
365
365
366 def print_description(self):
366 def print_description(self):
367 """Print the application description."""
367 """Print the application description."""
368 for p in wrap_paragraphs(self.description):
368 for p in wrap_paragraphs(self.description):
369 print(p)
369 print(p)
370 print()
370 print()
371
371
372 def print_examples(self):
372 def print_examples(self):
373 """Print usage and examples.
373 """Print usage and examples.
374
374
375 This usage string goes at the end of the command line help string
375 This usage string goes at the end of the command line help string
376 and should contain examples of the application's usage.
376 and should contain examples of the application's usage.
377 """
377 """
378 if self.examples:
378 if self.examples:
379 print("Examples")
379 print("Examples")
380 print("--------")
380 print("--------")
381 print()
381 print()
382 print(indent(dedent(self.examples.strip())))
382 print(indent(dedent(self.examples.strip())))
383 print()
383 print()
384
384
385 def print_version(self):
385 def print_version(self):
386 """Print the version string."""
386 """Print the version string."""
387 print(self.version)
387 print(self.version)
388
388
389 def update_config(self, config):
389 def update_config(self, config):
390 """Fire the traits events when the config is updated."""
390 """Fire the traits events when the config is updated."""
391 # Save a copy of the current config.
391 # Save a copy of the current config.
392 newconfig = deepcopy(self.config)
392 newconfig = deepcopy(self.config)
393 # Merge the new config into the current one.
393 # Merge the new config into the current one.
394 newconfig.merge(config)
394 newconfig.merge(config)
395 # Save the combined config as self.config, which triggers the traits
395 # Save the combined config as self.config, which triggers the traits
396 # events.
396 # events.
397 self.config = newconfig
397 self.config = newconfig
398
398
399 @catch_config_error
399 @catch_config_error
400 def initialize_subcommand(self, subc, argv=None):
400 def initialize_subcommand(self, subc, argv=None):
401 """Initialize a subcommand with argv."""
401 """Initialize a subcommand with argv."""
402 subapp,help = self.subcommands.get(subc)
402 subapp,help = self.subcommands.get(subc)
403
403
404 if isinstance(subapp, string_types):
404 if isinstance(subapp, string_types):
405 subapp = import_item(subapp)
405 subapp = import_item(subapp)
406
406
407 # clear existing instances
407 # clear existing instances
408 self.__class__.clear_instance()
408 self.__class__.clear_instance()
409 # instantiate
409 # instantiate
410 self.subapp = subapp.instance(config=self.config)
410 self.subapp = subapp.instance(config=self.config)
411 # and initialize subapp
411 # and initialize subapp
412 self.subapp.initialize(argv)
412 self.subapp.initialize(argv)
413
413
414 def flatten_flags(self):
414 def flatten_flags(self):
415 """flatten flags and aliases, so cl-args override as expected.
415 """flatten flags and aliases, so cl-args override as expected.
416
416
417 This prevents issues such as an alias pointing to InteractiveShell,
417 This prevents issues such as an alias pointing to InteractiveShell,
418 but a config file setting the same trait in TerminalInteraciveShell
418 but a config file setting the same trait in TerminalInteraciveShell
419 getting inappropriate priority over the command-line arg.
419 getting inappropriate priority over the command-line arg.
420
420
421 Only aliases with exactly one descendent in the class list
421 Only aliases with exactly one descendent in the class list
422 will be promoted.
422 will be promoted.
423
423
424 """
424 """
425 # build a tree of classes in our list that inherit from a particular
425 # build a tree of classes in our list that inherit from a particular
426 # it will be a dict by parent classname of classes in our list
426 # it will be a dict by parent classname of classes in our list
427 # that are descendents
427 # that are descendents
428 mro_tree = defaultdict(list)
428 mro_tree = defaultdict(list)
429 for cls in self.classes:
429 for cls in self.classes:
430 clsname = cls.__name__
430 clsname = cls.__name__
431 for parent in cls.mro()[1:-3]:
431 for parent in cls.mro()[1:-3]:
432 # exclude cls itself and Configurable,HasTraits,object
432 # exclude cls itself and Configurable,HasTraits,object
433 mro_tree[parent.__name__].append(clsname)
433 mro_tree[parent.__name__].append(clsname)
434 # flatten aliases, which have the form:
434 # flatten aliases, which have the form:
435 # { 'alias' : 'Class.trait' }
435 # { 'alias' : 'Class.trait' }
436 aliases = {}
436 aliases = {}
437 for alias, cls_trait in iteritems(self.aliases):
437 for alias, cls_trait in iteritems(self.aliases):
438 cls,trait = cls_trait.split('.',1)
438 cls,trait = cls_trait.split('.',1)
439 children = mro_tree[cls]
439 children = mro_tree[cls]
440 if len(children) == 1:
440 if len(children) == 1:
441 # exactly one descendent, promote alias
441 # exactly one descendent, promote alias
442 cls = children[0]
442 cls = children[0]
443 aliases[alias] = '.'.join([cls,trait])
443 aliases[alias] = '.'.join([cls,trait])
444
444
445 # flatten flags, which are of the form:
445 # flatten flags, which are of the form:
446 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
446 # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
447 flags = {}
447 flags = {}
448 for key, (flagdict, help) in iteritems(self.flags):
448 for key, (flagdict, help) in iteritems(self.flags):
449 newflag = {}
449 newflag = {}
450 for cls, subdict in iteritems(flagdict):
450 for cls, subdict in iteritems(flagdict):
451 children = mro_tree[cls]
451 children = mro_tree[cls]
452 # exactly one descendent, promote flag section
452 # exactly one descendent, promote flag section
453 if len(children) == 1:
453 if len(children) == 1:
454 cls = children[0]
454 cls = children[0]
455 newflag[cls] = subdict
455 newflag[cls] = subdict
456 flags[key] = (newflag, help)
456 flags[key] = (newflag, help)
457 return flags, aliases
457 return flags, aliases
458
458
459 @catch_config_error
459 @catch_config_error
460 def parse_command_line(self, argv=None):
460 def parse_command_line(self, argv=None):
461 """Parse the command line arguments."""
461 """Parse the command line arguments."""
462 argv = sys.argv[1:] if argv is None else argv
462 argv = sys.argv[1:] if argv is None else argv
463 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
463 self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
464
464
465 if argv and argv[0] == 'help':
465 if argv and argv[0] == 'help':
466 # turn `ipython help notebook` into `ipython notebook -h`
466 # turn `ipython help notebook` into `ipython notebook -h`
467 argv = argv[1:] + ['-h']
467 argv = argv[1:] + ['-h']
468
468
469 if self.subcommands and len(argv) > 0:
469 if self.subcommands and len(argv) > 0:
470 # we have subcommands, and one may have been specified
470 # we have subcommands, and one may have been specified
471 subc, subargv = argv[0], argv[1:]
471 subc, subargv = argv[0], argv[1:]
472 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
472 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
473 # it's a subcommand, and *not* a flag or class parameter
473 # it's a subcommand, and *not* a flag or class parameter
474 return self.initialize_subcommand(subc, subargv)
474 return self.initialize_subcommand(subc, subargv)
475
475
476 # Arguments after a '--' argument are for the script IPython may be
476 # Arguments after a '--' argument are for the script IPython may be
477 # about to run, not IPython iteslf. For arguments parsed here (help and
477 # about to run, not IPython iteslf. For arguments parsed here (help and
478 # version), we want to only search the arguments up to the first
478 # version), we want to only search the arguments up to the first
479 # occurrence of '--', which we're calling interpreted_argv.
479 # occurrence of '--', which we're calling interpreted_argv.
480 try:
480 try:
481 interpreted_argv = argv[:argv.index('--')]
481 interpreted_argv = argv[:argv.index('--')]
482 except ValueError:
482 except ValueError:
483 interpreted_argv = argv
483 interpreted_argv = argv
484
484
485 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
485 if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
486 self.print_help('--help-all' in interpreted_argv)
486 self.print_help('--help-all' in interpreted_argv)
487 self.exit(0)
487 self.exit(0)
488
488
489 if '--version' in interpreted_argv or '-V' in interpreted_argv:
489 if '--version' in interpreted_argv or '-V' in interpreted_argv:
490 self.print_version()
490 self.print_version()
491 self.exit(0)
491 self.exit(0)
492
492
493 # flatten flags&aliases, so cl-args get appropriate priority:
493 # flatten flags&aliases, so cl-args get appropriate priority:
494 flags,aliases = self.flatten_flags()
494 flags,aliases = self.flatten_flags()
495
496 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
495 loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
497 flags=flags)
496 flags=flags, log=self.log)
498 config = loader.load_config()
497 config = loader.load_config()
499 self.update_config(config)
498 self.update_config(config)
500 # store unparsed args in extra_args
499 # store unparsed args in extra_args
501 self.extra_args = loader.extra_args
500 self.extra_args = loader.extra_args
502
501
502 @classmethod
503 def _load_config_file(cls, basefilename, path=None, log=None):
504 """Load config files (json/py) by filename and path."""
505
506 pyloader = PyFileConfigLoader(basefilename+'.py', path=path, log=log)
507 jsonloader = JSONFileConfigLoader(basefilename+'.json', path=path, log=log)
508 config_found = False
509 config = None
510 for loader in [pyloader, jsonloader]:
511 try:
512 config = loader.load_config()
513 config_found = True
514 except ConfigFileNotFound:
515 pass
516 except Exception:
517 # try to get the full filename, but it will be empty in the
518 # unlikely event that the error raised before filefind finished
519 filename = loader.full_filename or filename
520 # problem while running the file
521 log.error("Exception while loading config file %s",
522 filename, exc_info=True)
523 else:
524 log.debug("Loaded config file: %s", loader.full_filename)
525 if config :
526 yield config
527
528 if not config_found :
529 raise ConfigFileNotFound('Neither .json, not .py file found.')
530 raise StopIteration
531
532
503 @catch_config_error
533 @catch_config_error
504 def load_config_file(self, filename, path=None):
534 def load_config_file(self, filename, path=None):
505 """Load a .py based config file by filename and path."""
535 """Load config files (json/py) by filename and path."""
506 loader = PyFileConfigLoader(filename, path=path)
536 filename, ext = os.path.splitext(filename)
507 try:
537 for config in self._load_config_file(filename, path=path , log=self.log):
508 config = loader.load_config()
509 except ConfigFileNotFound:
510 # problem finding the file, raise
511 raise
512 except Exception:
513 # try to get the full filename, but it will be empty in the
514 # unlikely event that the error raised before filefind finished
515 filename = loader.full_filename or filename
516 # problem while running the file
517 self.log.error("Exception while loading config file %s",
518 filename, exc_info=True)
519 else:
520 self.log.debug("Loaded config file: %s", loader.full_filename)
521 self.update_config(config)
538 self.update_config(config)
522
539
540
523 def generate_config_file(self):
541 def generate_config_file(self):
524 """generate default config file from Configurables"""
542 """generate default config file from Configurables"""
525 lines = ["# Configuration file for %s."%self.name]
543 lines = ["# Configuration file for %s."%self.name]
526 lines.append('')
544 lines.append('')
527 lines.append('c = get_config()')
545 lines.append('c = get_config()')
528 lines.append('')
546 lines.append('')
529 for cls in self.classes:
547 for cls in self.classes:
530 lines.append(cls.class_config_section())
548 lines.append(cls.class_config_section())
531 return '\n'.join(lines)
549 return '\n'.join(lines)
532
550
533 def exit(self, exit_status=0):
551 def exit(self, exit_status=0):
534 self.log.debug("Exiting application: %s" % self.name)
552 self.log.debug("Exiting application: %s" % self.name)
535 sys.exit(exit_status)
553 sys.exit(exit_status)
536
554
537 @classmethod
555 @classmethod
538 def launch_instance(cls, argv=None, **kwargs):
556 def launch_instance(cls, argv=None, **kwargs):
539 """Launch a global instance of this Application
557 """Launch a global instance of this Application
540
558
541 If a global instance already exists, this reinitializes and starts it
559 If a global instance already exists, this reinitializes and starts it
542 """
560 """
543 app = cls.instance(**kwargs)
561 app = cls.instance(**kwargs)
544 app.initialize(argv)
562 app.initialize(argv)
545 app.start()
563 app.start()
546
564
547 #-----------------------------------------------------------------------------
565 #-----------------------------------------------------------------------------
548 # utility functions, for convenience
566 # utility functions, for convenience
549 #-----------------------------------------------------------------------------
567 #-----------------------------------------------------------------------------
550
568
551 def boolean_flag(name, configurable, set_help='', unset_help=''):
569 def boolean_flag(name, configurable, set_help='', unset_help=''):
552 """Helper for building basic --trait, --no-trait flags.
570 """Helper for building basic --trait, --no-trait flags.
553
571
554 Parameters
572 Parameters
555 ----------
573 ----------
556
574
557 name : str
575 name : str
558 The name of the flag.
576 The name of the flag.
559 configurable : str
577 configurable : str
560 The 'Class.trait' string of the trait to be set/unset with the flag
578 The 'Class.trait' string of the trait to be set/unset with the flag
561 set_help : unicode
579 set_help : unicode
562 help string for --name flag
580 help string for --name flag
563 unset_help : unicode
581 unset_help : unicode
564 help string for --no-name flag
582 help string for --no-name flag
565
583
566 Returns
584 Returns
567 -------
585 -------
568
586
569 cfg : dict
587 cfg : dict
570 A dict with two keys: 'name', and 'no-name', for setting and unsetting
588 A dict with two keys: 'name', and 'no-name', for setting and unsetting
571 the trait, respectively.
589 the trait, respectively.
572 """
590 """
573 # default helpstrings
591 # default helpstrings
574 set_help = set_help or "set %s=True"%configurable
592 set_help = set_help or "set %s=True"%configurable
575 unset_help = unset_help or "set %s=False"%configurable
593 unset_help = unset_help or "set %s=False"%configurable
576
594
577 cls,trait = configurable.split('.')
595 cls,trait = configurable.split('.')
578
596
579 setter = {cls : {trait : True}}
597 setter = {cls : {trait : True}}
580 unsetter = {cls : {trait : False}}
598 unsetter = {cls : {trait : False}}
581 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
599 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
582
600
@@ -1,802 +1,841 b''
1 """A simple configuration system.
1 """A simple configuration system.
2
2
3 Inheritance diagram:
3 Inheritance diagram:
4
4
5 .. inheritance-diagram:: IPython.config.loader
5 .. inheritance-diagram:: IPython.config.loader
6 :parts: 3
6 :parts: 3
7
7
8 Authors
8 Authors
9 -------
9 -------
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min RK
12 * Min RK
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 import argparse
26 import argparse
27 import copy
27 import copy
28 import os
28 import os
29 import re
29 import re
30 import sys
30 import sys
31 import json
31
32
32 from IPython.utils.path import filefind, get_ipython_dir
33 from IPython.utils.path import filefind, get_ipython_dir
33 from IPython.utils import py3compat, warn
34 from IPython.utils import py3compat
34 from IPython.utils.encoding import DEFAULT_ENCODING
35 from IPython.utils.encoding import DEFAULT_ENCODING
35 from IPython.utils.py3compat import unicode_type, iteritems
36 from IPython.utils.py3compat import unicode_type, iteritems
36 from IPython.utils.traitlets import HasTraits, List, Any, TraitError
37 from IPython.utils.traitlets import HasTraits, List, Any, TraitError
37
38
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39 # Exceptions
40 # Exceptions
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41
42
42
43
43 class ConfigError(Exception):
44 class ConfigError(Exception):
44 pass
45 pass
45
46
46 class ConfigLoaderError(ConfigError):
47 class ConfigLoaderError(ConfigError):
47 pass
48 pass
48
49
49 class ConfigFileNotFound(ConfigError):
50 class ConfigFileNotFound(ConfigError):
50 pass
51 pass
51
52
52 class ArgumentError(ConfigLoaderError):
53 class ArgumentError(ConfigLoaderError):
53 pass
54 pass
54
55
55 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
56 # Argparse fix
57 # Argparse fix
57 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
58
59
59 # Unfortunately argparse by default prints help messages to stderr instead of
60 # Unfortunately argparse by default prints help messages to stderr instead of
60 # stdout. This makes it annoying to capture long help screens at the command
61 # stdout. This makes it annoying to capture long help screens at the command
61 # line, since one must know how to pipe stderr, which many users don't know how
62 # line, since one must know how to pipe stderr, which many users don't know how
62 # to do. So we override the print_help method with one that defaults to
63 # to do. So we override the print_help method with one that defaults to
63 # stdout and use our class instead.
64 # stdout and use our class instead.
64
65
65 class ArgumentParser(argparse.ArgumentParser):
66 class ArgumentParser(argparse.ArgumentParser):
66 """Simple argparse subclass that prints help to stdout by default."""
67 """Simple argparse subclass that prints help to stdout by default."""
67
68
68 def print_help(self, file=None):
69 def print_help(self, file=None):
69 if file is None:
70 if file is None:
70 file = sys.stdout
71 file = sys.stdout
71 return super(ArgumentParser, self).print_help(file)
72 return super(ArgumentParser, self).print_help(file)
72
73
73 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
74 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
74
75
75 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
76 # Config class for holding config information
77 # Config class for holding config information
77 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
78
79
79 class LazyConfigValue(HasTraits):
80 class LazyConfigValue(HasTraits):
80 """Proxy object for exposing methods on configurable containers
81 """Proxy object for exposing methods on configurable containers
81
82
82 Exposes:
83 Exposes:
83
84
84 - append, extend, insert on lists
85 - append, extend, insert on lists
85 - update on dicts
86 - update on dicts
86 - update, add on sets
87 - update, add on sets
87 """
88 """
88
89
89 _value = None
90 _value = None
90
91
91 # list methods
92 # list methods
92 _extend = List()
93 _extend = List()
93 _prepend = List()
94 _prepend = List()
94
95
95 def append(self, obj):
96 def append(self, obj):
96 self._extend.append(obj)
97 self._extend.append(obj)
97
98
98 def extend(self, other):
99 def extend(self, other):
99 self._extend.extend(other)
100 self._extend.extend(other)
100
101
101 def prepend(self, other):
102 def prepend(self, other):
102 """like list.extend, but for the front"""
103 """like list.extend, but for the front"""
103 self._prepend[:0] = other
104 self._prepend[:0] = other
104
105
105 _inserts = List()
106 _inserts = List()
106 def insert(self, index, other):
107 def insert(self, index, other):
107 if not isinstance(index, int):
108 if not isinstance(index, int):
108 raise TypeError("An integer is required")
109 raise TypeError("An integer is required")
109 self._inserts.append((index, other))
110 self._inserts.append((index, other))
110
111
111 # dict methods
112 # dict methods
112 # update is used for both dict and set
113 # update is used for both dict and set
113 _update = Any()
114 _update = Any()
114 def update(self, other):
115 def update(self, other):
115 if self._update is None:
116 if self._update is None:
116 if isinstance(other, dict):
117 if isinstance(other, dict):
117 self._update = {}
118 self._update = {}
118 else:
119 else:
119 self._update = set()
120 self._update = set()
120 self._update.update(other)
121 self._update.update(other)
121
122
122 # set methods
123 # set methods
123 def add(self, obj):
124 def add(self, obj):
124 self.update({obj})
125 self.update({obj})
125
126
126 def get_value(self, initial):
127 def get_value(self, initial):
127 """construct the value from the initial one
128 """construct the value from the initial one
128
129
129 after applying any insert / extend / update changes
130 after applying any insert / extend / update changes
130 """
131 """
131 if self._value is not None:
132 if self._value is not None:
132 return self._value
133 return self._value
133 value = copy.deepcopy(initial)
134 value = copy.deepcopy(initial)
134 if isinstance(value, list):
135 if isinstance(value, list):
135 for idx, obj in self._inserts:
136 for idx, obj in self._inserts:
136 value.insert(idx, obj)
137 value.insert(idx, obj)
137 value[:0] = self._prepend
138 value[:0] = self._prepend
138 value.extend(self._extend)
139 value.extend(self._extend)
139
140
140 elif isinstance(value, dict):
141 elif isinstance(value, dict):
141 if self._update:
142 if self._update:
142 value.update(self._update)
143 value.update(self._update)
143 elif isinstance(value, set):
144 elif isinstance(value, set):
144 if self._update:
145 if self._update:
145 value.update(self._update)
146 value.update(self._update)
146 self._value = value
147 self._value = value
147 return value
148 return value
148
149
149 def to_dict(self):
150 def to_dict(self):
150 """return JSONable dict form of my data
151 """return JSONable dict form of my data
151
152
152 Currently update as dict or set, extend, prepend as lists, and inserts as list of tuples.
153 Currently update as dict or set, extend, prepend as lists, and inserts as list of tuples.
153 """
154 """
154 d = {}
155 d = {}
155 if self._update:
156 if self._update:
156 d['update'] = self._update
157 d['update'] = self._update
157 if self._extend:
158 if self._extend:
158 d['extend'] = self._extend
159 d['extend'] = self._extend
159 if self._prepend:
160 if self._prepend:
160 d['prepend'] = self._prepend
161 d['prepend'] = self._prepend
161 elif self._inserts:
162 elif self._inserts:
162 d['inserts'] = self._inserts
163 d['inserts'] = self._inserts
163 return d
164 return d
164
165
165
166
166 def _is_section_key(key):
167 def _is_section_key(key):
167 """Is a Config key a section name (does it start with a capital)?"""
168 """Is a Config key a section name (does it start with a capital)?"""
168 if key and key[0].upper()==key[0] and not key.startswith('_'):
169 if key and key[0].upper()==key[0] and not key.startswith('_'):
169 return True
170 return True
170 else:
171 else:
171 return False
172 return False
172
173
173
174
174 class Config(dict):
175 class Config(dict):
175 """An attribute based dict that can do smart merges."""
176 """An attribute based dict that can do smart merges."""
176
177
177 def __init__(self, *args, **kwds):
178 def __init__(self, *args, **kwds):
178 dict.__init__(self, *args, **kwds)
179 dict.__init__(self, *args, **kwds)
179 self._ensure_subconfig()
180 self._ensure_subconfig()
180
181
181 def _ensure_subconfig(self):
182 def _ensure_subconfig(self):
182 """ensure that sub-dicts that should be Config objects are
183 """ensure that sub-dicts that should be Config objects are
183
184
184 casts dicts that are under section keys to Config objects,
185 casts dicts that are under section keys to Config objects,
185 which is necessary for constructing Config objects from dict literals.
186 which is necessary for constructing Config objects from dict literals.
186 """
187 """
187 for key in self:
188 for key in self:
188 obj = self[key]
189 obj = self[key]
189 if _is_section_key(key) \
190 if _is_section_key(key) \
190 and isinstance(obj, dict) \
191 and isinstance(obj, dict) \
191 and not isinstance(obj, Config):
192 and not isinstance(obj, Config):
192 setattr(self, key, Config(obj))
193 setattr(self, key, Config(obj))
193
194
194 def _merge(self, other):
195 def _merge(self, other):
195 """deprecated alias, use Config.merge()"""
196 """deprecated alias, use Config.merge()"""
196 self.merge(other)
197 self.merge(other)
197
198
198 def merge(self, other):
199 def merge(self, other):
199 """merge another config object into this one"""
200 """merge another config object into this one"""
200 to_update = {}
201 to_update = {}
201 for k, v in iteritems(other):
202 for k, v in iteritems(other):
202 if k not in self:
203 if k not in self:
203 to_update[k] = copy.deepcopy(v)
204 to_update[k] = copy.deepcopy(v)
204 else: # I have this key
205 else: # I have this key
205 if isinstance(v, Config) and isinstance(self[k], Config):
206 if isinstance(v, Config) and isinstance(self[k], Config):
206 # Recursively merge common sub Configs
207 # Recursively merge common sub Configs
207 self[k].merge(v)
208 self[k].merge(v)
208 else:
209 else:
209 # Plain updates for non-Configs
210 # Plain updates for non-Configs
210 to_update[k] = copy.deepcopy(v)
211 to_update[k] = copy.deepcopy(v)
211
212
212 self.update(to_update)
213 self.update(to_update)
213
214
214 def __contains__(self, key):
215 def __contains__(self, key):
215 # allow nested contains of the form `"Section.key" in config`
216 # allow nested contains of the form `"Section.key" in config`
216 if '.' in key:
217 if '.' in key:
217 first, remainder = key.split('.', 1)
218 first, remainder = key.split('.', 1)
218 if first not in self:
219 if first not in self:
219 return False
220 return False
220 return remainder in self[first]
221 return remainder in self[first]
221
222
222 return super(Config, self).__contains__(key)
223 return super(Config, self).__contains__(key)
223
224
224 # .has_key is deprecated for dictionaries.
225 # .has_key is deprecated for dictionaries.
225 has_key = __contains__
226 has_key = __contains__
226
227
227 def _has_section(self, key):
228 def _has_section(self, key):
228 return _is_section_key(key) and key in self
229 return _is_section_key(key) and key in self
229
230
230 def copy(self):
231 def copy(self):
231 return type(self)(dict.copy(self))
232 return type(self)(dict.copy(self))
232
233
233 def __copy__(self):
234 def __copy__(self):
234 return self.copy()
235 return self.copy()
235
236
236 def __deepcopy__(self, memo):
237 def __deepcopy__(self, memo):
237 import copy
238 import copy
238 return type(self)(copy.deepcopy(list(self.items())))
239 return type(self)(copy.deepcopy(list(self.items())))
239
240
240 def __getitem__(self, key):
241 def __getitem__(self, key):
241 try:
242 try:
242 return dict.__getitem__(self, key)
243 return dict.__getitem__(self, key)
243 except KeyError:
244 except KeyError:
244 if _is_section_key(key):
245 if _is_section_key(key):
245 c = Config()
246 c = Config()
246 dict.__setitem__(self, key, c)
247 dict.__setitem__(self, key, c)
247 return c
248 return c
248 else:
249 else:
249 # undefined, create lazy value, used for container methods
250 # undefined, create lazy value, used for container methods
250 v = LazyConfigValue()
251 v = LazyConfigValue()
251 dict.__setitem__(self, key, v)
252 dict.__setitem__(self, key, v)
252 return v
253 return v
253
254
254 def __setitem__(self, key, value):
255 def __setitem__(self, key, value):
255 if _is_section_key(key):
256 if _is_section_key(key):
256 if not isinstance(value, Config):
257 if not isinstance(value, Config):
257 raise ValueError('values whose keys begin with an uppercase '
258 raise ValueError('values whose keys begin with an uppercase '
258 'char must be Config instances: %r, %r' % (key, value))
259 'char must be Config instances: %r, %r' % (key, value))
259 dict.__setitem__(self, key, value)
260 dict.__setitem__(self, key, value)
260
261
261 def __getattr__(self, key):
262 def __getattr__(self, key):
262 if key.startswith('__'):
263 if key.startswith('__'):
263 return dict.__getattr__(self, key)
264 return dict.__getattr__(self, key)
264 try:
265 try:
265 return self.__getitem__(key)
266 return self.__getitem__(key)
266 except KeyError as e:
267 except KeyError as e:
267 raise AttributeError(e)
268 raise AttributeError(e)
268
269
269 def __setattr__(self, key, value):
270 def __setattr__(self, key, value):
270 if key.startswith('__'):
271 if key.startswith('__'):
271 return dict.__setattr__(self, key, value)
272 return dict.__setattr__(self, key, value)
272 try:
273 try:
273 self.__setitem__(key, value)
274 self.__setitem__(key, value)
274 except KeyError as e:
275 except KeyError as e:
275 raise AttributeError(e)
276 raise AttributeError(e)
276
277
277 def __delattr__(self, key):
278 def __delattr__(self, key):
278 if key.startswith('__'):
279 if key.startswith('__'):
279 return dict.__delattr__(self, key)
280 return dict.__delattr__(self, key)
280 try:
281 try:
281 dict.__delitem__(self, key)
282 dict.__delitem__(self, key)
282 except KeyError as e:
283 except KeyError as e:
283 raise AttributeError(e)
284 raise AttributeError(e)
284
285
285
286
286 #-----------------------------------------------------------------------------
287 #-----------------------------------------------------------------------------
287 # Config loading classes
288 # Config loading classes
288 #-----------------------------------------------------------------------------
289 #-----------------------------------------------------------------------------
289
290
290
291
291 class ConfigLoader(object):
292 class ConfigLoader(object):
292 """A object for loading configurations from just about anywhere.
293 """A object for loading configurations from just about anywhere.
293
294
294 The resulting configuration is packaged as a :class:`Struct`.
295 The resulting configuration is packaged as a :class:`Struct`.
295
296
296 Notes
297 Notes
297 -----
298 -----
298 A :class:`ConfigLoader` does one thing: load a config from a source
299 A :class:`ConfigLoader` does one thing: load a config from a source
299 (file, command line arguments) and returns the data as a :class:`Struct`.
300 (file, command line arguments) and returns the data as a :class:`Struct`.
300 There are lots of things that :class:`ConfigLoader` does not do. It does
301 There are lots of things that :class:`ConfigLoader` does not do. It does
301 not implement complex logic for finding config files. It does not handle
302 not implement complex logic for finding config files. It does not handle
302 default values or merge multiple configs. These things need to be
303 default values or merge multiple configs. These things need to be
303 handled elsewhere.
304 handled elsewhere.
304 """
305 """
305
306
306 def __init__(self):
307 def _log_default(self):
308 from IPython.config.application import Application
309 return Application.instance().log
310
311 def __init__(self, log=None):
307 """A base class for config loaders.
312 """A base class for config loaders.
308
313
314 log : instance of :class:`logging.Logger` to use.
315 By default loger of :meth:`IPython.config.application.Application.instance()`
316 will be used
317
309 Examples
318 Examples
310 --------
319 --------
311
320
312 >>> cl = ConfigLoader()
321 >>> cl = ConfigLoader()
313 >>> config = cl.load_config()
322 >>> config = cl.load_config()
314 >>> config
323 >>> config
315 {}
324 {}
316 """
325 """
317 self.clear()
326 self.clear()
327 if log is None :
328 self.log = self._log_default()
329 self.log.debug('Using default logger')
330 else :
331 self.log = log
318
332
319 def clear(self):
333 def clear(self):
320 self.config = Config()
334 self.config = Config()
321
335
322 def load_config(self):
336 def load_config(self):
323 """Load a config from somewhere, return a :class:`Config` instance.
337 """Load a config from somewhere, return a :class:`Config` instance.
324
338
325 Usually, this will cause self.config to be set and then returned.
339 Usually, this will cause self.config to be set and then returned.
326 However, in most cases, :meth:`ConfigLoader.clear` should be called
340 However, in most cases, :meth:`ConfigLoader.clear` should be called
327 to erase any previous state.
341 to erase any previous state.
328 """
342 """
329 self.clear()
343 self.clear()
330 return self.config
344 return self.config
331
345
332
346
333 class FileConfigLoader(ConfigLoader):
347 class FileConfigLoader(ConfigLoader):
334 """A base class for file based configurations.
348 """A base class for file based configurations.
335
349
336 As we add more file based config loaders, the common logic should go
350 As we add more file based config loaders, the common logic should go
337 here.
351 here.
338 """
352 """
339 pass
340
341
342 class PyFileConfigLoader(FileConfigLoader):
343 """A config loader for pure python files.
344
345 This calls execfile on a plain python file and looks for attributes
346 that are all caps. These attribute are added to the config Struct.
347 """
348
353
349 def __init__(self, filename, path=None):
354 def __init__(self, filename, path=None, **kw):
350 """Build a config loader for a filename and path.
355 """Build a config loader for a filename and path.
351
356
352 Parameters
357 Parameters
353 ----------
358 ----------
354 filename : str
359 filename : str
355 The file name of the config file.
360 The file name of the config file.
356 path : str, list, tuple
361 path : str, list, tuple
357 The path to search for the config file on, or a sequence of
362 The path to search for the config file on, or a sequence of
358 paths to try in order.
363 paths to try in order.
359 """
364 """
360 super(PyFileConfigLoader, self).__init__()
365 super(FileConfigLoader, self).__init__(**kw)
361 self.filename = filename
366 self.filename = filename
362 self.path = path
367 self.path = path
363 self.full_filename = ''
368 self.full_filename = ''
364 self.data = None
369
370 def _find_file(self):
371 """Try to find the file by searching the paths."""
372 self.full_filename = filefind(self.filename, self.path)
373
374 class JSONFileConfigLoader(FileConfigLoader):
375 """A Json file loader for config"""
376
377 def load_config(self):
378 """Load the config from a file and return it as a Struct."""
379 self.clear()
380 try:
381 self._find_file()
382 except IOError as e:
383 raise ConfigFileNotFound(str(e))
384 dct = self._read_file_as_dict()
385 self.config = self._convert_to_config(dct)
386 return self.config
387
388 def _read_file_as_dict(self):
389 with open(self.full_filename) as f :
390 return json.load(f)
391
392 def _convert_to_config(self, dictionary):
393 if 'version' in dictionary:
394 version = dictionary.pop('version')
395 else :
396 version = 1
397 self.log.warn("Unrecognized JSON config file version, assuming version : {}".format(version))
398
399 if version == 1:
400 return Config(dictionary)
401 else :
402 raise ValueError('Unknown version of JSON config file : version number {version}'.format(version=version))
403
404
405 class PyFileConfigLoader(FileConfigLoader):
406 """A config loader for pure python files.
407
408 This is responsible for locating a Python config file by filename and
409 profile name, then executing it in a namespace where it could have access
410 to subconfigs.
411 """
365
412
366 def load_config(self):
413 def load_config(self):
367 """Load the config from a file and return it as a Struct."""
414 """Load the config from a file and return it as a Struct."""
368 self.clear()
415 self.clear()
369 try:
416 try:
370 self._find_file()
417 self._find_file()
371 except IOError as e:
418 except IOError as e:
372 raise ConfigFileNotFound(str(e))
419 raise ConfigFileNotFound(str(e))
373 self._read_file_as_dict()
420 self._read_file_as_dict()
374 self._convert_to_config()
375 return self.config
421 return self.config
376
422
377 def _find_file(self):
378 """Try to find the file by searching the paths."""
379 self.full_filename = filefind(self.filename, self.path)
380
423
381 def _read_file_as_dict(self):
424 def _read_file_as_dict(self):
382 """Load the config file into self.config, with recursive loading."""
425 """Load the config file into self.config, with recursive loading."""
383 # This closure is made available in the namespace that is used
426 # This closure is made available in the namespace that is used
384 # to exec the config file. It allows users to call
427 # to exec the config file. It allows users to call
385 # load_subconfig('myconfig.py') to load config files recursively.
428 # load_subconfig('myconfig.py') to load config files recursively.
386 # It needs to be a closure because it has references to self.path
429 # It needs to be a closure because it has references to self.path
387 # and self.config. The sub-config is loaded with the same path
430 # and self.config. The sub-config is loaded with the same path
388 # as the parent, but it uses an empty config which is then merged
431 # as the parent, but it uses an empty config which is then merged
389 # with the parents.
432 # with the parents.
390
433
391 # If a profile is specified, the config file will be loaded
434 # If a profile is specified, the config file will be loaded
392 # from that profile
435 # from that profile
393
436
394 def load_subconfig(fname, profile=None):
437 def load_subconfig(fname, profile=None):
395 # import here to prevent circular imports
438 # import here to prevent circular imports
396 from IPython.core.profiledir import ProfileDir, ProfileDirError
439 from IPython.core.profiledir import ProfileDir, ProfileDirError
397 if profile is not None:
440 if profile is not None:
398 try:
441 try:
399 profile_dir = ProfileDir.find_profile_dir_by_name(
442 profile_dir = ProfileDir.find_profile_dir_by_name(
400 get_ipython_dir(),
443 get_ipython_dir(),
401 profile,
444 profile,
402 )
445 )
403 except ProfileDirError:
446 except ProfileDirError:
404 return
447 return
405 path = profile_dir.location
448 path = profile_dir.location
406 else:
449 else:
407 path = self.path
450 path = self.path
408 loader = PyFileConfigLoader(fname, path)
451 loader = PyFileConfigLoader(fname, path)
409 try:
452 try:
410 sub_config = loader.load_config()
453 sub_config = loader.load_config()
411 except ConfigFileNotFound:
454 except ConfigFileNotFound:
412 # Pass silently if the sub config is not there. This happens
455 # Pass silently if the sub config is not there. This happens
413 # when a user s using a profile, but not the default config.
456 # when a user s using a profile, but not the default config.
414 pass
457 pass
415 else:
458 else:
416 self.config.merge(sub_config)
459 self.config.merge(sub_config)
417
460
418 # Again, this needs to be a closure and should be used in config
461 # Again, this needs to be a closure and should be used in config
419 # files to get the config being loaded.
462 # files to get the config being loaded.
420 def get_config():
463 def get_config():
421 return self.config
464 return self.config
422
465
423 namespace = dict(
466 namespace = dict(
424 load_subconfig=load_subconfig,
467 load_subconfig=load_subconfig,
425 get_config=get_config,
468 get_config=get_config,
426 __file__=self.full_filename,
469 __file__=self.full_filename,
427 )
470 )
428 fs_encoding = sys.getfilesystemencoding() or 'ascii'
471 fs_encoding = sys.getfilesystemencoding() or 'ascii'
429 conf_filename = self.full_filename.encode(fs_encoding)
472 conf_filename = self.full_filename.encode(fs_encoding)
430 py3compat.execfile(conf_filename, namespace)
473 py3compat.execfile(conf_filename, namespace)
431
474
432 def _convert_to_config(self):
433 if self.data is None:
434 ConfigLoaderError('self.data does not exist')
435
436
475
437 class CommandLineConfigLoader(ConfigLoader):
476 class CommandLineConfigLoader(ConfigLoader):
438 """A config loader for command line arguments.
477 """A config loader for command line arguments.
439
478
440 As we add more command line based loaders, the common logic should go
479 As we add more command line based loaders, the common logic should go
441 here.
480 here.
442 """
481 """
443
482
444 def _exec_config_str(self, lhs, rhs):
483 def _exec_config_str(self, lhs, rhs):
445 """execute self.config.<lhs> = <rhs>
484 """execute self.config.<lhs> = <rhs>
446
485
447 * expands ~ with expanduser
486 * expands ~ with expanduser
448 * tries to assign with raw eval, otherwise assigns with just the string,
487 * tries to assign with raw eval, otherwise assigns with just the string,
449 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
488 allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
450 equivalent are `--C.a=4` and `--C.a='4'`.
489 equivalent are `--C.a=4` and `--C.a='4'`.
451 """
490 """
452 rhs = os.path.expanduser(rhs)
491 rhs = os.path.expanduser(rhs)
453 try:
492 try:
454 # Try to see if regular Python syntax will work. This
493 # Try to see if regular Python syntax will work. This
455 # won't handle strings as the quote marks are removed
494 # won't handle strings as the quote marks are removed
456 # by the system shell.
495 # by the system shell.
457 value = eval(rhs)
496 value = eval(rhs)
458 except (NameError, SyntaxError):
497 except (NameError, SyntaxError):
459 # This case happens if the rhs is a string.
498 # This case happens if the rhs is a string.
460 value = rhs
499 value = rhs
461
500
462 exec(u'self.config.%s = value' % lhs)
501 exec(u'self.config.%s = value' % lhs)
463
502
464 def _load_flag(self, cfg):
503 def _load_flag(self, cfg):
465 """update self.config from a flag, which can be a dict or Config"""
504 """update self.config from a flag, which can be a dict or Config"""
466 if isinstance(cfg, (dict, Config)):
505 if isinstance(cfg, (dict, Config)):
467 # don't clobber whole config sections, update
506 # don't clobber whole config sections, update
468 # each section from config:
507 # each section from config:
469 for sec,c in iteritems(cfg):
508 for sec,c in iteritems(cfg):
470 self.config[sec].update(c)
509 self.config[sec].update(c)
471 else:
510 else:
472 raise TypeError("Invalid flag: %r" % cfg)
511 raise TypeError("Invalid flag: %r" % cfg)
473
512
474 # raw --identifier=value pattern
513 # raw --identifier=value pattern
475 # but *also* accept '-' as wordsep, for aliases
514 # but *also* accept '-' as wordsep, for aliases
476 # accepts: --foo=a
515 # accepts: --foo=a
477 # --Class.trait=value
516 # --Class.trait=value
478 # --alias-name=value
517 # --alias-name=value
479 # rejects: -foo=value
518 # rejects: -foo=value
480 # --foo
519 # --foo
481 # --Class.trait
520 # --Class.trait
482 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
521 kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
483
522
484 # just flags, no assignments, with two *or one* leading '-'
523 # just flags, no assignments, with two *or one* leading '-'
485 # accepts: --foo
524 # accepts: --foo
486 # -foo-bar-again
525 # -foo-bar-again
487 # rejects: --anything=anything
526 # rejects: --anything=anything
488 # --two.word
527 # --two.word
489
528
490 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
529 flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
491
530
492 class KeyValueConfigLoader(CommandLineConfigLoader):
531 class KeyValueConfigLoader(CommandLineConfigLoader):
493 """A config loader that loads key value pairs from the command line.
532 """A config loader that loads key value pairs from the command line.
494
533
495 This allows command line options to be gives in the following form::
534 This allows command line options to be gives in the following form::
496
535
497 ipython --profile="foo" --InteractiveShell.autocall=False
536 ipython --profile="foo" --InteractiveShell.autocall=False
498 """
537 """
499
538
500 def __init__(self, argv=None, aliases=None, flags=None):
539 def __init__(self, argv=None, aliases=None, flags=None, **kw):
501 """Create a key value pair config loader.
540 """Create a key value pair config loader.
502
541
503 Parameters
542 Parameters
504 ----------
543 ----------
505 argv : list
544 argv : list
506 A list that has the form of sys.argv[1:] which has unicode
545 A list that has the form of sys.argv[1:] which has unicode
507 elements of the form u"key=value". If this is None (default),
546 elements of the form u"key=value". If this is None (default),
508 then sys.argv[1:] will be used.
547 then sys.argv[1:] will be used.
509 aliases : dict
548 aliases : dict
510 A dict of aliases for configurable traits.
549 A dict of aliases for configurable traits.
511 Keys are the short aliases, Values are the resolved trait.
550 Keys are the short aliases, Values are the resolved trait.
512 Of the form: `{'alias' : 'Configurable.trait'}`
551 Of the form: `{'alias' : 'Configurable.trait'}`
513 flags : dict
552 flags : dict
514 A dict of flags, keyed by str name. Vaues can be Config objects,
553 A dict of flags, keyed by str name. Vaues can be Config objects,
515 dicts, or "key=value" strings. If Config or dict, when the flag
554 dicts, or "key=value" strings. If Config or dict, when the flag
516 is triggered, The flag is loaded as `self.config.update(m)`.
555 is triggered, The flag is loaded as `self.config.update(m)`.
517
556
518 Returns
557 Returns
519 -------
558 -------
520 config : Config
559 config : Config
521 The resulting Config object.
560 The resulting Config object.
522
561
523 Examples
562 Examples
524 --------
563 --------
525
564
526 >>> from IPython.config.loader import KeyValueConfigLoader
565 >>> from IPython.config.loader import KeyValueConfigLoader
527 >>> cl = KeyValueConfigLoader()
566 >>> cl = KeyValueConfigLoader()
528 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
567 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
529 >>> sorted(d.items())
568 >>> sorted(d.items())
530 [('A', {'name': 'brian'}), ('B', {'number': 0})]
569 [('A', {'name': 'brian'}), ('B', {'number': 0})]
531 """
570 """
532 self.clear()
571 super(KeyValueConfigLoader, self).__init__(**kw)
533 if argv is None:
572 if argv is None:
534 argv = sys.argv[1:]
573 argv = sys.argv[1:]
535 self.argv = argv
574 self.argv = argv
536 self.aliases = aliases or {}
575 self.aliases = aliases or {}
537 self.flags = flags or {}
576 self.flags = flags or {}
538
577
539
578
540 def clear(self):
579 def clear(self):
541 super(KeyValueConfigLoader, self).clear()
580 super(KeyValueConfigLoader, self).clear()
542 self.extra_args = []
581 self.extra_args = []
543
582
544
583
545 def _decode_argv(self, argv, enc=None):
584 def _decode_argv(self, argv, enc=None):
546 """decode argv if bytes, using stin.encoding, falling back on default enc"""
585 """decode argv if bytes, using stin.encoding, falling back on default enc"""
547 uargv = []
586 uargv = []
548 if enc is None:
587 if enc is None:
549 enc = DEFAULT_ENCODING
588 enc = DEFAULT_ENCODING
550 for arg in argv:
589 for arg in argv:
551 if not isinstance(arg, unicode_type):
590 if not isinstance(arg, unicode_type):
552 # only decode if not already decoded
591 # only decode if not already decoded
553 arg = arg.decode(enc)
592 arg = arg.decode(enc)
554 uargv.append(arg)
593 uargv.append(arg)
555 return uargv
594 return uargv
556
595
557
596
558 def load_config(self, argv=None, aliases=None, flags=None):
597 def load_config(self, argv=None, aliases=None, flags=None):
559 """Parse the configuration and generate the Config object.
598 """Parse the configuration and generate the Config object.
560
599
561 After loading, any arguments that are not key-value or
600 After loading, any arguments that are not key-value or
562 flags will be stored in self.extra_args - a list of
601 flags will be stored in self.extra_args - a list of
563 unparsed command-line arguments. This is used for
602 unparsed command-line arguments. This is used for
564 arguments such as input files or subcommands.
603 arguments such as input files or subcommands.
565
604
566 Parameters
605 Parameters
567 ----------
606 ----------
568 argv : list, optional
607 argv : list, optional
569 A list that has the form of sys.argv[1:] which has unicode
608 A list that has the form of sys.argv[1:] which has unicode
570 elements of the form u"key=value". If this is None (default),
609 elements of the form u"key=value". If this is None (default),
571 then self.argv will be used.
610 then self.argv will be used.
572 aliases : dict
611 aliases : dict
573 A dict of aliases for configurable traits.
612 A dict of aliases for configurable traits.
574 Keys are the short aliases, Values are the resolved trait.
613 Keys are the short aliases, Values are the resolved trait.
575 Of the form: `{'alias' : 'Configurable.trait'}`
614 Of the form: `{'alias' : 'Configurable.trait'}`
576 flags : dict
615 flags : dict
577 A dict of flags, keyed by str name. Values can be Config objects
616 A dict of flags, keyed by str name. Values can be Config objects
578 or dicts. When the flag is triggered, The config is loaded as
617 or dicts. When the flag is triggered, The config is loaded as
579 `self.config.update(cfg)`.
618 `self.config.update(cfg)`.
580 """
619 """
581 self.clear()
620 self.clear()
582 if argv is None:
621 if argv is None:
583 argv = self.argv
622 argv = self.argv
584 if aliases is None:
623 if aliases is None:
585 aliases = self.aliases
624 aliases = self.aliases
586 if flags is None:
625 if flags is None:
587 flags = self.flags
626 flags = self.flags
588
627
589 # ensure argv is a list of unicode strings:
628 # ensure argv is a list of unicode strings:
590 uargv = self._decode_argv(argv)
629 uargv = self._decode_argv(argv)
591 for idx,raw in enumerate(uargv):
630 for idx,raw in enumerate(uargv):
592 # strip leading '-'
631 # strip leading '-'
593 item = raw.lstrip('-')
632 item = raw.lstrip('-')
594
633
595 if raw == '--':
634 if raw == '--':
596 # don't parse arguments after '--'
635 # don't parse arguments after '--'
597 # this is useful for relaying arguments to scripts, e.g.
636 # this is useful for relaying arguments to scripts, e.g.
598 # ipython -i foo.py --matplotlib=qt -- args after '--' go-to-foo.py
637 # ipython -i foo.py --matplotlib=qt -- args after '--' go-to-foo.py
599 self.extra_args.extend(uargv[idx+1:])
638 self.extra_args.extend(uargv[idx+1:])
600 break
639 break
601
640
602 if kv_pattern.match(raw):
641 if kv_pattern.match(raw):
603 lhs,rhs = item.split('=',1)
642 lhs,rhs = item.split('=',1)
604 # Substitute longnames for aliases.
643 # Substitute longnames for aliases.
605 if lhs in aliases:
644 if lhs in aliases:
606 lhs = aliases[lhs]
645 lhs = aliases[lhs]
607 if '.' not in lhs:
646 if '.' not in lhs:
608 # probably a mistyped alias, but not technically illegal
647 # probably a mistyped alias, but not technically illegal
609 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
648 self.log.warn("Unrecognized alias: '%s', it will probably have no effect. %s,-- %s"%(lhs,raw, aliases))
610 try:
649 try:
611 self._exec_config_str(lhs, rhs)
650 self._exec_config_str(lhs, rhs)
612 except Exception:
651 except Exception:
613 raise ArgumentError("Invalid argument: '%s'" % raw)
652 raise ArgumentError("Invalid argument: '%s'" % raw)
614
653
615 elif flag_pattern.match(raw):
654 elif flag_pattern.match(raw):
616 if item in flags:
655 if item in flags:
617 cfg,help = flags[item]
656 cfg,help = flags[item]
618 self._load_flag(cfg)
657 self._load_flag(cfg)
619 else:
658 else:
620 raise ArgumentError("Unrecognized flag: '%s'"%raw)
659 raise ArgumentError("Unrecognized flag: '%s'"%raw)
621 elif raw.startswith('-'):
660 elif raw.startswith('-'):
622 kv = '--'+item
661 kv = '--'+item
623 if kv_pattern.match(kv):
662 if kv_pattern.match(kv):
624 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
663 raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
625 else:
664 else:
626 raise ArgumentError("Invalid argument: '%s'"%raw)
665 raise ArgumentError("Invalid argument: '%s'"%raw)
627 else:
666 else:
628 # keep all args that aren't valid in a list,
667 # keep all args that aren't valid in a list,
629 # in case our parent knows what to do with them.
668 # in case our parent knows what to do with them.
630 self.extra_args.append(item)
669 self.extra_args.append(item)
631 return self.config
670 return self.config
632
671
633 class ArgParseConfigLoader(CommandLineConfigLoader):
672 class ArgParseConfigLoader(CommandLineConfigLoader):
634 """A loader that uses the argparse module to load from the command line."""
673 """A loader that uses the argparse module to load from the command line."""
635
674
636 def __init__(self, argv=None, aliases=None, flags=None, *parser_args, **parser_kw):
675 def __init__(self, argv=None, aliases=None, flags=None, log=None, *parser_args, **parser_kw):
637 """Create a config loader for use with argparse.
676 """Create a config loader for use with argparse.
638
677
639 Parameters
678 Parameters
640 ----------
679 ----------
641
680
642 argv : optional, list
681 argv : optional, list
643 If given, used to read command-line arguments from, otherwise
682 If given, used to read command-line arguments from, otherwise
644 sys.argv[1:] is used.
683 sys.argv[1:] is used.
645
684
646 parser_args : tuple
685 parser_args : tuple
647 A tuple of positional arguments that will be passed to the
686 A tuple of positional arguments that will be passed to the
648 constructor of :class:`argparse.ArgumentParser`.
687 constructor of :class:`argparse.ArgumentParser`.
649
688
650 parser_kw : dict
689 parser_kw : dict
651 A tuple of keyword arguments that will be passed to the
690 A tuple of keyword arguments that will be passed to the
652 constructor of :class:`argparse.ArgumentParser`.
691 constructor of :class:`argparse.ArgumentParser`.
653
692
654 Returns
693 Returns
655 -------
694 -------
656 config : Config
695 config : Config
657 The resulting Config object.
696 The resulting Config object.
658 """
697 """
659 super(CommandLineConfigLoader, self).__init__()
698 super(CommandLineConfigLoader, self).__init__(log=log)
660 self.clear()
699 self.clear()
661 if argv is None:
700 if argv is None:
662 argv = sys.argv[1:]
701 argv = sys.argv[1:]
663 self.argv = argv
702 self.argv = argv
664 self.aliases = aliases or {}
703 self.aliases = aliases or {}
665 self.flags = flags or {}
704 self.flags = flags or {}
666
705
667 self.parser_args = parser_args
706 self.parser_args = parser_args
668 self.version = parser_kw.pop("version", None)
707 self.version = parser_kw.pop("version", None)
669 kwargs = dict(argument_default=argparse.SUPPRESS)
708 kwargs = dict(argument_default=argparse.SUPPRESS)
670 kwargs.update(parser_kw)
709 kwargs.update(parser_kw)
671 self.parser_kw = kwargs
710 self.parser_kw = kwargs
672
711
673 def load_config(self, argv=None, aliases=None, flags=None):
712 def load_config(self, argv=None, aliases=None, flags=None):
674 """Parse command line arguments and return as a Config object.
713 """Parse command line arguments and return as a Config object.
675
714
676 Parameters
715 Parameters
677 ----------
716 ----------
678
717
679 args : optional, list
718 args : optional, list
680 If given, a list with the structure of sys.argv[1:] to parse
719 If given, a list with the structure of sys.argv[1:] to parse
681 arguments from. If not given, the instance's self.argv attribute
720 arguments from. If not given, the instance's self.argv attribute
682 (given at construction time) is used."""
721 (given at construction time) is used."""
683 self.clear()
722 self.clear()
684 if argv is None:
723 if argv is None:
685 argv = self.argv
724 argv = self.argv
686 if aliases is None:
725 if aliases is None:
687 aliases = self.aliases
726 aliases = self.aliases
688 if flags is None:
727 if flags is None:
689 flags = self.flags
728 flags = self.flags
690 self._create_parser(aliases, flags)
729 self._create_parser(aliases, flags)
691 self._parse_args(argv)
730 self._parse_args(argv)
692 self._convert_to_config()
731 self._convert_to_config()
693 return self.config
732 return self.config
694
733
695 def get_extra_args(self):
734 def get_extra_args(self):
696 if hasattr(self, 'extra_args'):
735 if hasattr(self, 'extra_args'):
697 return self.extra_args
736 return self.extra_args
698 else:
737 else:
699 return []
738 return []
700
739
701 def _create_parser(self, aliases=None, flags=None):
740 def _create_parser(self, aliases=None, flags=None):
702 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
741 self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
703 self._add_arguments(aliases, flags)
742 self._add_arguments(aliases, flags)
704
743
705 def _add_arguments(self, aliases=None, flags=None):
744 def _add_arguments(self, aliases=None, flags=None):
706 raise NotImplementedError("subclasses must implement _add_arguments")
745 raise NotImplementedError("subclasses must implement _add_arguments")
707
746
708 def _parse_args(self, args):
747 def _parse_args(self, args):
709 """self.parser->self.parsed_data"""
748 """self.parser->self.parsed_data"""
710 # decode sys.argv to support unicode command-line options
749 # decode sys.argv to support unicode command-line options
711 enc = DEFAULT_ENCODING
750 enc = DEFAULT_ENCODING
712 uargs = [py3compat.cast_unicode(a, enc) for a in args]
751 uargs = [py3compat.cast_unicode(a, enc) for a in args]
713 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
752 self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
714
753
715 def _convert_to_config(self):
754 def _convert_to_config(self):
716 """self.parsed_data->self.config"""
755 """self.parsed_data->self.config"""
717 for k, v in iteritems(vars(self.parsed_data)):
756 for k, v in iteritems(vars(self.parsed_data)):
718 exec("self.config.%s = v"%k, locals(), globals())
757 exec("self.config.%s = v"%k, locals(), globals())
719
758
720 class KVArgParseConfigLoader(ArgParseConfigLoader):
759 class KVArgParseConfigLoader(ArgParseConfigLoader):
721 """A config loader that loads aliases and flags with argparse,
760 """A config loader that loads aliases and flags with argparse,
722 but will use KVLoader for the rest. This allows better parsing
761 but will use KVLoader for the rest. This allows better parsing
723 of common args, such as `ipython -c 'print 5'`, but still gets
762 of common args, such as `ipython -c 'print 5'`, but still gets
724 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
763 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
725
764
726 def _add_arguments(self, aliases=None, flags=None):
765 def _add_arguments(self, aliases=None, flags=None):
727 self.alias_flags = {}
766 self.alias_flags = {}
728 # print aliases, flags
767 # print aliases, flags
729 if aliases is None:
768 if aliases is None:
730 aliases = self.aliases
769 aliases = self.aliases
731 if flags is None:
770 if flags is None:
732 flags = self.flags
771 flags = self.flags
733 paa = self.parser.add_argument
772 paa = self.parser.add_argument
734 for key,value in iteritems(aliases):
773 for key,value in iteritems(aliases):
735 if key in flags:
774 if key in flags:
736 # flags
775 # flags
737 nargs = '?'
776 nargs = '?'
738 else:
777 else:
739 nargs = None
778 nargs = None
740 if len(key) is 1:
779 if len(key) is 1:
741 paa('-'+key, '--'+key, type=unicode_type, dest=value, nargs=nargs)
780 paa('-'+key, '--'+key, type=unicode_type, dest=value, nargs=nargs)
742 else:
781 else:
743 paa('--'+key, type=unicode_type, dest=value, nargs=nargs)
782 paa('--'+key, type=unicode_type, dest=value, nargs=nargs)
744 for key, (value, help) in iteritems(flags):
783 for key, (value, help) in iteritems(flags):
745 if key in self.aliases:
784 if key in self.aliases:
746 #
785 #
747 self.alias_flags[self.aliases[key]] = value
786 self.alias_flags[self.aliases[key]] = value
748 continue
787 continue
749 if len(key) is 1:
788 if len(key) is 1:
750 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
789 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
751 else:
790 else:
752 paa('--'+key, action='append_const', dest='_flags', const=value)
791 paa('--'+key, action='append_const', dest='_flags', const=value)
753
792
754 def _convert_to_config(self):
793 def _convert_to_config(self):
755 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
794 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
756 # remove subconfigs list from namespace before transforming the Namespace
795 # remove subconfigs list from namespace before transforming the Namespace
757 if '_flags' in self.parsed_data:
796 if '_flags' in self.parsed_data:
758 subcs = self.parsed_data._flags
797 subcs = self.parsed_data._flags
759 del self.parsed_data._flags
798 del self.parsed_data._flags
760 else:
799 else:
761 subcs = []
800 subcs = []
762
801
763 for k, v in iteritems(vars(self.parsed_data)):
802 for k, v in iteritems(vars(self.parsed_data)):
764 if v is None:
803 if v is None:
765 # it was a flag that shares the name of an alias
804 # it was a flag that shares the name of an alias
766 subcs.append(self.alias_flags[k])
805 subcs.append(self.alias_flags[k])
767 else:
806 else:
768 # eval the KV assignment
807 # eval the KV assignment
769 self._exec_config_str(k, v)
808 self._exec_config_str(k, v)
770
809
771 for subc in subcs:
810 for subc in subcs:
772 self._load_flag(subc)
811 self._load_flag(subc)
773
812
774 if self.extra_args:
813 if self.extra_args:
775 sub_parser = KeyValueConfigLoader()
814 sub_parser = KeyValueConfigLoader(log=self.log)
776 sub_parser.load_config(self.extra_args)
815 sub_parser.load_config(self.extra_args)
777 self.config.merge(sub_parser.config)
816 self.config.merge(sub_parser.config)
778 self.extra_args = sub_parser.extra_args
817 self.extra_args = sub_parser.extra_args
779
818
780
819
781 def load_pyconfig_files(config_files, path):
820 def load_pyconfig_files(config_files, path):
782 """Load multiple Python config files, merging each of them in turn.
821 """Load multiple Python config files, merging each of them in turn.
783
822
784 Parameters
823 Parameters
785 ==========
824 ==========
786 config_files : list of str
825 config_files : list of str
787 List of config files names to load and merge into the config.
826 List of config files names to load and merge into the config.
788 path : unicode
827 path : unicode
789 The full path to the location of the config files.
828 The full path to the location of the config files.
790 """
829 """
791 config = Config()
830 config = Config()
792 for cf in config_files:
831 for cf in config_files:
793 loader = PyFileConfigLoader(cf, path=path)
832 loader = PyFileConfigLoader(cf, path=path)
794 try:
833 try:
795 next_config = loader.load_config()
834 next_config = loader.load_config()
796 except ConfigFileNotFound:
835 except ConfigFileNotFound:
797 pass
836 pass
798 except:
837 except:
799 raise
838 raise
800 else:
839 else:
801 config.merge(next_config)
840 config.merge(next_config)
802 return config
841 return config
@@ -1,337 +1,388 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for IPython.config.loader
3 Tests for IPython.config.loader
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez (design help)
8 * Fernando Perez (design help)
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import os
22 import os
23 import pickle
23 import pickle
24 import sys
24 import sys
25 import json
26
25 from tempfile import mkstemp
27 from tempfile import mkstemp
26 from unittest import TestCase
28 from unittest import TestCase
27
29
28 from nose import SkipTest
30 from nose import SkipTest
31 import nose.tools as nt
32
29
33
30 from IPython.testing.tools import mute_warn
31
34
32 from IPython.config.loader import (
35 from IPython.config.loader import (
33 Config,
36 Config,
34 LazyConfigValue,
37 LazyConfigValue,
35 PyFileConfigLoader,
38 PyFileConfigLoader,
39 JSONFileConfigLoader,
36 KeyValueConfigLoader,
40 KeyValueConfigLoader,
37 ArgParseConfigLoader,
41 ArgParseConfigLoader,
38 KVArgParseConfigLoader,
42 KVArgParseConfigLoader,
39 ConfigError,
43 ConfigError,
40 )
44 )
41
45
42 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
43 # Actual tests
47 # Actual tests
44 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
45
49
46
50
47 pyfile = """
51 pyfile = """
48 c = get_config()
52 c = get_config()
49 c.a=10
53 c.a=10
50 c.b=20
54 c.b=20
51 c.Foo.Bar.value=10
55 c.Foo.Bar.value=10
52 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
56 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
53 c.D.C.value='hi there'
57 c.D.C.value='hi there'
54 """
58 """
55
59
56 class TestPyFileCL(TestCase):
60 json1file = """
61 {
62 "version": 1,
63 "a": 10,
64 "b": 20,
65 "Foo": {
66 "Bam": {
67 "value": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
68 },
69 "Bar": {
70 "value": 10
71 }
72 },
73 "D": {
74 "C": {
75 "value": "hi there"
76 }
77 }
78 }
79 """
57
80
58 def test_basic(self):
81 # should not load
82 json2file = """
83 {
84 "version": 2
85 }
86 """
87
88 import logging
89 log = logging.getLogger('devnull')
90 log.setLevel(0)
91
92 class TestFileCL(TestCase):
93
94 def _check_conf(self, config):
95 self.assertEqual(config.a, 10)
96 self.assertEqual(config.b, 20)
97 self.assertEqual(config.Foo.Bar.value, 10)
98 self.assertEqual(config.Foo.Bam.value, list(range(10)))
99 self.assertEqual(config.D.C.value, 'hi there')
100
101 def test_python(self):
59 fd, fname = mkstemp('.py')
102 fd, fname = mkstemp('.py')
60 f = os.fdopen(fd, 'w')
103 f = os.fdopen(fd, 'w')
61 f.write(pyfile)
104 f.write(pyfile)
62 f.close()
105 f.close()
63 # Unlink the file
106 # Unlink the file
64 cl = PyFileConfigLoader(fname)
107 cl = PyFileConfigLoader(fname, log=log)
65 config = cl.load_config()
108 config = cl.load_config()
66 self.assertEqual(config.a, 10)
109 self._check_conf(config)
67 self.assertEqual(config.b, 20)
110
68 self.assertEqual(config.Foo.Bar.value, 10)
111 def test_json(self):
69 self.assertEqual(config.Foo.Bam.value, list(range(10)))
112 fd, fname = mkstemp('.json')
70 self.assertEqual(config.D.C.value, 'hi there')
113 f = os.fdopen(fd, 'w')
114 f.write(json1file)
115 f.close()
116 # Unlink the file
117 cl = JSONFileConfigLoader(fname, log=log)
118 config = cl.load_config()
119 self._check_conf(config)
120
121 def test_v2raise(self):
122 fd, fname = mkstemp('.json')
123 f = os.fdopen(fd, 'w')
124 f.write(json2file)
125 f.close()
126 # Unlink the file
127 cl = JSONFileConfigLoader(fname, log=log)
128 with nt.assert_raises(ValueError):
129 cl.load_config()
130
71
131
72 class MyLoader1(ArgParseConfigLoader):
132 class MyLoader1(ArgParseConfigLoader):
73 def _add_arguments(self, aliases=None, flags=None):
133 def _add_arguments(self, aliases=None, flags=None):
74 p = self.parser
134 p = self.parser
75 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
135 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
76 p.add_argument('-b', dest='MyClass.bar', type=int)
136 p.add_argument('-b', dest='MyClass.bar', type=int)
77 p.add_argument('-n', dest='n', action='store_true')
137 p.add_argument('-n', dest='n', action='store_true')
78 p.add_argument('Global.bam', type=str)
138 p.add_argument('Global.bam', type=str)
79
139
80 class MyLoader2(ArgParseConfigLoader):
140 class MyLoader2(ArgParseConfigLoader):
81 def _add_arguments(self, aliases=None, flags=None):
141 def _add_arguments(self, aliases=None, flags=None):
82 subparsers = self.parser.add_subparsers(dest='subparser_name')
142 subparsers = self.parser.add_subparsers(dest='subparser_name')
83 subparser1 = subparsers.add_parser('1')
143 subparser1 = subparsers.add_parser('1')
84 subparser1.add_argument('-x',dest='Global.x')
144 subparser1.add_argument('-x',dest='Global.x')
85 subparser2 = subparsers.add_parser('2')
145 subparser2 = subparsers.add_parser('2')
86 subparser2.add_argument('y')
146 subparser2.add_argument('y')
87
147
88 class TestArgParseCL(TestCase):
148 class TestArgParseCL(TestCase):
89
149
90 def test_basic(self):
150 def test_basic(self):
91 cl = MyLoader1()
151 cl = MyLoader1()
92 config = cl.load_config('-f hi -b 10 -n wow'.split())
152 config = cl.load_config('-f hi -b 10 -n wow'.split())
93 self.assertEqual(config.Global.foo, 'hi')
153 self.assertEqual(config.Global.foo, 'hi')
94 self.assertEqual(config.MyClass.bar, 10)
154 self.assertEqual(config.MyClass.bar, 10)
95 self.assertEqual(config.n, True)
155 self.assertEqual(config.n, True)
96 self.assertEqual(config.Global.bam, 'wow')
156 self.assertEqual(config.Global.bam, 'wow')
97 config = cl.load_config(['wow'])
157 config = cl.load_config(['wow'])
98 self.assertEqual(list(config.keys()), ['Global'])
158 self.assertEqual(list(config.keys()), ['Global'])
99 self.assertEqual(list(config.Global.keys()), ['bam'])
159 self.assertEqual(list(config.Global.keys()), ['bam'])
100 self.assertEqual(config.Global.bam, 'wow')
160 self.assertEqual(config.Global.bam, 'wow')
101
161
102 def test_add_arguments(self):
162 def test_add_arguments(self):
103 cl = MyLoader2()
163 cl = MyLoader2()
104 config = cl.load_config('2 frobble'.split())
164 config = cl.load_config('2 frobble'.split())
105 self.assertEqual(config.subparser_name, '2')
165 self.assertEqual(config.subparser_name, '2')
106 self.assertEqual(config.y, 'frobble')
166 self.assertEqual(config.y, 'frobble')
107 config = cl.load_config('1 -x frobble'.split())
167 config = cl.load_config('1 -x frobble'.split())
108 self.assertEqual(config.subparser_name, '1')
168 self.assertEqual(config.subparser_name, '1')
109 self.assertEqual(config.Global.x, 'frobble')
169 self.assertEqual(config.Global.x, 'frobble')
110
170
111 def test_argv(self):
171 def test_argv(self):
112 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
172 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
113 config = cl.load_config()
173 config = cl.load_config()
114 self.assertEqual(config.Global.foo, 'hi')
174 self.assertEqual(config.Global.foo, 'hi')
115 self.assertEqual(config.MyClass.bar, 10)
175 self.assertEqual(config.MyClass.bar, 10)
116 self.assertEqual(config.n, True)
176 self.assertEqual(config.n, True)
117 self.assertEqual(config.Global.bam, 'wow')
177 self.assertEqual(config.Global.bam, 'wow')
118
178
119
179
120 class TestKeyValueCL(TestCase):
180 class TestKeyValueCL(TestCase):
121 klass = KeyValueConfigLoader
181 klass = KeyValueConfigLoader
122
182
123 def test_basic(self):
183 def test_basic(self):
124 cl = self.klass()
184 cl = self.klass(log=log)
125 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
185 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
126 with mute_warn():
186 config = cl.load_config(argv)
127 config = cl.load_config(argv)
128 self.assertEqual(config.a, 10)
187 self.assertEqual(config.a, 10)
129 self.assertEqual(config.b, 20)
188 self.assertEqual(config.b, 20)
130 self.assertEqual(config.Foo.Bar.value, 10)
189 self.assertEqual(config.Foo.Bar.value, 10)
131 self.assertEqual(config.Foo.Bam.value, list(range(10)))
190 self.assertEqual(config.Foo.Bam.value, list(range(10)))
132 self.assertEqual(config.D.C.value, 'hi there')
191 self.assertEqual(config.D.C.value, 'hi there')
133
192
134 def test_expanduser(self):
193 def test_expanduser(self):
135 cl = self.klass()
194 cl = self.klass(log=log)
136 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
195 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
137 with mute_warn():
196 config = cl.load_config(argv)
138 config = cl.load_config(argv)
139 self.assertEqual(config.a, os.path.expanduser('~/1/2/3'))
197 self.assertEqual(config.a, os.path.expanduser('~/1/2/3'))
140 self.assertEqual(config.b, os.path.expanduser('~'))
198 self.assertEqual(config.b, os.path.expanduser('~'))
141 self.assertEqual(config.c, os.path.expanduser('~/'))
199 self.assertEqual(config.c, os.path.expanduser('~/'))
142 self.assertEqual(config.d, '~/')
200 self.assertEqual(config.d, '~/')
143
201
144 def test_extra_args(self):
202 def test_extra_args(self):
145 cl = self.klass()
203 cl = self.klass(log=log)
146 with mute_warn():
204 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
147 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
148 self.assertEqual(cl.extra_args, ['b', 'd'])
205 self.assertEqual(cl.extra_args, ['b', 'd'])
149 self.assertEqual(config.a, 5)
206 self.assertEqual(config.a, 5)
150 self.assertEqual(config.c, 10)
207 self.assertEqual(config.c, 10)
151 with mute_warn():
208 config = cl.load_config(['--', '--a=5', '--c=10'])
152 config = cl.load_config(['--', '--a=5', '--c=10'])
153 self.assertEqual(cl.extra_args, ['--a=5', '--c=10'])
209 self.assertEqual(cl.extra_args, ['--a=5', '--c=10'])
154
210
155 def test_unicode_args(self):
211 def test_unicode_args(self):
156 cl = self.klass()
212 cl = self.klass(log=log)
157 argv = [u'--a=épsîlön']
213 argv = [u'--a=épsîlön']
158 with mute_warn():
214 config = cl.load_config(argv)
159 config = cl.load_config(argv)
160 self.assertEqual(config.a, u'épsîlön')
215 self.assertEqual(config.a, u'épsîlön')
161
216
162 def test_unicode_bytes_args(self):
217 def test_unicode_bytes_args(self):
163 uarg = u'--a=é'
218 uarg = u'--a=é'
164 try:
219 try:
165 barg = uarg.encode(sys.stdin.encoding)
220 barg = uarg.encode(sys.stdin.encoding)
166 except (TypeError, UnicodeEncodeError):
221 except (TypeError, UnicodeEncodeError):
167 raise SkipTest("sys.stdin.encoding can't handle 'é'")
222 raise SkipTest("sys.stdin.encoding can't handle 'é'")
168
223
169 cl = self.klass()
224 cl = self.klass(log=log)
170 with mute_warn():
225 config = cl.load_config([barg])
171 config = cl.load_config([barg])
172 self.assertEqual(config.a, u'é')
226 self.assertEqual(config.a, u'é')
173
227
174 def test_unicode_alias(self):
228 def test_unicode_alias(self):
175 cl = self.klass()
229 cl = self.klass(log=log)
176 argv = [u'--a=épsîlön']
230 argv = [u'--a=épsîlön']
177 with mute_warn():
231 config = cl.load_config(argv, aliases=dict(a='A.a'))
178 config = cl.load_config(argv, aliases=dict(a='A.a'))
179 self.assertEqual(config.A.a, u'épsîlön')
232 self.assertEqual(config.A.a, u'épsîlön')
180
233
181
234
182 class TestArgParseKVCL(TestKeyValueCL):
235 class TestArgParseKVCL(TestKeyValueCL):
183 klass = KVArgParseConfigLoader
236 klass = KVArgParseConfigLoader
184
237
185 def test_expanduser2(self):
238 def test_expanduser2(self):
186 cl = self.klass()
239 cl = self.klass(log=log)
187 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
240 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
188 with mute_warn():
241 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
189 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
190 self.assertEqual(config.A.a, os.path.expanduser('~/1/2/3'))
242 self.assertEqual(config.A.a, os.path.expanduser('~/1/2/3'))
191 self.assertEqual(config.A.b, '~/1/2/3')
243 self.assertEqual(config.A.b, '~/1/2/3')
192
244
193 def test_eval(self):
245 def test_eval(self):
194 cl = self.klass()
246 cl = self.klass(log=log)
195 argv = ['-c', 'a=5']
247 argv = ['-c', 'a=5']
196 with mute_warn():
248 config = cl.load_config(argv, aliases=dict(c='A.c'))
197 config = cl.load_config(argv, aliases=dict(c='A.c'))
198 self.assertEqual(config.A.c, u"a=5")
249 self.assertEqual(config.A.c, u"a=5")
199
250
200
251
201 class TestConfig(TestCase):
252 class TestConfig(TestCase):
202
253
203 def test_setget(self):
254 def test_setget(self):
204 c = Config()
255 c = Config()
205 c.a = 10
256 c.a = 10
206 self.assertEqual(c.a, 10)
257 self.assertEqual(c.a, 10)
207 self.assertEqual('b' in c, False)
258 self.assertEqual('b' in c, False)
208
259
209 def test_auto_section(self):
260 def test_auto_section(self):
210 c = Config()
261 c = Config()
211 self.assertNotIn('A', c)
262 self.assertNotIn('A', c)
212 assert not c._has_section('A')
263 assert not c._has_section('A')
213 A = c.A
264 A = c.A
214 A.foo = 'hi there'
265 A.foo = 'hi there'
215 self.assertIn('A', c)
266 self.assertIn('A', c)
216 assert c._has_section('A')
267 assert c._has_section('A')
217 self.assertEqual(c.A.foo, 'hi there')
268 self.assertEqual(c.A.foo, 'hi there')
218 del c.A
269 del c.A
219 self.assertEqual(c.A, Config())
270 self.assertEqual(c.A, Config())
220
271
221 def test_merge_doesnt_exist(self):
272 def test_merge_doesnt_exist(self):
222 c1 = Config()
273 c1 = Config()
223 c2 = Config()
274 c2 = Config()
224 c2.bar = 10
275 c2.bar = 10
225 c2.Foo.bar = 10
276 c2.Foo.bar = 10
226 c1.merge(c2)
277 c1.merge(c2)
227 self.assertEqual(c1.Foo.bar, 10)
278 self.assertEqual(c1.Foo.bar, 10)
228 self.assertEqual(c1.bar, 10)
279 self.assertEqual(c1.bar, 10)
229 c2.Bar.bar = 10
280 c2.Bar.bar = 10
230 c1.merge(c2)
281 c1.merge(c2)
231 self.assertEqual(c1.Bar.bar, 10)
282 self.assertEqual(c1.Bar.bar, 10)
232
283
233 def test_merge_exists(self):
284 def test_merge_exists(self):
234 c1 = Config()
285 c1 = Config()
235 c2 = Config()
286 c2 = Config()
236 c1.Foo.bar = 10
287 c1.Foo.bar = 10
237 c1.Foo.bam = 30
288 c1.Foo.bam = 30
238 c2.Foo.bar = 20
289 c2.Foo.bar = 20
239 c2.Foo.wow = 40
290 c2.Foo.wow = 40
240 c1.merge(c2)
291 c1.merge(c2)
241 self.assertEqual(c1.Foo.bam, 30)
292 self.assertEqual(c1.Foo.bam, 30)
242 self.assertEqual(c1.Foo.bar, 20)
293 self.assertEqual(c1.Foo.bar, 20)
243 self.assertEqual(c1.Foo.wow, 40)
294 self.assertEqual(c1.Foo.wow, 40)
244 c2.Foo.Bam.bam = 10
295 c2.Foo.Bam.bam = 10
245 c1.merge(c2)
296 c1.merge(c2)
246 self.assertEqual(c1.Foo.Bam.bam, 10)
297 self.assertEqual(c1.Foo.Bam.bam, 10)
247
298
248 def test_deepcopy(self):
299 def test_deepcopy(self):
249 c1 = Config()
300 c1 = Config()
250 c1.Foo.bar = 10
301 c1.Foo.bar = 10
251 c1.Foo.bam = 30
302 c1.Foo.bam = 30
252 c1.a = 'asdf'
303 c1.a = 'asdf'
253 c1.b = range(10)
304 c1.b = range(10)
254 import copy
305 import copy
255 c2 = copy.deepcopy(c1)
306 c2 = copy.deepcopy(c1)
256 self.assertEqual(c1, c2)
307 self.assertEqual(c1, c2)
257 self.assertTrue(c1 is not c2)
308 self.assertTrue(c1 is not c2)
258 self.assertTrue(c1.Foo is not c2.Foo)
309 self.assertTrue(c1.Foo is not c2.Foo)
259
310
260 def test_builtin(self):
311 def test_builtin(self):
261 c1 = Config()
312 c1 = Config()
262 c1.format = "json"
313 c1.format = "json"
263
314
264 def test_fromdict(self):
315 def test_fromdict(self):
265 c1 = Config({'Foo' : {'bar' : 1}})
316 c1 = Config({'Foo' : {'bar' : 1}})
266 self.assertEqual(c1.Foo.__class__, Config)
317 self.assertEqual(c1.Foo.__class__, Config)
267 self.assertEqual(c1.Foo.bar, 1)
318 self.assertEqual(c1.Foo.bar, 1)
268
319
269 def test_fromdictmerge(self):
320 def test_fromdictmerge(self):
270 c1 = Config()
321 c1 = Config()
271 c2 = Config({'Foo' : {'bar' : 1}})
322 c2 = Config({'Foo' : {'bar' : 1}})
272 c1.merge(c2)
323 c1.merge(c2)
273 self.assertEqual(c1.Foo.__class__, Config)
324 self.assertEqual(c1.Foo.__class__, Config)
274 self.assertEqual(c1.Foo.bar, 1)
325 self.assertEqual(c1.Foo.bar, 1)
275
326
276 def test_fromdictmerge2(self):
327 def test_fromdictmerge2(self):
277 c1 = Config({'Foo' : {'baz' : 2}})
328 c1 = Config({'Foo' : {'baz' : 2}})
278 c2 = Config({'Foo' : {'bar' : 1}})
329 c2 = Config({'Foo' : {'bar' : 1}})
279 c1.merge(c2)
330 c1.merge(c2)
280 self.assertEqual(c1.Foo.__class__, Config)
331 self.assertEqual(c1.Foo.__class__, Config)
281 self.assertEqual(c1.Foo.bar, 1)
332 self.assertEqual(c1.Foo.bar, 1)
282 self.assertEqual(c1.Foo.baz, 2)
333 self.assertEqual(c1.Foo.baz, 2)
283 self.assertNotIn('baz', c2.Foo)
334 self.assertNotIn('baz', c2.Foo)
284
335
285 def test_contains(self):
336 def test_contains(self):
286 c1 = Config({'Foo' : {'baz' : 2}})
337 c1 = Config({'Foo' : {'baz' : 2}})
287 c2 = Config({'Foo' : {'bar' : 1}})
338 c2 = Config({'Foo' : {'bar' : 1}})
288 self.assertIn('Foo', c1)
339 self.assertIn('Foo', c1)
289 self.assertIn('Foo.baz', c1)
340 self.assertIn('Foo.baz', c1)
290 self.assertIn('Foo.bar', c2)
341 self.assertIn('Foo.bar', c2)
291 self.assertNotIn('Foo.bar', c1)
342 self.assertNotIn('Foo.bar', c1)
292
343
293 def test_pickle_config(self):
344 def test_pickle_config(self):
294 cfg = Config()
345 cfg = Config()
295 cfg.Foo.bar = 1
346 cfg.Foo.bar = 1
296 pcfg = pickle.dumps(cfg)
347 pcfg = pickle.dumps(cfg)
297 cfg2 = pickle.loads(pcfg)
348 cfg2 = pickle.loads(pcfg)
298 self.assertEqual(cfg2, cfg)
349 self.assertEqual(cfg2, cfg)
299
350
300 def test_getattr_section(self):
351 def test_getattr_section(self):
301 cfg = Config()
352 cfg = Config()
302 self.assertNotIn('Foo', cfg)
353 self.assertNotIn('Foo', cfg)
303 Foo = cfg.Foo
354 Foo = cfg.Foo
304 assert isinstance(Foo, Config)
355 assert isinstance(Foo, Config)
305 self.assertIn('Foo', cfg)
356 self.assertIn('Foo', cfg)
306
357
307 def test_getitem_section(self):
358 def test_getitem_section(self):
308 cfg = Config()
359 cfg = Config()
309 self.assertNotIn('Foo', cfg)
360 self.assertNotIn('Foo', cfg)
310 Foo = cfg['Foo']
361 Foo = cfg['Foo']
311 assert isinstance(Foo, Config)
362 assert isinstance(Foo, Config)
312 self.assertIn('Foo', cfg)
363 self.assertIn('Foo', cfg)
313
364
314 def test_getattr_not_section(self):
365 def test_getattr_not_section(self):
315 cfg = Config()
366 cfg = Config()
316 self.assertNotIn('foo', cfg)
367 self.assertNotIn('foo', cfg)
317 foo = cfg.foo
368 foo = cfg.foo
318 assert isinstance(foo, LazyConfigValue)
369 assert isinstance(foo, LazyConfigValue)
319 self.assertIn('foo', cfg)
370 self.assertIn('foo', cfg)
320
371
321 def test_getitem_not_section(self):
372 def test_getitem_not_section(self):
322 cfg = Config()
373 cfg = Config()
323 self.assertNotIn('foo', cfg)
374 self.assertNotIn('foo', cfg)
324 foo = cfg['foo']
375 foo = cfg['foo']
325 assert isinstance(foo, LazyConfigValue)
376 assert isinstance(foo, LazyConfigValue)
326 self.assertIn('foo', cfg)
377 self.assertIn('foo', cfg)
327
378
328 def test_merge_copies(self):
379 def test_merge_copies(self):
329 c = Config()
380 c = Config()
330 c2 = Config()
381 c2 = Config()
331 c2.Foo.trait = []
382 c2.Foo.trait = []
332 c.merge(c2)
383 c.merge(c2)
333 c2.Foo.trait.append(1)
384 c2.Foo.trait.append(1)
334 self.assertIsNot(c.Foo, c2.Foo)
385 self.assertIsNot(c.Foo, c2.Foo)
335 self.assertEqual(c.Foo.trait, [])
386 self.assertEqual(c.Foo.trait, [])
336 self.assertEqual(c2.Foo.trait, [1])
387 self.assertEqual(c2.Foo.trait, [1])
337
388
@@ -1,389 +1,387 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min Ragan-Kelley
12 * Min Ragan-Kelley
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2011 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 from __future__ import absolute_import
26 from __future__ import absolute_import
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 import logging
29 import logging
30 import os
30 import os
31 import sys
31 import sys
32
32
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 Config, PyFileConfigLoader, ConfigFileNotFound
34 Config, PyFileConfigLoader, ConfigFileNotFound
35 )
35 )
36 from IPython.config.application import boolean_flag, catch_config_error
36 from IPython.config.application import boolean_flag, catch_config_error, Application
37 from IPython.core import release
37 from IPython.core import release
38 from IPython.core import usage
38 from IPython.core import usage
39 from IPython.core.completer import IPCompleter
39 from IPython.core.completer import IPCompleter
40 from IPython.core.crashhandler import CrashHandler
40 from IPython.core.crashhandler import CrashHandler
41 from IPython.core.formatters import PlainTextFormatter
41 from IPython.core.formatters import PlainTextFormatter
42 from IPython.core.history import HistoryManager
42 from IPython.core.history import HistoryManager
43 from IPython.core.prompts import PromptManager
43 from IPython.core.prompts import PromptManager
44 from IPython.core.application import (
44 from IPython.core.application import (
45 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
45 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
46 )
46 )
47 from IPython.core.magics import ScriptMagics
47 from IPython.core.magics import ScriptMagics
48 from IPython.core.shellapp import (
48 from IPython.core.shellapp import (
49 InteractiveShellApp, shell_flags, shell_aliases
49 InteractiveShellApp, shell_flags, shell_aliases
50 )
50 )
51 from IPython.extensions.storemagic import StoreMagics
51 from IPython.extensions.storemagic import StoreMagics
52 from IPython.terminal.interactiveshell import TerminalInteractiveShell
52 from IPython.terminal.interactiveshell import TerminalInteractiveShell
53 from IPython.utils import warn
53 from IPython.utils import warn
54 from IPython.utils.path import get_ipython_dir, check_for_old_config
54 from IPython.utils.path import get_ipython_dir, check_for_old_config
55 from IPython.utils.traitlets import (
55 from IPython.utils.traitlets import (
56 Bool, List, Dict,
56 Bool, List, Dict,
57 )
57 )
58
58
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60 # Globals, utilities and helpers
60 # Globals, utilities and helpers
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62
62
63 _examples = """
63 _examples = """
64 ipython --matplotlib # enable matplotlib integration
64 ipython --matplotlib # enable matplotlib integration
65 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
65 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
66
66
67 ipython --log-level=DEBUG # set logging to DEBUG
67 ipython --log-level=DEBUG # set logging to DEBUG
68 ipython --profile=foo # start with profile foo
68 ipython --profile=foo # start with profile foo
69
69
70 ipython qtconsole # start the qtconsole GUI application
70 ipython qtconsole # start the qtconsole GUI application
71 ipython help qtconsole # show the help for the qtconsole subcmd
71 ipython help qtconsole # show the help for the qtconsole subcmd
72
72
73 ipython console # start the terminal-based console application
73 ipython console # start the terminal-based console application
74 ipython help console # show the help for the console subcmd
74 ipython help console # show the help for the console subcmd
75
75
76 ipython notebook # start the IPython notebook
76 ipython notebook # start the IPython notebook
77 ipython help notebook # show the help for the notebook subcmd
77 ipython help notebook # show the help for the notebook subcmd
78
78
79 ipython profile create foo # create profile foo w/ default config files
79 ipython profile create foo # create profile foo w/ default config files
80 ipython help profile # show the help for the profile subcmd
80 ipython help profile # show the help for the profile subcmd
81
81
82 ipython locate # print the path to the IPython directory
82 ipython locate # print the path to the IPython directory
83 ipython locate profile foo # print the path to the directory for profile `foo`
83 ipython locate profile foo # print the path to the directory for profile `foo`
84
84
85 ipython nbconvert # convert notebooks to/from other formats
85 ipython nbconvert # convert notebooks to/from other formats
86 """
86 """
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Crash handler for this application
89 # Crash handler for this application
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92 class IPAppCrashHandler(CrashHandler):
92 class IPAppCrashHandler(CrashHandler):
93 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
93 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
94
94
95 def __init__(self, app):
95 def __init__(self, app):
96 contact_name = release.author
96 contact_name = release.author
97 contact_email = release.author_email
97 contact_email = release.author_email
98 bug_tracker = 'https://github.com/ipython/ipython/issues'
98 bug_tracker = 'https://github.com/ipython/ipython/issues'
99 super(IPAppCrashHandler,self).__init__(
99 super(IPAppCrashHandler,self).__init__(
100 app, contact_name, contact_email, bug_tracker
100 app, contact_name, contact_email, bug_tracker
101 )
101 )
102
102
103 def make_report(self,traceback):
103 def make_report(self,traceback):
104 """Return a string containing a crash report."""
104 """Return a string containing a crash report."""
105
105
106 sec_sep = self.section_sep
106 sec_sep = self.section_sep
107 # Start with parent report
107 # Start with parent report
108 report = [super(IPAppCrashHandler, self).make_report(traceback)]
108 report = [super(IPAppCrashHandler, self).make_report(traceback)]
109 # Add interactive-specific info we may have
109 # Add interactive-specific info we may have
110 rpt_add = report.append
110 rpt_add = report.append
111 try:
111 try:
112 rpt_add(sec_sep+"History of session input:")
112 rpt_add(sec_sep+"History of session input:")
113 for line in self.app.shell.user_ns['_ih']:
113 for line in self.app.shell.user_ns['_ih']:
114 rpt_add(line)
114 rpt_add(line)
115 rpt_add('\n*** Last line of input (may not be in above history):\n')
115 rpt_add('\n*** Last line of input (may not be in above history):\n')
116 rpt_add(self.app.shell._last_input_line+'\n')
116 rpt_add(self.app.shell._last_input_line+'\n')
117 except:
117 except:
118 pass
118 pass
119
119
120 return ''.join(report)
120 return ''.join(report)
121
121
122 #-----------------------------------------------------------------------------
122 #-----------------------------------------------------------------------------
123 # Aliases and Flags
123 # Aliases and Flags
124 #-----------------------------------------------------------------------------
124 #-----------------------------------------------------------------------------
125 flags = dict(base_flags)
125 flags = dict(base_flags)
126 flags.update(shell_flags)
126 flags.update(shell_flags)
127 frontend_flags = {}
127 frontend_flags = {}
128 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
128 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
129 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
129 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
130 'Turn on auto editing of files with syntax errors.',
130 'Turn on auto editing of files with syntax errors.',
131 'Turn off auto editing of files with syntax errors.'
131 'Turn off auto editing of files with syntax errors.'
132 )
132 )
133 addflag('banner', 'TerminalIPythonApp.display_banner',
133 addflag('banner', 'TerminalIPythonApp.display_banner',
134 "Display a banner upon starting IPython.",
134 "Display a banner upon starting IPython.",
135 "Don't display a banner upon starting IPython."
135 "Don't display a banner upon starting IPython."
136 )
136 )
137 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
137 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
138 """Set to confirm when you try to exit IPython with an EOF (Control-D
138 """Set to confirm when you try to exit IPython with an EOF (Control-D
139 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
139 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
140 you can force a direct exit without any confirmation.""",
140 you can force a direct exit without any confirmation.""",
141 "Don't prompt the user when exiting."
141 "Don't prompt the user when exiting."
142 )
142 )
143 addflag('term-title', 'TerminalInteractiveShell.term_title',
143 addflag('term-title', 'TerminalInteractiveShell.term_title',
144 "Enable auto setting the terminal title.",
144 "Enable auto setting the terminal title.",
145 "Disable auto setting the terminal title."
145 "Disable auto setting the terminal title."
146 )
146 )
147 classic_config = Config()
147 classic_config = Config()
148 classic_config.InteractiveShell.cache_size = 0
148 classic_config.InteractiveShell.cache_size = 0
149 classic_config.PlainTextFormatter.pprint = False
149 classic_config.PlainTextFormatter.pprint = False
150 classic_config.PromptManager.in_template = '>>> '
150 classic_config.PromptManager.in_template = '>>> '
151 classic_config.PromptManager.in2_template = '... '
151 classic_config.PromptManager.in2_template = '... '
152 classic_config.PromptManager.out_template = ''
152 classic_config.PromptManager.out_template = ''
153 classic_config.InteractiveShell.separate_in = ''
153 classic_config.InteractiveShell.separate_in = ''
154 classic_config.InteractiveShell.separate_out = ''
154 classic_config.InteractiveShell.separate_out = ''
155 classic_config.InteractiveShell.separate_out2 = ''
155 classic_config.InteractiveShell.separate_out2 = ''
156 classic_config.InteractiveShell.colors = 'NoColor'
156 classic_config.InteractiveShell.colors = 'NoColor'
157 classic_config.InteractiveShell.xmode = 'Plain'
157 classic_config.InteractiveShell.xmode = 'Plain'
158
158
159 frontend_flags['classic']=(
159 frontend_flags['classic']=(
160 classic_config,
160 classic_config,
161 "Gives IPython a similar feel to the classic Python prompt."
161 "Gives IPython a similar feel to the classic Python prompt."
162 )
162 )
163 # # log doesn't make so much sense this way anymore
163 # # log doesn't make so much sense this way anymore
164 # paa('--log','-l',
164 # paa('--log','-l',
165 # action='store_true', dest='InteractiveShell.logstart',
165 # action='store_true', dest='InteractiveShell.logstart',
166 # help="Start logging to the default log file (./ipython_log.py).")
166 # help="Start logging to the default log file (./ipython_log.py).")
167 #
167 #
168 # # quick is harder to implement
168 # # quick is harder to implement
169 frontend_flags['quick']=(
169 frontend_flags['quick']=(
170 {'TerminalIPythonApp' : {'quick' : True}},
170 {'TerminalIPythonApp' : {'quick' : True}},
171 "Enable quick startup with no config files."
171 "Enable quick startup with no config files."
172 )
172 )
173
173
174 frontend_flags['i'] = (
174 frontend_flags['i'] = (
175 {'TerminalIPythonApp' : {'force_interact' : True}},
175 {'TerminalIPythonApp' : {'force_interact' : True}},
176 """If running code from the command line, become interactive afterwards.
176 """If running code from the command line, become interactive afterwards.
177 Note: can also be given simply as '-i.'"""
177 Note: can also be given simply as '-i.'"""
178 )
178 )
179 flags.update(frontend_flags)
179 flags.update(frontend_flags)
180
180
181 aliases = dict(base_aliases)
181 aliases = dict(base_aliases)
182 aliases.update(shell_aliases)
182 aliases.update(shell_aliases)
183
183
184 #-----------------------------------------------------------------------------
184 #-----------------------------------------------------------------------------
185 # Main classes and functions
185 # Main classes and functions
186 #-----------------------------------------------------------------------------
186 #-----------------------------------------------------------------------------
187
187
188
188
189 class LocateIPythonApp(BaseIPythonApplication):
189 class LocateIPythonApp(BaseIPythonApplication):
190 description = """print the path to the IPython dir"""
190 description = """print the path to the IPython dir"""
191 subcommands = Dict(dict(
191 subcommands = Dict(dict(
192 profile=('IPython.core.profileapp.ProfileLocate',
192 profile=('IPython.core.profileapp.ProfileLocate',
193 "print the path to an IPython profile directory",
193 "print the path to an IPython profile directory",
194 ),
194 ),
195 ))
195 ))
196 def start(self):
196 def start(self):
197 if self.subapp is not None:
197 if self.subapp is not None:
198 return self.subapp.start()
198 return self.subapp.start()
199 else:
199 else:
200 print(self.ipython_dir)
200 print(self.ipython_dir)
201
201
202
202
203 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
203 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
204 name = u'ipython'
204 name = u'ipython'
205 description = usage.cl_usage
205 description = usage.cl_usage
206 crash_handler_class = IPAppCrashHandler
206 crash_handler_class = IPAppCrashHandler
207 examples = _examples
207 examples = _examples
208
208
209 flags = Dict(flags)
209 flags = Dict(flags)
210 aliases = Dict(aliases)
210 aliases = Dict(aliases)
211 classes = List()
211 classes = List()
212 def _classes_default(self):
212 def _classes_default(self):
213 """This has to be in a method, for TerminalIPythonApp to be available."""
213 """This has to be in a method, for TerminalIPythonApp to be available."""
214 return [
214 return [
215 InteractiveShellApp, # ShellApp comes before TerminalApp, because
215 InteractiveShellApp, # ShellApp comes before TerminalApp, because
216 self.__class__, # it will also affect subclasses (e.g. QtConsole)
216 self.__class__, # it will also affect subclasses (e.g. QtConsole)
217 TerminalInteractiveShell,
217 TerminalInteractiveShell,
218 PromptManager,
218 PromptManager,
219 HistoryManager,
219 HistoryManager,
220 ProfileDir,
220 ProfileDir,
221 PlainTextFormatter,
221 PlainTextFormatter,
222 IPCompleter,
222 IPCompleter,
223 ScriptMagics,
223 ScriptMagics,
224 StoreMagics,
224 StoreMagics,
225 ]
225 ]
226
226
227 subcommands = Dict(dict(
227 subcommands = Dict(dict(
228 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
228 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
229 """Launch the IPython Qt Console."""
229 """Launch the IPython Qt Console."""
230 ),
230 ),
231 notebook=('IPython.html.notebookapp.NotebookApp',
231 notebook=('IPython.html.notebookapp.NotebookApp',
232 """Launch the IPython HTML Notebook Server."""
232 """Launch the IPython HTML Notebook Server."""
233 ),
233 ),
234 profile = ("IPython.core.profileapp.ProfileApp",
234 profile = ("IPython.core.profileapp.ProfileApp",
235 "Create and manage IPython profiles."
235 "Create and manage IPython profiles."
236 ),
236 ),
237 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
237 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
238 "Start a kernel without an attached frontend."
238 "Start a kernel without an attached frontend."
239 ),
239 ),
240 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
240 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
241 """Launch the IPython terminal-based Console."""
241 """Launch the IPython terminal-based Console."""
242 ),
242 ),
243 locate=('IPython.terminal.ipapp.LocateIPythonApp',
243 locate=('IPython.terminal.ipapp.LocateIPythonApp',
244 LocateIPythonApp.description
244 LocateIPythonApp.description
245 ),
245 ),
246 history=('IPython.core.historyapp.HistoryApp',
246 history=('IPython.core.historyapp.HistoryApp',
247 "Manage the IPython history database."
247 "Manage the IPython history database."
248 ),
248 ),
249 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
249 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
250 "Convert notebooks to/from other formats."
250 "Convert notebooks to/from other formats."
251 ),
251 ),
252 ))
252 ))
253
253
254 # *do* autocreate requested profile, but don't create the config file.
254 # *do* autocreate requested profile, but don't create the config file.
255 auto_create=Bool(True)
255 auto_create=Bool(True)
256 # configurables
256 # configurables
257 ignore_old_config=Bool(False, config=True,
257 ignore_old_config=Bool(False, config=True,
258 help="Suppress warning messages about legacy config files"
258 help="Suppress warning messages about legacy config files"
259 )
259 )
260 quick = Bool(False, config=True,
260 quick = Bool(False, config=True,
261 help="""Start IPython quickly by skipping the loading of config files."""
261 help="""Start IPython quickly by skipping the loading of config files."""
262 )
262 )
263 def _quick_changed(self, name, old, new):
263 def _quick_changed(self, name, old, new):
264 if new:
264 if new:
265 self.load_config_file = lambda *a, **kw: None
265 self.load_config_file = lambda *a, **kw: None
266 self.ignore_old_config=True
266 self.ignore_old_config=True
267
267
268 display_banner = Bool(True, config=True,
268 display_banner = Bool(True, config=True,
269 help="Whether to display a banner upon starting IPython."
269 help="Whether to display a banner upon starting IPython."
270 )
270 )
271
271
272 # if there is code of files to run from the cmd line, don't interact
272 # if there is code of files to run from the cmd line, don't interact
273 # unless the --i flag (App.force_interact) is true.
273 # unless the --i flag (App.force_interact) is true.
274 force_interact = Bool(False, config=True,
274 force_interact = Bool(False, config=True,
275 help="""If a command or file is given via the command-line,
275 help="""If a command or file is given via the command-line,
276 e.g. 'ipython foo.py"""
276 e.g. 'ipython foo.py"""
277 )
277 )
278 def _force_interact_changed(self, name, old, new):
278 def _force_interact_changed(self, name, old, new):
279 if new:
279 if new:
280 self.interact = True
280 self.interact = True
281
281
282 def _file_to_run_changed(self, name, old, new):
282 def _file_to_run_changed(self, name, old, new):
283 if new:
283 if new:
284 self.something_to_run = True
284 self.something_to_run = True
285 if new and not self.force_interact:
285 if new and not self.force_interact:
286 self.interact = False
286 self.interact = False
287 _code_to_run_changed = _file_to_run_changed
287 _code_to_run_changed = _file_to_run_changed
288 _module_to_run_changed = _file_to_run_changed
288 _module_to_run_changed = _file_to_run_changed
289
289
290 # internal, not-configurable
290 # internal, not-configurable
291 interact=Bool(True)
291 interact=Bool(True)
292 something_to_run=Bool(False)
292 something_to_run=Bool(False)
293
293
294 def parse_command_line(self, argv=None):
294 def parse_command_line(self, argv=None):
295 """override to allow old '-pylab' flag with deprecation warning"""
295 """override to allow old '-pylab' flag with deprecation warning"""
296
296
297 argv = sys.argv[1:] if argv is None else argv
297 argv = sys.argv[1:] if argv is None else argv
298
298
299 if '-pylab' in argv:
299 if '-pylab' in argv:
300 # deprecated `-pylab` given,
300 # deprecated `-pylab` given,
301 # warn and transform into current syntax
301 # warn and transform into current syntax
302 argv = argv[:] # copy, don't clobber
302 argv = argv[:] # copy, don't clobber
303 idx = argv.index('-pylab')
303 idx = argv.index('-pylab')
304 warn.warn("`-pylab` flag has been deprecated.\n"
304 warn.warn("`-pylab` flag has been deprecated.\n"
305 " Use `--matplotlib <backend>` and import pylab manually.")
305 " Use `--matplotlib <backend>` and import pylab manually.")
306 argv[idx] = '--pylab'
306 argv[idx] = '--pylab'
307
307
308 return super(TerminalIPythonApp, self).parse_command_line(argv)
308 return super(TerminalIPythonApp, self).parse_command_line(argv)
309
309
310 @catch_config_error
310 @catch_config_error
311 def initialize(self, argv=None):
311 def initialize(self, argv=None):
312 """Do actions after construct, but before starting the app."""
312 """Do actions after construct, but before starting the app."""
313 super(TerminalIPythonApp, self).initialize(argv)
313 super(TerminalIPythonApp, self).initialize(argv)
314 if self.subapp is not None:
314 if self.subapp is not None:
315 # don't bother initializing further, starting subapp
315 # don't bother initializing further, starting subapp
316 return
316 return
317 if not self.ignore_old_config:
317 if not self.ignore_old_config:
318 check_for_old_config(self.ipython_dir)
318 check_for_old_config(self.ipython_dir)
319 # print self.extra_args
319 # print self.extra_args
320 if self.extra_args and not self.something_to_run:
320 if self.extra_args and not self.something_to_run:
321 self.file_to_run = self.extra_args[0]
321 self.file_to_run = self.extra_args[0]
322 self.init_path()
322 self.init_path()
323 # create the shell
323 # create the shell
324 self.init_shell()
324 self.init_shell()
325 # and draw the banner
325 # and draw the banner
326 self.init_banner()
326 self.init_banner()
327 # Now a variety of things that happen after the banner is printed.
327 # Now a variety of things that happen after the banner is printed.
328 self.init_gui_pylab()
328 self.init_gui_pylab()
329 self.init_extensions()
329 self.init_extensions()
330 self.init_code()
330 self.init_code()
331
331
332 def init_shell(self):
332 def init_shell(self):
333 """initialize the InteractiveShell instance"""
333 """initialize the InteractiveShell instance"""
334 # Create an InteractiveShell instance.
334 # Create an InteractiveShell instance.
335 # shell.display_banner should always be False for the terminal
335 # shell.display_banner should always be False for the terminal
336 # based app, because we call shell.show_banner() by hand below
336 # based app, because we call shell.show_banner() by hand below
337 # so the banner shows *before* all extension loading stuff.
337 # so the banner shows *before* all extension loading stuff.
338 self.shell = TerminalInteractiveShell.instance(parent=self,
338 self.shell = TerminalInteractiveShell.instance(parent=self,
339 display_banner=False, profile_dir=self.profile_dir,
339 display_banner=False, profile_dir=self.profile_dir,
340 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
340 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
341 self.shell.configurables.append(self)
341 self.shell.configurables.append(self)
342
342
343 def init_banner(self):
343 def init_banner(self):
344 """optionally display the banner"""
344 """optionally display the banner"""
345 if self.display_banner and self.interact:
345 if self.display_banner and self.interact:
346 self.shell.show_banner()
346 self.shell.show_banner()
347 # Make sure there is a space below the banner.
347 # Make sure there is a space below the banner.
348 if self.log_level <= logging.INFO: print()
348 if self.log_level <= logging.INFO: print()
349
349
350 def _pylab_changed(self, name, old, new):
350 def _pylab_changed(self, name, old, new):
351 """Replace --pylab='inline' with --pylab='auto'"""
351 """Replace --pylab='inline' with --pylab='auto'"""
352 if new == 'inline':
352 if new == 'inline':
353 warn.warn("'inline' not available as pylab backend, "
353 warn.warn("'inline' not available as pylab backend, "
354 "using 'auto' instead.")
354 "using 'auto' instead.")
355 self.pylab = 'auto'
355 self.pylab = 'auto'
356
356
357 def start(self):
357 def start(self):
358 if self.subapp is not None:
358 if self.subapp is not None:
359 return self.subapp.start()
359 return self.subapp.start()
360 # perform any prexec steps:
360 # perform any prexec steps:
361 if self.interact:
361 if self.interact:
362 self.log.debug("Starting IPython's mainloop...")
362 self.log.debug("Starting IPython's mainloop...")
363 self.shell.mainloop()
363 self.shell.mainloop()
364 else:
364 else:
365 self.log.debug("IPython not interactive...")
365 self.log.debug("IPython not interactive...")
366
366
367
368 def load_default_config(ipython_dir=None):
367 def load_default_config(ipython_dir=None):
369 """Load the default config file from the default ipython_dir.
368 """Load the default config file from the default ipython_dir.
370
369
371 This is useful for embedded shells.
370 This is useful for embedded shells.
372 """
371 """
373 if ipython_dir is None:
372 if ipython_dir is None:
374 ipython_dir = get_ipython_dir()
373 ipython_dir = get_ipython_dir()
374
375 profile_dir = os.path.join(ipython_dir, 'profile_default')
375 profile_dir = os.path.join(ipython_dir, 'profile_default')
376 cl = PyFileConfigLoader("ipython_config.py", profile_dir)
377 try:
378 config = cl.load_config()
379 except ConfigFileNotFound:
380 # no config found
381 config = Config()
382 return config
383
376
377 config = Config()
378 for cf in Application._load_config_file(filename[:-3], path=profile_dir, log=None):
379 config.update(cf)
380
381 return config
384
382
385 launch_new_instance = TerminalIPythonApp.launch_instance
383 launch_new_instance = TerminalIPythonApp.launch_instance
386
384
387
385
388 if __name__ == '__main__':
386 if __name__ == '__main__':
389 launch_new_instance()
387 launch_new_instance()
@@ -1,524 +1,566 b''
1 .. _config_overview:
1 .. _config_overview:
2
2
3 ============================================
3 ============================================
4 Overview of the IPython configuration system
4 Overview of the IPython configuration system
5 ============================================
5 ============================================
6
6
7 This section describes the IPython configuration system.
7 This section describes the IPython configuration system.
8
8
9 The main concepts
9 The main concepts
10 =================
10 =================
11
11
12 There are a number of abstractions that the IPython configuration system uses.
12 There are a number of abstractions that the IPython configuration system uses.
13 Each of these abstractions is represented by a Python class.
13 Each of these abstractions is represented by a Python class.
14
14
15 Configuration object: :class:`~IPython.config.loader.Config`
15 Configuration object: :class:`~IPython.config.loader.Config`
16 A configuration object is a simple dictionary-like class that holds
16 A configuration object is a simple dictionary-like class that holds
17 configuration attributes and sub-configuration objects. These classes
17 configuration attributes and sub-configuration objects. These classes
18 support dotted attribute style access (``Foo.bar``) in addition to the
18 support dotted attribute style access (``cfg.Foo.bar``) in addition to the
19 regular dictionary style access (``Foo['bar']``). Configuration objects
19 regular dictionary style access (``cfg['Foo']['bar']``).
20 are smart. They know how to merge themselves with other configuration
20 The Config object is a wrapper around a simple dictionary with some convenience methods,
21 objects and they automatically create sub-configuration objects.
21 such as merging and automatic section creation.
22
22
23 Application: :class:`~IPython.config.application.Application`
23 Application: :class:`~IPython.config.application.Application`
24 An application is a process that does a specific job. The most obvious
24 An application is a process that does a specific job. The most obvious
25 application is the :command:`ipython` command line program. Each
25 application is the :command:`ipython` command line program. Each
26 application reads *one or more* configuration files and a single set of
26 application reads *one or more* configuration files and a single set of
27 command line options
27 command line options
28 and then produces a master configuration object for the application. This
28 and then produces a master configuration object for the application. This
29 configuration object is then passed to the configurable objects that the
29 configuration object is then passed to the configurable objects that the
30 application creates. These configurable objects implement the actual logic
30 application creates. These configurable objects implement the actual logic
31 of the application and know how to configure themselves given the
31 of the application and know how to configure themselves given the
32 configuration object.
32 configuration object.
33
33
34 Applications always have a `log` attribute that is a configured Logger.
34 Applications always have a `log` attribute that is a configured Logger.
35 This allows centralized logging configuration per-application.
35 This allows centralized logging configuration per-application.
36
36
37 Configurable: :class:`~IPython.config.configurable.Configurable`
37 Configurable: :class:`~IPython.config.configurable.Configurable`
38 A configurable is a regular Python class that serves as a base class for
38 A configurable is a regular Python class that serves as a base class for
39 all main classes in an application. The
39 all main classes in an application. The
40 :class:`~IPython.config.configurable.Configurable` base class is
40 :class:`~IPython.config.configurable.Configurable` base class is
41 lightweight and only does one things.
41 lightweight and only does one things.
42
42
43 This :class:`~IPython.config.configurable.Configurable` is a subclass
43 This :class:`~IPython.config.configurable.Configurable` is a subclass
44 of :class:`~IPython.utils.traitlets.HasTraits` that knows how to configure
44 of :class:`~IPython.utils.traitlets.HasTraits` that knows how to configure
45 itself. Class level traits with the metadata ``config=True`` become
45 itself. Class level traits with the metadata ``config=True`` become
46 values that can be configured from the command line and configuration
46 values that can be configured from the command line and configuration
47 files.
47 files.
48
48
49 Developers create :class:`~IPython.config.configurable.Configurable`
49 Developers create :class:`~IPython.config.configurable.Configurable`
50 subclasses that implement all of the logic in the application. Each of
50 subclasses that implement all of the logic in the application. Each of
51 these subclasses has its own configuration information that controls how
51 these subclasses has its own configuration information that controls how
52 instances are created.
52 instances are created.
53
53
54 Singletons: :class:`~IPython.config.configurable.SingletonConfigurable`
54 Singletons: :class:`~IPython.config.configurable.SingletonConfigurable`
55 Any object for which there is a single canonical instance. These are
55 Any object for which there is a single canonical instance. These are
56 just like Configurables, except they have a class method
56 just like Configurables, except they have a class method
57 :meth:`~IPython.config.configurable.SingletonConfigurable.instance`,
57 :meth:`~IPython.config.configurable.SingletonConfigurable.instance`,
58 that returns the current active instance (or creates one if it
58 that returns the current active instance (or creates one if it
59 does not exist). Examples of singletons include
59 does not exist). Examples of singletons include
60 :class:`~IPython.config.application.Application`s and
60 :class:`~IPython.config.application.Application`s and
61 :class:`~IPython.core.interactiveshell.InteractiveShell`. This lets
61 :class:`~IPython.core.interactiveshell.InteractiveShell`. This lets
62 objects easily connect to the current running Application without passing
62 objects easily connect to the current running Application without passing
63 objects around everywhere. For instance, to get the current running
63 objects around everywhere. For instance, to get the current running
64 Application instance, simply do: ``app = Application.instance()``.
64 Application instance, simply do: ``app = Application.instance()``.
65
65
66
66
67 .. note::
67 .. note::
68
68
69 Singletons are not strictly enforced - you can have many instances
69 Singletons are not strictly enforced - you can have many instances
70 of a given singleton class, but the :meth:`instance` method will always
70 of a given singleton class, but the :meth:`instance` method will always
71 return the same one.
71 return the same one.
72
72
73 Having described these main concepts, we can now state the main idea in our
73 Having described these main concepts, we can now state the main idea in our
74 configuration system: *"configuration" allows the default values of class
74 configuration system: *"configuration" allows the default values of class
75 attributes to be controlled on a class by class basis*. Thus all instances of
75 attributes to be controlled on a class by class basis*. Thus all instances of
76 a given class are configured in the same way. Furthermore, if two instances
76 a given class are configured in the same way. Furthermore, if two instances
77 need to be configured differently, they need to be instances of two different
77 need to be configured differently, they need to be instances of two different
78 classes. While this model may seem a bit restrictive, we have found that it
78 classes. While this model may seem a bit restrictive, we have found that it
79 expresses most things that need to be configured extremely well. However, it
79 expresses most things that need to be configured extremely well. However, it
80 is possible to create two instances of the same class that have different
80 is possible to create two instances of the same class that have different
81 trait values. This is done by overriding the configuration.
81 trait values. This is done by overriding the configuration.
82
82
83 Now, we show what our configuration objects and files look like.
83 Now, we show what our configuration objects and files look like.
84
84
85 Configuration objects and files
85 Configuration objects and files
86 ===============================
86 ===============================
87
87
88 A configuration file is simply a pure Python file that sets the attributes
88 A configuration object is little more than a wrapper around a dictionary.
89 of a global, pre-created configuration object. This configuration object is a
89 A configuration *file* is simply a mechanism for producing that object.
90 :class:`~IPython.config.loader.Config` instance. While in a configuration
90 The main IPython configuration file is a plain Python script,
91 file, to get a reference to this object, simply call the :func:`get_config`
91 which can perform extensive logic to populate the config object.
92 function. We inject this function into the global namespace that the
92 IPython 2.0 introduces a JSON configuration file,
93 configuration file is executed in.
93 which is just a direct JSON serialization of the config dictionary.
94 The JSON format is easily processed by external software.
95
96 When both Python and JSON configuration file are present, both will be loaded,
97 with JSON configuration having higher priority.
98
99 Python configuration Files
100 ~~~~~~~~~~~~~~~~~~~~~~~~~~
101
102 A Python configuration file is a pure Python file that populates a configuration object.
103 This configuration object is a :class:`~IPython.config.loader.Config` instance.
104 While in a configuration file, to get a reference to this object, simply call the :func:`get_config`
105 function, which is available in the global namespace of the script.
94
106
95 Here is an example of a super simple configuration file that does nothing::
107 Here is an example of a super simple configuration file that does nothing::
96
108
97 c = get_config()
109 c = get_config()
98
110
99 Once you get a reference to the configuration object, you simply set
111 Once you get a reference to the configuration object, you simply set
100 attributes on it. All you have to know is:
112 attributes on it. All you have to know is:
101
113
102 * The name of each attribute.
114 * The name of the class to configure.
115 * The name of the attribute.
103 * The type of each attribute.
116 * The type of each attribute.
104
117
105 The answers to these two questions are provided by the various
118 The answers to these questions are provided by the various
106 :class:`~IPython.config.configurable.Configurable` subclasses that an
119 :class:`~IPython.config.configurable.Configurable` subclasses that an
107 application uses. Let's look at how this would work for a simple configurable
120 application uses. Let's look at how this would work for a simple configurable
108 subclass::
121 subclass::
109
122
110 # Sample configurable:
123 # Sample configurable:
111 from IPython.config.configurable import Configurable
124 from IPython.config.configurable import Configurable
112 from IPython.utils.traitlets import Int, Float, Unicode, Bool
125 from IPython.utils.traitlets import Int, Float, Unicode, Bool
113
126
114 class MyClass(Configurable):
127 class MyClass(Configurable):
115 name = Unicode(u'defaultname', config=True)
128 name = Unicode(u'defaultname', config=True)
116 ranking = Int(0, config=True)
129 ranking = Int(0, config=True)
117 value = Float(99.0)
130 value = Float(99.0)
118 # The rest of the class implementation would go here..
131 # The rest of the class implementation would go here..
119
132
120 In this example, we see that :class:`MyClass` has three attributes, two
133 In this example, we see that :class:`MyClass` has three attributes, two
121 of whom (``name``, ``ranking``) can be configured. All of the attributes
134 of (``name``, ``ranking``) can be configured. All of the attributes
122 are given types and default values. If a :class:`MyClass` is instantiated,
135 are given types and default values. If a :class:`MyClass` is instantiated,
123 but not configured, these default values will be used. But let's see how
136 but not configured, these default values will be used. But let's see how
124 to configure this class in a configuration file::
137 to configure this class in a configuration file::
125
138
126 # Sample config file
139 # Sample config file
127 c = get_config()
140 c = get_config()
128
141
129 c.MyClass.name = 'coolname'
142 c.MyClass.name = 'coolname'
130 c.MyClass.ranking = 10
143 c.MyClass.ranking = 10
131
144
132 After this configuration file is loaded, the values set in it will override
145 After this configuration file is loaded, the values set in it will override
133 the class defaults anytime a :class:`MyClass` is created. Furthermore,
146 the class defaults anytime a :class:`MyClass` is created. Furthermore,
134 these attributes will be type checked and validated anytime they are set.
147 these attributes will be type checked and validated anytime they are set.
135 This type checking is handled by the :mod:`IPython.utils.traitlets` module,
148 This type checking is handled by the :mod:`IPython.utils.traitlets` module,
136 which provides the :class:`Unicode`, :class:`Int` and :class:`Float` types.
149 which provides the :class:`Unicode`, :class:`Int` and :class:`Float` types.
137 In addition to these traitlets, the :mod:`IPython.utils.traitlets` provides
150 In addition to these traitlets, the :mod:`IPython.utils.traitlets` provides
138 traitlets for a number of other types.
151 traitlets for a number of other types.
139
152
140 .. note::
153 .. note::
141
154
142 Underneath the hood, the :class:`Configurable` base class is a subclass of
155 Underneath the hood, the :class:`Configurable` base class is a subclass of
143 :class:`IPython.utils.traitlets.HasTraits`. The
156 :class:`IPython.utils.traitlets.HasTraits`. The
144 :mod:`IPython.utils.traitlets` module is a lightweight version of
157 :mod:`IPython.utils.traitlets` module is a lightweight version of
145 :mod:`enthought.traits`. Our implementation is a pure Python subset
158 :mod:`enthought.traits`. Our implementation is a pure Python subset
146 (mostly API compatible) of :mod:`enthought.traits` that does not have any
159 (mostly API compatible) of :mod:`enthought.traits` that does not have any
147 of the automatic GUI generation capabilities. Our plan is to achieve 100%
160 of the automatic GUI generation capabilities. Our plan is to achieve 100%
148 API compatibility to enable the actual :mod:`enthought.traits` to
161 API compatibility to enable the actual :mod:`enthought.traits` to
149 eventually be used instead. Currently, we cannot use
162 eventually be used instead. Currently, we cannot use
150 :mod:`enthought.traits` as we are committed to the core of IPython being
163 :mod:`enthought.traits` as we are committed to the core of IPython being
151 pure Python.
164 pure Python.
152
165
153 It should be very clear at this point what the naming convention is for
166 It should be very clear at this point what the naming convention is for
154 configuration attributes::
167 configuration attributes::
155
168
156 c.ClassName.attribute_name = attribute_value
169 c.ClassName.attribute_name = attribute_value
157
170
158 Here, ``ClassName`` is the name of the class whose configuration attribute you
171 Here, ``ClassName`` is the name of the class whose configuration attribute you
159 want to set, ``attribute_name`` is the name of the attribute you want to set
172 want to set, ``attribute_name`` is the name of the attribute you want to set
160 and ``attribute_value`` the the value you want it to have. The ``ClassName``
173 and ``attribute_value`` the the value you want it to have. The ``ClassName``
161 attribute of ``c`` is not the actual class, but instead is another
174 attribute of ``c`` is not the actual class, but instead is another
162 :class:`~IPython.config.loader.Config` instance.
175 :class:`~IPython.config.loader.Config` instance.
163
176
164 .. note::
177 .. note::
165
178
166 The careful reader may wonder how the ``ClassName`` (``MyClass`` in
179 The careful reader may wonder how the ``ClassName`` (``MyClass`` in
167 the above example) attribute of the configuration object ``c`` gets
180 the above example) attribute of the configuration object ``c`` gets
168 created. These attributes are created on the fly by the
181 created. These attributes are created on the fly by the
169 :class:`~IPython.config.loader.Config` instance, using a simple naming
182 :class:`~IPython.config.loader.Config` instance, using a simple naming
170 convention. Any attribute of a :class:`~IPython.config.loader.Config`
183 convention. Any attribute of a :class:`~IPython.config.loader.Config`
171 instance whose name begins with an uppercase character is assumed to be a
184 instance whose name begins with an uppercase character is assumed to be a
172 sub-configuration and a new empty :class:`~IPython.config.loader.Config`
185 sub-configuration and a new empty :class:`~IPython.config.loader.Config`
173 instance is dynamically created for that attribute. This allows deeply
186 instance is dynamically created for that attribute. This allows deeply
174 hierarchical information created easily (``c.Foo.Bar.value``) on the fly.
187 hierarchical information created easily (``c.Foo.Bar.value``) on the fly.
175
188
189 JSON configuration Files
190 ~~~~~~~~~~~~~~~~~~~~~~~~
191
192 A JSON configuration file is simply a file that contain a
193 :class:`~IPython.config.loader.Config` dictionary serialized to JSON.
194 A JSON configuration file has the same base name as a Python configuration file,
195 just with a .json extension.
196
197 Configuration described in previous section could be written as follow in a
198 JSON configuration file:
199
200 .. sourcecode:: json
201
202 {
203 "version": "1.0",
204 "MyClass": {
205 "name": "coolname",
206 "ranking": 10
207 }
208 }
209
210 JSON configuration files can be more easily generated or processed by programs
211 or other languages.
212
213
176 Configuration files inheritance
214 Configuration files inheritance
177 ===============================
215 ===============================
178
216
217 .. note::
218
219 This section only apply to Python configuration files.
220
179 Let's say you want to have different configuration files for various purposes.
221 Let's say you want to have different configuration files for various purposes.
180 Our configuration system makes it easy for one configuration file to inherit
222 Our configuration system makes it easy for one configuration file to inherit
181 the information in another configuration file. The :func:`load_subconfig`
223 the information in another configuration file. The :func:`load_subconfig`
182 command can be used in a configuration file for this purpose. Here is a simple
224 command can be used in a configuration file for this purpose. Here is a simple
183 example that loads all of the values from the file :file:`base_config.py`::
225 example that loads all of the values from the file :file:`base_config.py`::
184
226
185 # base_config.py
227 # base_config.py
186 c = get_config()
228 c = get_config()
187 c.MyClass.name = 'coolname'
229 c.MyClass.name = 'coolname'
188 c.MyClass.ranking = 100
230 c.MyClass.ranking = 100
189
231
190 into the configuration file :file:`main_config.py`::
232 into the configuration file :file:`main_config.py`::
191
233
192 # main_config.py
234 # main_config.py
193 c = get_config()
235 c = get_config()
194
236
195 # Load everything from base_config.py
237 # Load everything from base_config.py
196 load_subconfig('base_config.py')
238 load_subconfig('base_config.py')
197
239
198 # Now override one of the values
240 # Now override one of the values
199 c.MyClass.name = 'bettername'
241 c.MyClass.name = 'bettername'
200
242
201 In a situation like this the :func:`load_subconfig` makes sure that the
243 In a situation like this the :func:`load_subconfig` makes sure that the
202 search path for sub-configuration files is inherited from that of the parent.
244 search path for sub-configuration files is inherited from that of the parent.
203 Thus, you can typically put the two in the same directory and everything will
245 Thus, you can typically put the two in the same directory and everything will
204 just work.
246 just work.
205
247
206 You can also load configuration files by profile, for instance:
248 You can also load configuration files by profile, for instance:
207
249
208 .. sourcecode:: python
250 .. sourcecode:: python
209
251
210 load_subconfig('ipython_config.py', profile='default')
252 load_subconfig('ipython_config.py', profile='default')
211
253
212 to inherit your default configuration as a starting point.
254 to inherit your default configuration as a starting point.
213
255
214
256
215 Class based configuration inheritance
257 Class based configuration inheritance
216 =====================================
258 =====================================
217
259
218 There is another aspect of configuration where inheritance comes into play.
260 There is another aspect of configuration where inheritance comes into play.
219 Sometimes, your classes will have an inheritance hierarchy that you want
261 Sometimes, your classes will have an inheritance hierarchy that you want
220 to be reflected in the configuration system. Here is a simple example::
262 to be reflected in the configuration system. Here is a simple example::
221
263
222 from IPython.config.configurable import Configurable
264 from IPython.config.configurable import Configurable
223 from IPython.utils.traitlets import Int, Float, Unicode, Bool
265 from IPython.utils.traitlets import Int, Float, Unicode, Bool
224
266
225 class Foo(Configurable):
267 class Foo(Configurable):
226 name = Unicode(u'fooname', config=True)
268 name = Unicode(u'fooname', config=True)
227 value = Float(100.0, config=True)
269 value = Float(100.0, config=True)
228
270
229 class Bar(Foo):
271 class Bar(Foo):
230 name = Unicode(u'barname', config=True)
272 name = Unicode(u'barname', config=True)
231 othervalue = Int(0, config=True)
273 othervalue = Int(0, config=True)
232
274
233 Now, we can create a configuration file to configure instances of :class:`Foo`
275 Now, we can create a configuration file to configure instances of :class:`Foo`
234 and :class:`Bar`::
276 and :class:`Bar`::
235
277
236 # config file
278 # config file
237 c = get_config()
279 c = get_config()
238
280
239 c.Foo.name = u'bestname'
281 c.Foo.name = u'bestname'
240 c.Bar.othervalue = 10
282 c.Bar.othervalue = 10
241
283
242 This class hierarchy and configuration file accomplishes the following:
284 This class hierarchy and configuration file accomplishes the following:
243
285
244 * The default value for :attr:`Foo.name` and :attr:`Bar.name` will be
286 * The default value for :attr:`Foo.name` and :attr:`Bar.name` will be
245 'bestname'. Because :class:`Bar` is a :class:`Foo` subclass it also
287 'bestname'. Because :class:`Bar` is a :class:`Foo` subclass it also
246 picks up the configuration information for :class:`Foo`.
288 picks up the configuration information for :class:`Foo`.
247 * The default value for :attr:`Foo.value` and :attr:`Bar.value` will be
289 * The default value for :attr:`Foo.value` and :attr:`Bar.value` will be
248 ``100.0``, which is the value specified as the class default.
290 ``100.0``, which is the value specified as the class default.
249 * The default value for :attr:`Bar.othervalue` will be 10 as set in the
291 * The default value for :attr:`Bar.othervalue` will be 10 as set in the
250 configuration file. Because :class:`Foo` is the parent of :class:`Bar`
292 configuration file. Because :class:`Foo` is the parent of :class:`Bar`
251 it doesn't know anything about the :attr:`othervalue` attribute.
293 it doesn't know anything about the :attr:`othervalue` attribute.
252
294
253
295
254 .. _ipython_dir:
296 .. _ipython_dir:
255
297
256 Configuration file location
298 Configuration file location
257 ===========================
299 ===========================
258
300
259 So where should you put your configuration files? IPython uses "profiles" for
301 So where should you put your configuration files? IPython uses "profiles" for
260 configuration, and by default, all profiles will be stored in the so called
302 configuration, and by default, all profiles will be stored in the so called
261 "IPython directory". The location of this directory is determined by the
303 "IPython directory". The location of this directory is determined by the
262 following algorithm:
304 following algorithm:
263
305
264 * If the ``ipython-dir`` command line flag is given, its value is used.
306 * If the ``ipython-dir`` command line flag is given, its value is used.
265
307
266 * If not, the value returned by :func:`IPython.utils.path.get_ipython_dir`
308 * If not, the value returned by :func:`IPython.utils.path.get_ipython_dir`
267 is used. This function will first look at the :envvar:`IPYTHONDIR`
309 is used. This function will first look at the :envvar:`IPYTHONDIR`
268 environment variable and then default to :file:`~/.ipython`.
310 environment variable and then default to :file:`~/.ipython`.
269 Historical support for the :envvar:`IPYTHON_DIR` environment variable will
311 Historical support for the :envvar:`IPYTHON_DIR` environment variable will
270 be removed in a future release.
312 be removed in a future release.
271
313
272 For most users, the configuration directory will be :file:`~/.ipython`.
314 For most users, the configuration directory will be :file:`~/.ipython`.
273
315
274 Previous versions of IPython on Linux would use the XDG config directory,
316 Previous versions of IPython on Linux would use the XDG config directory,
275 creating :file:`~/.config/ipython` by default. We have decided to go
317 creating :file:`~/.config/ipython` by default. We have decided to go
276 back to :file:`~/.ipython` for consistency among systems. IPython will
318 back to :file:`~/.ipython` for consistency among systems. IPython will
277 issue a warning if it finds the XDG location, and will move it to the new
319 issue a warning if it finds the XDG location, and will move it to the new
278 location if there isn't already a directory there.
320 location if there isn't already a directory there.
279
321
280 Once the location of the IPython directory has been determined, you need to know
322 Once the location of the IPython directory has been determined, you need to know
281 which profile you are using. For users with a single configuration, this will
323 which profile you are using. For users with a single configuration, this will
282 simply be 'default', and will be located in
324 simply be 'default', and will be located in
283 :file:`<IPYTHONDIR>/profile_default`.
325 :file:`<IPYTHONDIR>/profile_default`.
284
326
285 The next thing you need to know is what to call your configuration file. The
327 The next thing you need to know is what to call your configuration file. The
286 basic idea is that each application has its own default configuration filename.
328 basic idea is that each application has its own default configuration filename.
287 The default named used by the :command:`ipython` command line program is
329 The default named used by the :command:`ipython` command line program is
288 :file:`ipython_config.py`, and *all* IPython applications will use this file.
330 :file:`ipython_config.py`, and *all* IPython applications will use this file.
289 Other applications, such as the parallel :command:`ipcluster` scripts or the
331 Other applications, such as the parallel :command:`ipcluster` scripts or the
290 QtConsole will load their own config files *after* :file:`ipython_config.py`. To
332 QtConsole will load their own config files *after* :file:`ipython_config.py`. To
291 load a particular configuration file instead of the default, the name can be
333 load a particular configuration file instead of the default, the name can be
292 overridden by the ``config_file`` command line flag.
334 overridden by the ``config_file`` command line flag.
293
335
294 To generate the default configuration files, do::
336 To generate the default configuration files, do::
295
337
296 $ ipython profile create
338 $ ipython profile create
297
339
298 and you will have a default :file:`ipython_config.py` in your IPython directory
340 and you will have a default :file:`ipython_config.py` in your IPython directory
299 under :file:`profile_default`. If you want the default config files for the
341 under :file:`profile_default`. If you want the default config files for the
300 :mod:`IPython.parallel` applications, add ``--parallel`` to the end of the
342 :mod:`IPython.parallel` applications, add ``--parallel`` to the end of the
301 command-line args.
343 command-line args.
302
344
303
345
304 Locating these files
346 Locating these files
305 --------------------
347 --------------------
306
348
307 From the command-line, you can quickly locate the IPYTHONDIR or a specific
349 From the command-line, you can quickly locate the IPYTHONDIR or a specific
308 profile with:
350 profile with:
309
351
310 .. sourcecode:: bash
352 .. sourcecode:: bash
311
353
312 $ ipython locate
354 $ ipython locate
313 /home/you/.ipython
355 /home/you/.ipython
314
356
315 $ ipython locate profile foo
357 $ ipython locate profile foo
316 /home/you/.ipython/profile_foo
358 /home/you/.ipython/profile_foo
317
359
318 These map to the utility functions: :func:`IPython.utils.path.get_ipython_dir`
360 These map to the utility functions: :func:`IPython.utils.path.get_ipython_dir`
319 and :func:`IPython.utils.path.locate_profile` respectively.
361 and :func:`IPython.utils.path.locate_profile` respectively.
320
362
321
363
322 .. _profiles_dev:
364 .. _profiles_dev:
323
365
324 Profiles
366 Profiles
325 ========
367 ========
326
368
327 A profile is a directory containing configuration and runtime files, such as
369 A profile is a directory containing configuration and runtime files, such as
328 logs, connection info for the parallel apps, and your IPython command history.
370 logs, connection info for the parallel apps, and your IPython command history.
329
371
330 The idea is that users often want to maintain a set of configuration files for
372 The idea is that users often want to maintain a set of configuration files for
331 different purposes: one for doing numerical computing with NumPy and SciPy and
373 different purposes: one for doing numerical computing with NumPy and SciPy and
332 another for doing symbolic computing with SymPy. Profiles make it easy to keep a
374 another for doing symbolic computing with SymPy. Profiles make it easy to keep a
333 separate configuration files, logs, and histories for each of these purposes.
375 separate configuration files, logs, and histories for each of these purposes.
334
376
335 Let's start by showing how a profile is used:
377 Let's start by showing how a profile is used:
336
378
337 .. code-block:: bash
379 .. code-block:: bash
338
380
339 $ ipython --profile=sympy
381 $ ipython --profile=sympy
340
382
341 This tells the :command:`ipython` command line program to get its configuration
383 This tells the :command:`ipython` command line program to get its configuration
342 from the "sympy" profile. The file names for various profiles do not change. The
384 from the "sympy" profile. The file names for various profiles do not change. The
343 only difference is that profiles are named in a special way. In the case above,
385 only difference is that profiles are named in a special way. In the case above,
344 the "sympy" profile means looking for :file:`ipython_config.py` in :file:`<IPYTHONDIR>/profile_sympy`.
386 the "sympy" profile means looking for :file:`ipython_config.py` in :file:`<IPYTHONDIR>/profile_sympy`.
345
387
346 The general pattern is this: simply create a new profile with:
388 The general pattern is this: simply create a new profile with:
347
389
348 .. code-block:: bash
390 .. code-block:: bash
349
391
350 $ ipython profile create <name>
392 $ ipython profile create <name>
351
393
352 which adds a directory called ``profile_<name>`` to your IPython directory. Then
394 which adds a directory called ``profile_<name>`` to your IPython directory. Then
353 you can load this profile by adding ``--profile=<name>`` to your command line
395 you can load this profile by adding ``--profile=<name>`` to your command line
354 options. Profiles are supported by all IPython applications.
396 options. Profiles are supported by all IPython applications.
355
397
356 IPython ships with some sample profiles in :file:`IPython/config/profile`. If
398 IPython ships with some sample profiles in :file:`IPython/config/profile`. If
357 you create profiles with the name of one of our shipped profiles, these config
399 you create profiles with the name of one of our shipped profiles, these config
358 files will be copied over instead of starting with the automatically generated
400 files will be copied over instead of starting with the automatically generated
359 config files.
401 config files.
360
402
361 Security Files
403 Security Files
362 --------------
404 --------------
363
405
364 If you are using the notebook, qtconsole, or parallel code, IPython stores
406 If you are using the notebook, qtconsole, or parallel code, IPython stores
365 connection information in small JSON files in the active profile's security
407 connection information in small JSON files in the active profile's security
366 directory. This directory is made private, so only you can see the files inside. If
408 directory. This directory is made private, so only you can see the files inside. If
367 you need to move connection files around to other computers, this is where they will
409 you need to move connection files around to other computers, this is where they will
368 be. If you want your code to be able to open security files by name, we have a
410 be. If you want your code to be able to open security files by name, we have a
369 convenience function :func:`IPython.utils.path.get_security_file`, which will return
411 convenience function :func:`IPython.utils.path.get_security_file`, which will return
370 the absolute path to a security file from its filename and [optionally] profile
412 the absolute path to a security file from its filename and [optionally] profile
371 name.
413 name.
372
414
373 .. _startup_files:
415 .. _startup_files:
374
416
375 Startup Files
417 Startup Files
376 -------------
418 -------------
377
419
378 If you want some code to be run at the beginning of every IPython session with
420 If you want some code to be run at the beginning of every IPython session with
379 a particular profile, the easiest way is to add Python (``.py``) or
421 a particular profile, the easiest way is to add Python (``.py``) or
380 IPython (``.ipy``) scripts to your :file:`<profile>/startup` directory. Files
422 IPython (``.ipy``) scripts to your :file:`<profile>/startup` directory. Files
381 in this directory will always be executed as soon as the IPython shell is
423 in this directory will always be executed as soon as the IPython shell is
382 constructed, and before any other code or scripts you have specified. If you
424 constructed, and before any other code or scripts you have specified. If you
383 have multiple files in the startup directory, they will be run in
425 have multiple files in the startup directory, they will be run in
384 lexicographical order, so you can control the ordering by adding a '00-'
426 lexicographical order, so you can control the ordering by adding a '00-'
385 prefix.
427 prefix.
386
428
387
429
388 .. _commandline:
430 .. _commandline:
389
431
390 Command-line arguments
432 Command-line arguments
391 ======================
433 ======================
392
434
393 IPython exposes *all* configurable options on the command-line. The command-line
435 IPython exposes *all* configurable options on the command-line. The command-line
394 arguments are generated from the Configurable traits of the classes associated
436 arguments are generated from the Configurable traits of the classes associated
395 with a given Application. Configuring IPython from the command-line may look
437 with a given Application. Configuring IPython from the command-line may look
396 very similar to an IPython config file
438 very similar to an IPython config file
397
439
398 IPython applications use a parser called
440 IPython applications use a parser called
399 :class:`~IPython.config.loader.KeyValueLoader` to load values into a Config
441 :class:`~IPython.config.loader.KeyValueLoader` to load values into a Config
400 object. Values are assigned in much the same way as in a config file:
442 object. Values are assigned in much the same way as in a config file:
401
443
402 .. code-block:: bash
444 .. code-block:: bash
403
445
404 $ ipython --InteractiveShell.use_readline=False --BaseIPythonApplication.profile='myprofile'
446 $ ipython --InteractiveShell.use_readline=False --BaseIPythonApplication.profile='myprofile'
405
447
406 Is the same as adding:
448 Is the same as adding:
407
449
408 .. sourcecode:: python
450 .. sourcecode:: python
409
451
410 c.InteractiveShell.use_readline=False
452 c.InteractiveShell.use_readline=False
411 c.BaseIPythonApplication.profile='myprofile'
453 c.BaseIPythonApplication.profile='myprofile'
412
454
413 to your config file. Key/Value arguments *always* take a value, separated by '='
455 to your config file. Key/Value arguments *always* take a value, separated by '='
414 and no spaces.
456 and no spaces.
415
457
416 Common Arguments
458 Common Arguments
417 ----------------
459 ----------------
418
460
419 Since the strictness and verbosity of the KVLoader above are not ideal for everyday
461 Since the strictness and verbosity of the KVLoader above are not ideal for everyday
420 use, common arguments can be specified as flags_ or aliases_.
462 use, common arguments can be specified as flags_ or aliases_.
421
463
422 Flags and Aliases are handled by :mod:`argparse` instead, allowing for more flexible
464 Flags and Aliases are handled by :mod:`argparse` instead, allowing for more flexible
423 parsing. In general, flags and aliases are prefixed by ``--``, except for those
465 parsing. In general, flags and aliases are prefixed by ``--``, except for those
424 that are single characters, in which case they can be specified with a single ``-``, e.g.:
466 that are single characters, in which case they can be specified with a single ``-``, e.g.:
425
467
426 .. code-block:: bash
468 .. code-block:: bash
427
469
428 $ ipython -i -c "import numpy; x=numpy.linspace(0,1)" --profile testing --colors=lightbg
470 $ ipython -i -c "import numpy; x=numpy.linspace(0,1)" --profile testing --colors=lightbg
429
471
430 Aliases
472 Aliases
431 *******
473 *******
432
474
433 For convenience, applications have a mapping of commonly used traits, so you don't have
475 For convenience, applications have a mapping of commonly used traits, so you don't have
434 to specify the whole class name:
476 to specify the whole class name:
435
477
436 .. code-block:: bash
478 .. code-block:: bash
437
479
438 $ ipython --profile myprofile
480 $ ipython --profile myprofile
439 # and
481 # and
440 $ ipython --profile='myprofile'
482 $ ipython --profile='myprofile'
441 # are equivalent to
483 # are equivalent to
442 $ ipython --BaseIPythonApplication.profile='myprofile'
484 $ ipython --BaseIPythonApplication.profile='myprofile'
443
485
444 Flags
486 Flags
445 *****
487 *****
446
488
447 Applications can also be passed **flags**. Flags are options that take no
489 Applications can also be passed **flags**. Flags are options that take no
448 arguments. They are simply wrappers for
490 arguments. They are simply wrappers for
449 setting one or more configurables with predefined values, often True/False.
491 setting one or more configurables with predefined values, often True/False.
450
492
451 For instance:
493 For instance:
452
494
453 .. code-block:: bash
495 .. code-block:: bash
454
496
455 $ ipcontroller --debug
497 $ ipcontroller --debug
456 # is equivalent to
498 # is equivalent to
457 $ ipcontroller --Application.log_level=DEBUG
499 $ ipcontroller --Application.log_level=DEBUG
458 # and
500 # and
459 $ ipython --matploitlib
501 $ ipython --matploitlib
460 # is equivalent to
502 # is equivalent to
461 $ ipython --matplotlib auto
503 $ ipython --matplotlib auto
462 # or
504 # or
463 $ ipython --no-banner
505 $ ipython --no-banner
464 # is equivalent to
506 # is equivalent to
465 $ ipython --TerminalIPythonApp.display_banner=False
507 $ ipython --TerminalIPythonApp.display_banner=False
466
508
467 Subcommands
509 Subcommands
468 -----------
510 -----------
469
511
470
512
471 Some IPython applications have **subcommands**. Subcommands are modeled after
513 Some IPython applications have **subcommands**. Subcommands are modeled after
472 :command:`git`, and are called with the form :command:`command subcommand
514 :command:`git`, and are called with the form :command:`command subcommand
473 [...args]`. Currently, the QtConsole is a subcommand of terminal IPython:
515 [...args]`. Currently, the QtConsole is a subcommand of terminal IPython:
474
516
475 .. code-block:: bash
517 .. code-block:: bash
476
518
477 $ ipython qtconsole --profile myprofile
519 $ ipython qtconsole --profile myprofile
478
520
479 and :command:`ipcluster` is simply a wrapper for its various subcommands (start,
521 and :command:`ipcluster` is simply a wrapper for its various subcommands (start,
480 stop, engines).
522 stop, engines).
481
523
482 .. code-block:: bash
524 .. code-block:: bash
483
525
484 $ ipcluster start --profile=myprofile -n 4
526 $ ipcluster start --profile=myprofile -n 4
485
527
486
528
487 To see a list of the available aliases, flags, and subcommands for an IPython application, simply pass ``-h`` or ``--help``. And to see the full list of configurable options (*very* long), pass ``--help-all``.
529 To see a list of the available aliases, flags, and subcommands for an IPython application, simply pass ``-h`` or ``--help``. And to see the full list of configurable options (*very* long), pass ``--help-all``.
488
530
489
531
490 Design requirements
532 Design requirements
491 ===================
533 ===================
492
534
493 Here are the main requirements we wanted our configuration system to have:
535 Here are the main requirements we wanted our configuration system to have:
494
536
495 * Support for hierarchical configuration information.
537 * Support for hierarchical configuration information.
496
538
497 * Full integration with command line option parsers. Often, you want to read
539 * Full integration with command line option parsers. Often, you want to read
498 a configuration file, but then override some of the values with command line
540 a configuration file, but then override some of the values with command line
499 options. Our configuration system automates this process and allows each
541 options. Our configuration system automates this process and allows each
500 command line option to be linked to a particular attribute in the
542 command line option to be linked to a particular attribute in the
501 configuration hierarchy that it will override.
543 configuration hierarchy that it will override.
502
544
503 * Configuration files that are themselves valid Python code. This accomplishes
545 * Configuration files that are themselves valid Python code. This accomplishes
504 many things. First, it becomes possible to put logic in your configuration
546 many things. First, it becomes possible to put logic in your configuration
505 files that sets attributes based on your operating system, network setup,
547 files that sets attributes based on your operating system, network setup,
506 Python version, etc. Second, Python has a super simple syntax for accessing
548 Python version, etc. Second, Python has a super simple syntax for accessing
507 hierarchical data structures, namely regular attribute access
549 hierarchical data structures, namely regular attribute access
508 (``Foo.Bar.Bam.name``). Third, using Python makes it easy for users to
550 (``Foo.Bar.Bam.name``). Third, using Python makes it easy for users to
509 import configuration attributes from one configuration file to another.
551 import configuration attributes from one configuration file to another.
510 Fourth, even though Python is dynamically typed, it does have types that can
552 Fourth, even though Python is dynamically typed, it does have types that can
511 be checked at runtime. Thus, a ``1`` in a config file is the integer '1',
553 be checked at runtime. Thus, a ``1`` in a config file is the integer '1',
512 while a ``'1'`` is a string.
554 while a ``'1'`` is a string.
513
555
514 * A fully automated method for getting the configuration information to the
556 * A fully automated method for getting the configuration information to the
515 classes that need it at runtime. Writing code that walks a configuration
557 classes that need it at runtime. Writing code that walks a configuration
516 hierarchy to extract a particular attribute is painful. When you have
558 hierarchy to extract a particular attribute is painful. When you have
517 complex configuration information with hundreds of attributes, this makes
559 complex configuration information with hundreds of attributes, this makes
518 you want to cry.
560 you want to cry.
519
561
520 * Type checking and validation that doesn't require the entire configuration
562 * Type checking and validation that doesn't require the entire configuration
521 hierarchy to be specified statically before runtime. Python is a very
563 hierarchy to be specified statically before runtime. Python is a very
522 dynamic language and you don't always know everything that needs to be
564 dynamic language and you don't always know everything that needs to be
523 configured when a program starts.
565 configured when a program starts.
524
566
General Comments 0
You need to be logged in to leave comments. Login now