Show More
@@ -6,6 +6,7 b'' | |||||
6 |
|
6 | |||
7 | from __future__ import print_function |
|
7 | from __future__ import print_function | |
8 |
|
8 | |||
|
9 | import json | |||
9 | import logging |
|
10 | import logging | |
10 | import os |
|
11 | import os | |
11 | import re |
|
12 | import re | |
@@ -535,8 +536,17 b' class Application(SingletonConfigurable):' | |||||
535 | def load_config_file(self, filename, path=None): |
|
536 | def load_config_file(self, filename, path=None): | |
536 | """Load config files by filename and path.""" |
|
537 | """Load config files by filename and path.""" | |
537 | filename, ext = os.path.splitext(filename) |
|
538 | filename, ext = os.path.splitext(filename) | |
|
539 | loaded = [] | |||
538 | for config in self._load_config_files(filename, path=path, log=self.log): |
|
540 | for config in self._load_config_files(filename, path=path, log=self.log): | |
|
541 | loaded.append(config) | |||
539 | self.update_config(config) |
|
542 | self.update_config(config) | |
|
543 | if len(loaded) > 1: | |||
|
544 | collisions = loaded[0].collisions(loaded[1]) | |||
|
545 | if collisions: | |||
|
546 | self.log.warn("Collisions detected in {0}.py and {0}.json config files." | |||
|
547 | " {0}.json has higher priority: {1}".format( | |||
|
548 | filename, json.dumps(collisions, indent=2), | |||
|
549 | )) | |||
540 |
|
550 | |||
541 |
|
551 | |||
542 | def generate_config_file(self): |
|
552 | def generate_config_file(self): |
@@ -193,7 +193,27 b' class Config(dict):' | |||||
193 | to_update[k] = copy.deepcopy(v) |
|
193 | to_update[k] = copy.deepcopy(v) | |
194 |
|
194 | |||
195 | self.update(to_update) |
|
195 | self.update(to_update) | |
196 |
|
196 | |||
|
197 | def collisions(self, other): | |||
|
198 | """Check for collisions between two config objects. | |||
|
199 | ||||
|
200 | Returns a dict of the form {"Class": {"trait": "collision message"}}`, | |||
|
201 | indicating which values have been ignored. | |||
|
202 | ||||
|
203 | An empty dict indicates no collisions. | |||
|
204 | """ | |||
|
205 | collisions = {} | |||
|
206 | for section in self: | |||
|
207 | if section not in other: | |||
|
208 | continue | |||
|
209 | mine = self[section] | |||
|
210 | theirs = other[section] | |||
|
211 | for key in mine: | |||
|
212 | if key in theirs and mine[key] != theirs[key]: | |||
|
213 | collisions.setdefault(section, {}) | |||
|
214 | collisions[section][key] = "%r ignored, using %r" % (mine[key], theirs[key]) | |||
|
215 | return collisions | |||
|
216 | ||||
197 | def __contains__(self, key): |
|
217 | def __contains__(self, key): | |
198 | # allow nested contains of the form `"Section.key" in config` |
|
218 | # allow nested contains of the form `"Section.key" in config` | |
199 | if '.' in key: |
|
219 | if '.' in key: | |
@@ -565,7 +585,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):' | |||||
565 |
|
585 | |||
566 |
|
586 | |||
567 | def _decode_argv(self, argv, enc=None): |
|
587 | def _decode_argv(self, argv, enc=None): | |
568 | """decode argv if bytes, using stin.encoding, falling back on default enc""" |
|
588 | """decode argv if bytes, using stdin.encoding, falling back on default enc""" | |
569 | uargv = [] |
|
589 | uargv = [] | |
570 | if enc is None: |
|
590 | if enc is None: | |
571 | enc = DEFAULT_ENCODING |
|
591 | enc = DEFAULT_ENCODING |
@@ -1,28 +1,12 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """Tests for IPython.config.loader""" | |
3 | Tests for IPython.config.loader |
|
|||
4 |
|
||||
5 | Authors: |
|
|||
6 |
|
||||
7 | * Brian Granger |
|
|||
8 | * Fernando Perez (design help) |
|
|||
9 | """ |
|
|||
10 |
|
3 | |||
11 | #----------------------------------------------------------------------------- |
|
4 | # Copyright (c) IPython Development Team. | |
12 | # Copyright (C) 2008 The IPython Development Team |
|
5 | # Distributed under the terms of the Modified BSD License. | |
13 | # |
|
|||
14 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
15 | # the file COPYING, distributed as part of this software. |
|
|||
16 | #----------------------------------------------------------------------------- |
|
|||
17 |
|
||||
18 | #----------------------------------------------------------------------------- |
|
|||
19 | # Imports |
|
|||
20 | #----------------------------------------------------------------------------- |
|
|||
21 |
|
6 | |||
22 | import os |
|
7 | import os | |
23 | import pickle |
|
8 | import pickle | |
24 | import sys |
|
9 | import sys | |
25 | import json |
|
|||
26 |
|
10 | |||
27 | from tempfile import mkstemp |
|
11 | from tempfile import mkstemp | |
28 | from unittest import TestCase |
|
12 | from unittest import TestCase | |
@@ -43,10 +27,6 b' from IPython.config.loader import (' | |||||
43 | ConfigError, |
|
27 | ConfigError, | |
44 | ) |
|
28 | ) | |
45 |
|
29 | |||
46 | #----------------------------------------------------------------------------- |
|
|||
47 | # Actual tests |
|
|||
48 | #----------------------------------------------------------------------------- |
|
|||
49 |
|
||||
50 |
|
30 | |||
51 | pyfile = """ |
|
31 | pyfile = """ | |
52 | c = get_config() |
|
32 | c = get_config() | |
@@ -117,6 +97,34 b' class TestFileCL(TestCase):' | |||||
117 | cl = JSONFileConfigLoader(fname, log=log) |
|
97 | cl = JSONFileConfigLoader(fname, log=log) | |
118 | config = cl.load_config() |
|
98 | config = cl.load_config() | |
119 | self._check_conf(config) |
|
99 | self._check_conf(config) | |
|
100 | ||||
|
101 | def test_collision(self): | |||
|
102 | a = Config() | |||
|
103 | b = Config() | |||
|
104 | self.assertEqual(a.collisions(b), {}) | |||
|
105 | a.A.trait1 = 1 | |||
|
106 | b.A.trait2 = 2 | |||
|
107 | self.assertEqual(a.collisions(b), {}) | |||
|
108 | b.A.trait1 = 1 | |||
|
109 | self.assertEqual(a.collisions(b), {}) | |||
|
110 | b.A.trait1 = 0 | |||
|
111 | self.assertEqual(a.collisions(b), { | |||
|
112 | 'A': { | |||
|
113 | 'trait1': "1 ignored, using 0", | |||
|
114 | } | |||
|
115 | }) | |||
|
116 | self.assertEqual(b.collisions(a), { | |||
|
117 | 'A': { | |||
|
118 | 'trait1': "0 ignored, using 1", | |||
|
119 | } | |||
|
120 | }) | |||
|
121 | a.A.trait2 = 3 | |||
|
122 | self.assertEqual(b.collisions(a), { | |||
|
123 | 'A': { | |||
|
124 | 'trait1': "0 ignored, using 1", | |||
|
125 | 'trait2': "2 ignored, using 3", | |||
|
126 | } | |||
|
127 | }) | |||
120 |
|
128 | |||
121 | def test_v2raise(self): |
|
129 | def test_v2raise(self): | |
122 | fd, fname = mkstemp('.json') |
|
130 | fd, fname = mkstemp('.json') |
General Comments 0
You need to be logged in to leave comments.
Login now