##// 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.
@@ -31,7 +31,7 b' 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 (
@@ -492,34 +492,52 b' class Application(SingletonConfigurable):'
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]
@@ -28,9 +28,10 b' 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
@@ -303,9 +304,17 b' class ConfigLoader(object):'
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
@@ -315,6 +324,11 b' class ConfigLoader(object):'
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()
@@ -336,17 +350,8 b' class FileConfigLoader(ConfigLoader):'
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
@@ -357,11 +362,53 b' class PyFileConfigLoader(FileConfigLoader):'
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."""
@@ -371,12 +418,8 b' class PyFileConfigLoader(FileConfigLoader):'
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."""
@@ -429,10 +472,6 b' class PyFileConfigLoader(FileConfigLoader):'
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.
@@ -497,7 +536,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
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
@@ -529,7 +568,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
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
@@ -606,7 +645,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
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:
@@ -633,7 +672,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
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
@@ -656,7 +695,7 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
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:]
@@ -772,7 +811,7 b' class KVArgParseConfigLoader(ArgParseConfigLoader):'
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
@@ -22,17 +22,21 b' Authors:'
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,
@@ -53,21 +57,77 b" 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):
@@ -121,10 +181,9 b' 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)
@@ -132,31 +191,27 b' class TestKeyValueCL(TestCase):'
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):
@@ -166,16 +221,14 b' class TestKeyValueCL(TestCase):'
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
@@ -183,18 +236,16 b' 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
@@ -33,7 +33,7 b' import sys'
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
@@ -364,7 +364,6 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
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
@@ -372,15 +371,14 b' def load_default_config(ipython_dir=None):'
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
@@ -15,10 +15,10 b' Each of these abstractions is represented by a Python class.'
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
@@ -85,12 +85,24 b' Now, we show what our configuration objects and files look like.'
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
@@ -99,10 +111,11 b' Here is an example of a super simple configuration file that does nothing::'
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::
@@ -118,7 +131,7 b' subclass::'
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::
@@ -173,9 +186,38 b' attribute of ``c`` is not the actual class, but instead is another'
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`
General Comments 0
You need to be logged in to leave comments. Login now