Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 # coding: utf-8 | 1 # coding: utf-8 |
2 | 2 |
3 # This Source Code Form is subject to the terms of the Mozilla Public | 3 # This Source Code Form is subject to the terms of the Mozilla Public |
4 # License, v. 2.0. If a copy of the MPL was not distributed with this | 4 # License, v. 2.0. If a copy of the MPL was not distributed with this |
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
6 | 6 |
7 import os | 7 import os |
8 import io | 8 import io |
9 import ConfigParser | 9 import ConfigParser |
10 from StringIO import StringIO | 10 from StringIO import StringIO |
(...skipping 26 matching lines...) Expand all Loading... | |
37 whitespace-separated lists given by an inherited option: | 37 whitespace-separated lists given by an inherited option: |
38 | 38 |
39 [section] | 39 [section] |
40 opt1 += foo | 40 opt1 += foo |
41 opt2 -= bar | 41 opt2 -= bar |
42 | 42 |
43 The value of the inherit option has to be a relative path with forward | 43 The value of the inherit option has to be a relative path with forward |
44 slashes as delimiters. Up to 5 configuration files can be chained this way, | 44 slashes as delimiters. Up to 5 configuration files can be chained this way, |
45 longer chains are disallowed to deal with circular references. | 45 longer chains are disallowed to deal with circular references. |
46 | 46 |
47 As opposed to ChainedConfigParser, files are decoded as UTF-8 while reading. | 47 As opposed to SafeConfigParser, files are decoded as UTF-8 while |
Wladimir Palant
2015/07/07 14:53:17
Did you mean SafeConfigParser?
Sebastian Noack
2015/07/07 15:20:43
Yes, corrected.
| |
48 Also, ChainedConfigParser data is read-only and the options are case-sensiti ve. | 48 reading. Also, ChainedConfigParser data is read-only. An additional |
Wladimir Palant
2015/07/07 14:53:17
Nit: "case-sensitive by default" (it's configurabl
Sebastian Noack
2015/07/07 15:20:43
Not really. There were some code assumptions, rely
| |
49 An additional option_source(section, option) method is provided to get the | 49 option_source(section, option) method is provided to get the path |
50 path of the configuration file defining this option (for relative paths). | 50 of the configuration file defining this option (for relative paths). |
51 Items returned by the items() function also have a source attribute serving | 51 Items returned by the items() function also have a source attribute |
52 the same purpose. | 52 serving the same purpose. |
53 ''' | 53 ''' |
54 | 54 |
55 def __init__(self): | 55 def __init__(self): |
56 ConfigParser.SafeConfigParser.__init__(self) | 56 ConfigParser.SafeConfigParser.__init__(self) |
57 self._origin = {} | 57 self._origin = {} |
58 | 58 |
59 def _make_parser(self, filename): | 59 def _make_parser(self, filename): |
60 parser = ConfigParser.SafeConfigParser() | 60 parser = ConfigParser.SafeConfigParser() |
61 parser.optionxform = self.optionxform | 61 parser.optionxform = lambda option: option |
62 | 62 |
63 with io.open(filename, encoding='utf-8') as file: | 63 with io.open(filename, encoding='utf-8') as file: |
64 parser.readfp(file, filename) | 64 parser.readfp(file, filename) |
65 | 65 |
66 return parser | 66 return parser |
67 | 67 |
68 def _get_parser_chain(self, parser, filename): | 68 def _get_parser_chain(self, parser, filename): |
69 parsers = [] | 69 parsers = [] |
70 | 70 |
71 while True: | 71 while True: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 # add_section() hardcodes 'default' and raises a ValueError if | 112 # add_section() hardcodes 'default' and raises a ValueError if |
113 # you try to add a section called like that (case insensitive). | 113 # you try to add a section called like that (case insensitive). |
114 # This bug has been fixed in Python 3. | 114 # This bug has been fixed in Python 3. |
115 ConfigParser.SafeConfigParser.readfp(self, StringIO('[%s]' % section )) | 115 ConfigParser.SafeConfigParser.readfp(self, StringIO('[%s]' % section )) |
116 | 116 |
117 for option, value in parser.items(section): | 117 for option, value in parser.items(section): |
118 is_diff, option, value = self._apply_diff(section, option, value) | 118 is_diff, option, value = self._apply_diff(section, option, value) |
119 ConfigParser.SafeConfigParser.set(self, section, option, value) | 119 ConfigParser.SafeConfigParser.set(self, section, option, value) |
120 | 120 |
121 if not is_diff: | 121 if not is_diff: |
122 self._origin[(section, option)] = filename | 122 self._origin[(section, self.optionxform(option))] = filename |
123 | 123 |
124 def read(self, filenames): | 124 def read(self, filenames): |
125 if isinstance(filenames, basestring): | 125 if isinstance(filenames, basestring): |
126 filenames = [filenames] | 126 filenames = [filenames] |
127 | 127 |
128 read_ok = [] | 128 read_ok = [] |
129 for filename in filenames: | 129 for filename in filenames: |
130 try: | 130 try: |
131 parser = self._make_parser(filename) | 131 parser = self._make_parser(filename) |
132 except IOError: | 132 except IOError: |
133 continue | 133 continue |
134 self._process_parsers(self._get_parser_chain(parser, filename)) | 134 self._process_parsers(self._get_parser_chain(parser, filename)) |
135 read_ok.append(filename) | 135 read_ok.append(filename) |
136 | 136 |
137 return read_ok | 137 return read_ok |
138 | 138 |
139 def items(self, section, *args, **kwargs): | 139 def items(self, section, *args, **kwargs): |
140 items = [] | 140 items = [] |
141 for option, value in ConfigParser.SafeConfigParser.items(self, section, *arg s, **kwargs): | 141 for option, value in ConfigParser.SafeConfigParser.items(self, section, *arg s, **kwargs): |
142 items.append(Item(option, value, self._origin[(section, option)])) | 142 items.append(Item( |
143 option, value, | |
144 self._origin[(section, self.optionxform(option))] | |
145 )) | |
143 return items | 146 return items |
144 | 147 |
145 def option_source(self, section, option): | 148 def option_source(self, section, option): |
149 option = self.optionxform(option) | |
146 try: | 150 try: |
147 return self._origin[(section, option)] | 151 return self._origin[(section, option)] |
148 except KeyError: | 152 except KeyError: |
149 if not self.has_section(section): | 153 if not self.has_section(section): |
150 raise ConfigParser.NoSectionError(section) | 154 raise ConfigParser.NoSectionError(section) |
151 raise ConfigParser.NoOptionError(option, section) | 155 raise ConfigParser.NoOptionError(option, section) |
152 | |
153 def optionxform(self, option): | |
154 return option | |
155 | 156 |
156 def readfp(self, fp, filename=None): | 157 def readfp(self, fp, filename=None): |
157 raise NotImplementedError | 158 raise NotImplementedError |
158 | 159 |
159 def set(self, section, option, value=None): | 160 def set(self, section, option, value=None): |
160 raise NotImplementedError | 161 raise NotImplementedError |
161 | 162 |
162 def add_section(self, section): | 163 def add_section(self, section): |
163 raise NotImplementedError | 164 raise NotImplementedError |
164 | 165 |
165 def remove_option(self, section, option): | 166 def remove_option(self, section, option): |
166 raise NotImplementedError | 167 raise NotImplementedError |
167 | 168 |
168 def remove_section(self, section): | 169 def remove_section(self, section): |
169 raise NotImplementedError | 170 raise NotImplementedError |
LEFT | RIGHT |