Index: Lib/configparser.py =================================================================== --- Lib/configparser.py (revision 88301) +++ Lib/configparser.py (working copy) @@ -119,7 +119,7 @@ between keys and values are surrounded by spaces. """ -from collections import MutableMapping, OrderedDict as _default_dict +from collections import Mapping, MutableMapping, OrderedDict as _default_dict import functools import io import itertools @@ -550,7 +550,39 @@ else: return "%%(%s)s" % parser.optionxform(s) +class _Chainmap(Mapping): + """Combine multiple mappings for successive lookups. + For example, to emulate Python's normal lookup sequence: + + import __builtin__ + pylookup = _Chainmap(locals(), globals(), vars(__builtin__)) + """ + + def __init__(self, *maps): + self.maps = maps + + def __getitem__(self, key): + for mapping in self.maps: + try: + return mapping[key] + except KeyError: + pass + raise KeyError(key) + + def __iter__(self): + seen = set() + for mapping in self.maps: + s = set(mapping) - seen + for elem in s: + yield elem + seen.update(s) + + def __len__(self): + s = set() + s.update(*self.maps) + return len(s) + class RawConfigParser(MutableMapping): """ConfigParser that does not do interpolation.""" @@ -1099,23 +1131,24 @@ return exc def _unify_values(self, section, vars): - """Create a copy of the DEFAULTSECT with values from a specific - `section' and the `vars' dictionary. If provided, values in `vars' - take precendence. + """Create a sequence of lookups with 'vars' taking priority over + the 'section' which takes priority over the DEFAULTSECT. + """ - d = self._defaults.copy() + sectiondict = {} try: - d.update(self._sections[section]) + sectiondict = self._sections[section] except KeyError: if section != self.default_section: raise NoSectionError(section) # Update with the entry specific variables + vardict = {} if vars: for key, value in vars.items(): if value is not None: value = str(value) - d[self.optionxform(key)] = value - return d + vardict[self.optionxform(key)] = value + return _Chainmap(vardict, sectiondict, self._defaults) def _convert_to_boolean(self, value): """Return a boolean value translating from other types if necessary.