Show More
@@ -163,14 +163,19 b' class LazyConfigValue(HasTraits):' | |||||
163 | return d |
|
163 | return d | |
164 |
|
164 | |||
165 |
|
165 | |||
|
166 | def _is_section_key(key): | |||
|
167 | """Is a Config key a section name (does it start with a capital)?""" | |||
|
168 | if key and key[0].upper()==key[0] and not key.startswith('_'): | |||
|
169 | return True | |||
|
170 | else: | |||
|
171 | return False | |||
|
172 | ||||
|
173 | ||||
166 | class Config(dict): |
|
174 | class Config(dict): | |
167 | """An attribute based dict that can do smart merges.""" |
|
175 | """An attribute based dict that can do smart merges.""" | |
168 |
|
176 | |||
169 | def __init__(self, *args, **kwds): |
|
177 | def __init__(self, *args, **kwds): | |
170 | dict.__init__(self, *args, **kwds) |
|
178 | dict.__init__(self, *args, **kwds) | |
171 | # This sets self.__dict__ = self, but it has to be done this way |
|
|||
172 | # because we are also overriding __setattr__. |
|
|||
173 | dict.__setattr__(self, '__dict__', self) |
|
|||
174 | self._ensure_subconfig() |
|
179 | self._ensure_subconfig() | |
175 |
|
180 | |||
176 | def _ensure_subconfig(self): |
|
181 | def _ensure_subconfig(self): | |
@@ -181,10 +186,10 b' class Config(dict):' | |||||
181 | """ |
|
186 | """ | |
182 | for key in self: |
|
187 | for key in self: | |
183 | obj = self[key] |
|
188 | obj = self[key] | |
184 |
if |
|
189 | if _is_section_key(key) \ | |
185 | and isinstance(obj, dict) \ |
|
190 | and isinstance(obj, dict) \ | |
186 | and not isinstance(obj, Config): |
|
191 | and not isinstance(obj, Config): | |
187 |
|
|
192 | setattr(self, key, Config(obj)) | |
188 |
|
193 | |||
189 | def _merge(self, other): |
|
194 | def _merge(self, other): | |
190 | """deprecated alias, use Config.merge()""" |
|
195 | """deprecated alias, use Config.merge()""" | |
@@ -206,12 +211,6 b' class Config(dict):' | |||||
206 |
|
211 | |||
207 | self.update(to_update) |
|
212 | self.update(to_update) | |
208 |
|
213 | |||
209 | def _is_section_key(self, key): |
|
|||
210 | if key[0].upper()==key[0] and not key.startswith('_'): |
|
|||
211 | return True |
|
|||
212 | else: |
|
|||
213 | return False |
|
|||
214 |
|
||||
215 | def __contains__(self, key): |
|
214 | def __contains__(self, key): | |
216 | # allow nested contains of the form `"Section.key" in config` |
|
215 | # allow nested contains of the form `"Section.key" in config` | |
217 | if '.' in key: |
|
216 | if '.' in key: | |
@@ -221,7 +220,7 b' class Config(dict):' | |||||
221 | return remainder in self[first] |
|
220 | return remainder in self[first] | |
222 |
|
221 | |||
223 | # we always have Sections |
|
222 | # we always have Sections | |
224 |
if |
|
223 | if _is_section_key(key): | |
225 | return True |
|
224 | return True | |
226 | else: |
|
225 | else: | |
227 | return super(Config, self).__contains__(key) |
|
226 | return super(Config, self).__contains__(key) | |
@@ -229,7 +228,7 b' class Config(dict):' | |||||
229 | has_key = __contains__ |
|
228 | has_key = __contains__ | |
230 |
|
229 | |||
231 | def _has_section(self, key): |
|
230 | def _has_section(self, key): | |
232 |
if |
|
231 | if _is_section_key(key): | |
233 | if super(Config, self).__contains__(key): |
|
232 | if super(Config, self).__contains__(key): | |
234 | return True |
|
233 | return True | |
235 | return False |
|
234 | return False | |
@@ -245,20 +244,7 b' class Config(dict):' | |||||
245 | return type(self)(copy.deepcopy(list(self.items()))) |
|
244 | return type(self)(copy.deepcopy(list(self.items()))) | |
246 |
|
245 | |||
247 | def __getitem__(self, key): |
|
246 | def __getitem__(self, key): | |
248 | # We cannot use directly self._is_section_key, because it triggers |
|
247 | if _is_section_key(key): | |
249 | # infinite recursion on top of PyPy. Instead, we manually fish the |
|
|||
250 | # bound method. |
|
|||
251 | is_section_key = self.__class__._is_section_key.__get__(self) |
|
|||
252 |
|
||||
253 | # Because we use this for an exec namespace, we need to delegate |
|
|||
254 | # the lookup of names in __builtin__ to itself. This means |
|
|||
255 | # that you can't have section or attribute names that are |
|
|||
256 | # builtins. |
|
|||
257 | try: |
|
|||
258 | return getattr(builtin_mod, key) |
|
|||
259 | except AttributeError: |
|
|||
260 | pass |
|
|||
261 | if is_section_key(key): |
|
|||
262 | try: |
|
248 | try: | |
263 | return dict.__getitem__(self, key) |
|
249 | return dict.__getitem__(self, key) | |
264 | except KeyError: |
|
250 | except KeyError: | |
@@ -269,36 +255,37 b' class Config(dict):' | |||||
269 | try: |
|
255 | try: | |
270 | return dict.__getitem__(self, key) |
|
256 | return dict.__getitem__(self, key) | |
271 | except KeyError: |
|
257 | except KeyError: | |
272 | if key.startswith('__'): |
|
|||
273 | # don't create LazyConfig on special method requests |
|
|||
274 | raise |
|
|||
275 | # undefined, create lazy value, used for container methods |
|
258 | # undefined, create lazy value, used for container methods | |
276 | v = LazyConfigValue() |
|
259 | v = LazyConfigValue() | |
277 | dict.__setitem__(self, key, v) |
|
260 | dict.__setitem__(self, key, v) | |
278 | return v |
|
261 | return v | |
279 |
|
262 | |||
280 |
|
||||
281 | def __setitem__(self, key, value): |
|
263 | def __setitem__(self, key, value): | |
282 |
if |
|
264 | if _is_section_key(key): | |
283 | if not isinstance(value, Config): |
|
265 | if not isinstance(value, Config): | |
284 | raise ValueError('values whose keys begin with an uppercase ' |
|
266 | raise ValueError('values whose keys begin with an uppercase ' | |
285 | 'char must be Config instances: %r, %r' % (key, value)) |
|
267 | 'char must be Config instances: %r, %r' % (key, value)) | |
286 | else: |
|
|||
287 |
|
|
268 | dict.__setitem__(self, key, value) | |
288 |
|
269 | |||
289 | def __getattr__(self, key): |
|
270 | def __getattr__(self, key): | |
|
271 | if key.startswith('__'): | |||
|
272 | return dict.__getattr__(self, key) | |||
290 | try: |
|
273 | try: | |
291 | return self.__getitem__(key) |
|
274 | return self.__getitem__(key) | |
292 | except KeyError as e: |
|
275 | except KeyError as e: | |
293 | raise AttributeError(e) |
|
276 | raise AttributeError(e) | |
294 |
|
277 | |||
295 | def __setattr__(self, key, value): |
|
278 | def __setattr__(self, key, value): | |
|
279 | if key.startswith('__'): | |||
|
280 | return dict.__setattr__(self, key, value) | |||
296 | try: |
|
281 | try: | |
297 | self.__setitem__(key, value) |
|
282 | self.__setitem__(key, value) | |
298 | except KeyError as e: |
|
283 | except KeyError as e: | |
299 | raise AttributeError(e) |
|
284 | raise AttributeError(e) | |
300 |
|
285 | |||
301 | def __delattr__(self, key): |
|
286 | def __delattr__(self, key): | |
|
287 | if key.startswith('__'): | |||
|
288 | return dict.__delattr__(self, key) | |||
302 | try: |
|
289 | try: | |
303 | dict.__delitem__(self, key) |
|
290 | dict.__delitem__(self, key) | |
304 | except KeyError as e: |
|
291 | except KeyError as e: |
General Comments 0
You need to be logged in to leave comments.
Login now