Left: | ||
Right: |
OLD | NEW |
---|---|
1 # This Source Code Form is subject to the terms of the Mozilla Public | 1 # This Source Code Form is subject to the terms of the Mozilla Public |
2 # License, v. 2.0. If a copy of the MPL was not distributed with this | 2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
4 | 4 |
5 import os | 5 import os |
6 import io | 6 import io |
7 import ConfigParser | 7 import ConfigParser |
8 from StringIO import StringIO | 8 from StringIO import StringIO |
9 | 9 |
10 | 10 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 is_addition = option.endswith('+') | 86 is_addition = option.endswith('+') |
87 is_diff = is_addition or option.endswith('-') | 87 is_diff = is_addition or option.endswith('-') |
88 | 88 |
89 if is_diff: | 89 if is_diff: |
90 option = option[:-1].rstrip() | 90 option = option[:-1].rstrip() |
91 try: | 91 try: |
92 orig_value = self.get(section, option) | 92 orig_value = self.get(section, option) |
93 except ConfigParser.NoOptionError: | 93 except ConfigParser.NoOptionError: |
94 raise DiffForUnknownOptionError(option, section) | 94 raise DiffForUnknownOptionError(option, section) |
95 | 95 |
96 orig_values = orig_value.split() | 96 orig_values = orig_value.splitlines() |
97 diff_values = value.split() | 97 diff_values = value.splitlines() |
98 | 98 |
99 if is_addition: | 99 if is_addition: |
100 new_values = orig_values + [v for v in diff_values if v not in o rig_values] | 100 new_values = orig_values + [v for v in diff_values if v not in o rig_values] |
101 else: | 101 else: |
102 new_values = [v for v in orig_values if v not in diff_values] | 102 new_values = [v for v in orig_values if v not in diff_values] |
103 | 103 |
104 value = ' '.join(new_values) | 104 value = '\n'.join(new_values) |
105 | 105 |
106 return is_diff, option, value | 106 return is_diff, option, value |
107 | 107 |
108 def _process_parsers(self, parsers): | 108 def _process_parsers(self, parsers): |
109 for parser, filename in parsers: | 109 for parser, filename in parsers: |
110 for section in parser.sections(): | 110 for section in parser.sections(): |
111 if not self.has_section(section): | 111 if not self.has_section(section): |
112 try: | 112 try: |
113 ConfigParser.SafeConfigParser.add_section(self, section) | 113 ConfigParser.SafeConfigParser.add_section(self, section) |
114 except ValueError: | 114 except ValueError: |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 | 150 |
151 def option_source(self, section, option): | 151 def option_source(self, section, option): |
152 option = self.optionxform(option) | 152 option = self.optionxform(option) |
153 try: | 153 try: |
154 return self._origin[(section, option)] | 154 return self._origin[(section, option)] |
155 except KeyError: | 155 except KeyError: |
156 if not self.has_section(section): | 156 if not self.has_section(section): |
157 raise ConfigParser.NoSectionError(section) | 157 raise ConfigParser.NoSectionError(section) |
158 raise ConfigParser.NoOptionError(option, section) | 158 raise ConfigParser.NoOptionError(option, section) |
159 | 159 |
160 def section_as_dict(self, section, additional={}): | |
161 """Parse a given section into a dictionary. | |
162 | |
163 Parse arbitrary key/value pairs from 'section' of the current | |
164 configuration into a dictionary and merge it with the optional | |
165 parameter `additional`. | |
166 | |
167 The following rules need to be considered: | |
168 | |
169 * An option's key may be declared as a series of nested dictionary keys, | |
170 seperated by '.'. | |
171 * Declaring an option's value in a new line (even if only one is given) | |
172 will define the option's value as an array. | |
173 * When an option's value is defined as an array, no other nested | |
174 objects may follow. | |
175 * An array is expandable by the ConfigParser's '+=' token (Note: A | |
176 previously declared string will be converted into an array). | |
177 * Values may be marked as `number` or `bool` by prefixing them | |
178 accordingly (this also applies to values in an array): | |
179 * bool:<value> | |
180 * number:<value> | |
181 | |
182 Example: | |
183 { | |
184 foo = foo "foo": "foo", | |
185 asd = "asd": ["asd"], | |
186 asd "bar": { | |
187 bar.baz = a "baz": ["a", "c", "d"] | |
188 baz.foo = a }, | |
189 baz.z = "baz": { | |
190 bar "foo": "a", | |
191 bool:true ===> "z": ["bar", true] | |
192 bar.baz += }, | |
193 c "bad": true, | |
194 d "good": false, | |
195 bad = bool:true "is": { | |
196 good = bool:false "integer": 1, | |
197 is.integer = number:1 "float": 1.4 | |
198 is.float = number:1.4 } | |
199 } | |
200 """ | |
201 def parse_values(v): | |
202 if isinstance(v, list): | |
203 return [parse_values(x) for x in v] | |
Sebastian Noack
2018/04/18 15:59:00
Checking for lists and recursively calling this fu
tlucas
2018/04/19 10:01:39
Done.
| |
204 | |
205 if v.startswith('number:'): | |
206 v = v.split(':', 1)[1] | |
207 try: | |
208 v = int(v) | |
Sebastian Noack
2018/04/18 15:58:59
Nit: I wouldn't reassign v, but just return the pa
tlucas
2018/04/19 10:01:39
Done.
| |
209 except ValueError: | |
210 v = float(v) | |
211 elif v == 'bool:true': | |
212 v = True | |
213 elif v == 'bool:false': | |
214 v = False | |
215 return v | |
216 | |
217 def setdefault_recursive(target, keys, value): | |
218 if len(keys) == 1: | |
219 target.setdefault(keys[0], parse_values(value)) | |
220 else: | |
221 current = target.setdefault(keys[0], {}) | |
222 setdefault_recursive(current, keys[1:], value) | |
223 | |
224 data = self.items(section) | |
225 result = {} | |
226 | |
227 for k, v in data: | |
228 if '\n' in v: | |
229 v = [x for x in v.splitlines() if x] | |
230 | |
231 setdefault_recursive(result, k.split('.'), v) | |
Sebastian Noack
2018/04/18 15:59:00
The recursion here is unnecessary:
parents = k.
tlucas
2018/04/19 10:01:39
Done.
| |
232 | |
233 result.update(additional) | |
Sebastian Noack
2018/04/18 15:58:59
Well, the point of passing the generated part of t
tlucas
2018/04/19 10:01:40
Done.
| |
234 | |
235 return result | |
236 | |
160 def readfp(self, fp, filename=None): | 237 def readfp(self, fp, filename=None): |
161 raise NotImplementedError | 238 raise NotImplementedError |
162 | 239 |
163 def set(self, section, option, value=None): | 240 def set(self, section, option, value=None): |
164 raise NotImplementedError | 241 raise NotImplementedError |
165 | 242 |
166 def add_section(self, section): | 243 def add_section(self, section): |
167 raise NotImplementedError | 244 raise NotImplementedError |
168 | 245 |
169 def remove_option(self, section, option): | 246 def remove_option(self, section, option): |
170 raise NotImplementedError | 247 raise NotImplementedError |
171 | 248 |
172 def remove_section(self, section): | 249 def remove_section(self, section): |
173 raise NotImplementedError | 250 raise NotImplementedError |
OLD | NEW |