Left: | ||
Right: |
LEFT | RIGHT |
---|---|
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 139 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={}): | 160 def serialize_section_if_present(self, section, base): |
Vasily Kuznetsov
2018/04/19 14:40:10
What this method does seems more like parsing than
Sebastian Noack
2018/04/19 15:02:59
In the end it gets serialized (as JSON). But you m
| |
161 """Parse a given section into a dictionary. | 161 """Serialize a given section as a dictionary into `base`. |
162 | 162 |
163 Parse arbitrary key/value pairs from 'section' of the current | 163 Parse arbitrary key/value pairs from 'section' of the current |
164 configuration into a dictionary and merge it with the optional | 164 configuration into a dictionary and deep merge it into `base`. |
165 parameter `additional`. | |
166 | 165 |
167 The following rules need to be considered: | 166 The following rules need to be considered: |
168 | 167 |
169 * An option's key may be declared as a series of nested dictionary keys, | 168 * An option's key may be declared as a series of nested dictionary keys, |
170 seperated by '.'. | 169 seperated by '.'. |
171 * Declaring an option's value in a new line (even if only one is given) | 170 * 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. | 171 will define the option's value as a list. |
173 * When an option's value is defined as an array, no other nested | 172 * When an option's value is defined as a list, no other nested |
174 objects may follow. | 173 objects may follow. |
175 * An array is expandable by the ConfigParser's '+=' token (Note: A | 174 * A list is expandable by the ConfigParser's '+=' token (Note: A |
176 previously declared string will be converted into an array). | 175 previously declared string will be converted into a list). |
177 * Values may be marked as `number` or `bool` by prefixing them | 176 * Values may be marked as `number` or `bool` by prefixing them |
178 accordingly (this also applies to values in an array): | 177 accordingly (this also applies to values in a list): |
179 * bool:<value> | 178 * bool:<value> |
180 * number:<value> | 179 * number:<value> |
181 | 180 |
182 Example: | 181 Example: |
183 { | 182 { |
184 foo = foo "foo": "foo", | 183 foo = foo "foo": "foo", |
185 asd = "asd": ["asd"], | 184 asd = "asd": ["asd"], |
186 asd "bar": { | 185 asd "bar": { |
187 bar.baz = a "baz": ["a", "c", "d"] | 186 bar.baz = a "baz": ["a", "c", "d"] |
188 baz.foo = a }, | 187 baz.foo = a }, |
189 baz.z = "baz": { | 188 baz.z = "baz": { |
190 bar "foo": "a", | 189 bar "foo": "a", |
191 bool:true ===> "z": ["bar", true] | 190 bool:true ===> "z": ["bar", true] |
192 bar.baz += }, | 191 bar.baz += }, |
193 c "bad": true, | 192 c "bad": true, |
194 d "good": false, | 193 d "good": false, |
195 bad = bool:true "is": { | 194 bad = bool:true "is": { |
196 good = bool:false "integer": 1, | 195 good = bool:false "integer": 1, |
197 is.integer = number:1 "float": 1.4 | 196 is.integer = number:1 "float": 1.4 |
198 is.float = number:1.4 } | 197 is.float = number:1.4 } |
199 } | 198 } |
200 """ | 199 """ |
201 def parse_values(v): | 200 def parse_value(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:'): | 201 if v.startswith('number:'): |
206 v = v.split(':', 1)[1] | 202 v = v.split(':', 1)[1] |
207 try: | 203 try: |
208 v = int(v) | 204 return 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: | 205 except ValueError: |
210 v = float(v) | 206 return float(v) |
211 elif v == 'bool:true': | 207 if v == 'bool:true': |
212 v = True | 208 return True |
213 elif v == 'bool:false': | 209 if v == 'bool:false': |
214 v = False | 210 return False |
215 return v | 211 return v |
216 | 212 |
217 def setdefault_recursive(target, keys, value): | 213 if self.has_section(section): |
218 if len(keys) == 1: | 214 for k, v in self.items(section): |
219 target.setdefault(keys[0], parse_values(value)) | 215 parents = k.split('.') |
220 else: | 216 tail = parents.pop() |
221 current = target.setdefault(keys[0], {}) | 217 current = base |
222 setdefault_recursive(current, keys[1:], value) | 218 for name in parents: |
223 | 219 current = base.setdefault(name, {}) |
224 data = self.items(section) | 220 |
225 result = {} | 221 if '\n' in v: |
226 | 222 current[tail] = [parse_value(x) for x in v.splitlines() if x ] |
227 for k, v in data: | 223 else: |
228 if '\n' in v: | 224 current[tail] = parse_value(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 | 225 |
237 def readfp(self, fp, filename=None): | 226 def readfp(self, fp, filename=None): |
238 raise NotImplementedError | 227 raise NotImplementedError |
239 | 228 |
240 def set(self, section, option, value=None): | 229 def set(self, section, option, value=None): |
241 raise NotImplementedError | 230 raise NotImplementedError |
242 | 231 |
243 def add_section(self, section): | 232 def add_section(self, section): |
244 raise NotImplementedError | 233 raise NotImplementedError |
245 | 234 |
246 def remove_option(self, section, option): | 235 def remove_option(self, section, option): |
247 raise NotImplementedError | 236 raise NotImplementedError |
248 | 237 |
249 def remove_section(self, section): | 238 def remove_section(self, section): |
250 raise NotImplementedError | 239 raise NotImplementedError |
LEFT | RIGHT |