| 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 from collections import OrderedDict | 
|    9  |   10  | 
|   10  |   11  | 
|   11 class Item(tuple): |   12 class Item(tuple): | 
|   12     def __new__(cls, name, value, source): |   13     def __new__(cls, name, value, source): | 
|   13         result = super(Item, cls).__new__(cls, (name, value)) |   14         result = super(Item, cls).__new__(cls, (name, value)) | 
|   14         result.source = source |   15         result.source = source | 
|   15         return result |   16         return result | 
|   16  |   17  | 
|   17  |   18  | 
|   18 class DiffForUnknownOptionError(ConfigParser.Error): |   19 class DiffForUnknownOptionError(ConfigParser.Error): | 
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  150  |  151  | 
|  151     def option_source(self, section, option): |  152     def option_source(self, section, option): | 
|  152         option = self.optionxform(option) |  153         option = self.optionxform(option) | 
|  153         try: |  154         try: | 
|  154             return self._origin[(section, option)] |  155             return self._origin[(section, option)] | 
|  155         except KeyError: |  156         except KeyError: | 
|  156             if not self.has_section(section): |  157             if not self.has_section(section): | 
|  157                 raise ConfigParser.NoSectionError(section) |  158                 raise ConfigParser.NoSectionError(section) | 
|  158             raise ConfigParser.NoOptionError(option, section) |  159             raise ConfigParser.NoOptionError(option, section) | 
|  159  |  160  | 
 |  161     def as_json_object(self, section): | 
 |  162         r"""Parse a given section into a JSON object. | 
 |  163  | 
 |  164         Parse arbitrary key/value pairs from 'section' of the current | 
 |  165         configuration into a nested JSON object. | 
 |  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         * An option's key must end with '[]', to mark this option as an array | 
 |  172         * When an option is marked as an array, no other nested objects may | 
 |  173           follow | 
 |  174         * An array is expandable by the ConfigParser's '+=' token. | 
 |  175         * Values may be marked as special types by appending '\{code}': | 
 |  176           * \b - boolean | 
 |  177           * \i - integer | 
 |  178           * \f - float | 
 |  179  | 
 |  180         Example: | 
 |  181  | 
 |  182                                         { | 
 |  183                                           "good": false, | 
 |  184                                           "bar": { | 
 |  185                                             "baz": ["bar", "bazinga"] | 
 |  186         foo = foo                         }, | 
 |  187         bar.baz[] = bar                   "is": { | 
 |  188         baz.foo = a                         "integer": 1, | 
 |  189         baz.z[] = b                         "float": 1.4 | 
 |  190         bar.baz[] += bazinga    ==>       }, | 
 |  191         bad = true\b                      "baz": { | 
 |  192         good = f\b                          "foo": "a", | 
 |  193         is.integer = 1\i                    "z": ["b"] | 
 |  194         is.float = 1.4\f                  }, | 
 |  195                                           "bad": true | 
 |  196                                           "foo": "foo" | 
 |  197                                         } | 
 |  198         """ | 
 |  199         def parse_values(v): | 
 |  200             import distutils | 
 |  201             if isinstance(v, list): | 
 |  202                 return [parse_values(x) for x in v] | 
 |  203  | 
 |  204             mapping = { | 
 |  205                 '\\b': lambda x: bool(distutils.util.strtobool(x)), | 
 |  206                 '\\i': int, | 
 |  207                 '\\f': float, | 
 |  208             } | 
 |  209             if '\\' in v: | 
 |  210                 return mapping[v[-2:]](v[:-2]) | 
 |  211             return v | 
 |  212  | 
 |  213         def setdefault_recursive(target, arr): | 
 |  214             if len(arr) == 2: | 
 |  215                 target.setdefault(arr[0], parse_values(arr[1])) | 
 |  216             else: | 
 |  217                 current = target.setdefault(arr[0], OrderedDict()) | 
 |  218                 setdefault_recursive(current, arr[1:]) | 
 |  219  | 
 |  220         data = self.items(section) | 
 |  221         result = OrderedDict() | 
 |  222  | 
 |  223         for k, v in data: | 
 |  224             if k.endswith('[]'): | 
 |  225                 k = k[:-2] | 
 |  226                 v = v.split() | 
 |  227  | 
 |  228             setdefault_recursive(result, k.split('.') + [v]) | 
 |  229  | 
 |  230         return result | 
 |  231  | 
|  160     def readfp(self, fp, filename=None): |  232     def readfp(self, fp, filename=None): | 
|  161         raise NotImplementedError |  233         raise NotImplementedError | 
|  162  |  234  | 
|  163     def set(self, section, option, value=None): |  235     def set(self, section, option, value=None): | 
|  164         raise NotImplementedError |  236         raise NotImplementedError | 
|  165  |  237  | 
|  166     def add_section(self, section): |  238     def add_section(self, section): | 
|  167         raise NotImplementedError |  239         raise NotImplementedError | 
|  168  |  240  | 
|  169     def remove_option(self, section, option): |  241     def remove_option(self, section, option): | 
|  170         raise NotImplementedError |  242         raise NotImplementedError | 
|  171  |  243  | 
|  172     def remove_section(self, section): |  244     def remove_section(self, section): | 
|  173         raise NotImplementedError |  245         raise NotImplementedError | 
| OLD | NEW |