""" This is a heavily hacked version of ConfigParser to keep the order in which options and sections are read, and allow multiple options with the same key. """ import contextlib import os import re import string __all__ = [ "MAX_INTERPOLATION_DEPTH", "ConfigParser", "DuplicateSectionError", "InterpolationDepthError", "InterpolationError", "MissingSectionHeaderError", "NoOptionError", "NoSectionError", "ParsingError", ] DEFAULTSECT = "DEFAULT" MAX_INTERPOLATION_DEPTH = 10 # exception classes class Error(Exception): def __init__(self, msg=''): self._msg = msg Exception.__init__(self, msg) def __repr__(self): return self._msg __str__ = __repr__ class NoSectionError(Error): def __init__(self, section): Error.__init__(self, 'No section: %s' % section) self.section = section class DuplicateSectionError(Error): def __init__(self, section): Error.__init__(self, "Section %s already exists" % section) self.section = section class NoOptionError(Error): def __init__(self, option, section): Error.__init__(self, "No option `%s' in section: %s" % (option, section)) self.option = option self.section = section class InterpolationError(Error): def __init__(self, reference, option, section, rawval): Error.__init__(self, "Bad value substitution:\n" "\tsection: [%s]\n" "\toption : %s\n" "\tkey : %s\n" "\trawval : %s\n" % (section, option, reference, rawval)) self.reference = reference self.option = option self.section = section class InterpolationDepthError(Error): def __init__(self, option, section, rawval): Error.__init__(self, "Value interpolation too deeply recursive:\n" "\tsection: [%s]\n" "\toption : %s\n" "\trawval : %s\n" % (section, option, rawval)) self.option = option self.section = section class ParsingError(Error): def __init__(self, filename): Error.__init__(self, 'File contains parsing errors: %s' % filename) self.filename = filename self.errors = [] def append(self, lineno, line): self.errors.append((lineno, line)) self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line) class MissingSectionHeaderError(ParsingError): def __init__(self, filename, lineno, line): Error.__init__( self, 'File contains no section headers.\nfile: %s, line: %d\n%s' % (filename, lineno, line)) self.filename = filename self.lineno = lineno self.line = line class ConfigParser: def __init__(self, defaults=None): # Options are stored in __sections_list like this: # [(sectname, [(optname, optval), ...]), ...] self.__sections_list = [] self.__sections_dict = {} if defaults is None: self.__defaults = {} else: self.__defaults = defaults def defaults(self): return self.__defaults def sections(self): return list(self.__sections_dict.keys()) def has_section(self, section): return section in self.__sections_dict def options(self, section): self.__sections_dict[section] try: opts = list(self.__sections_dict[section].keys()) except KeyError as e: raise NoSectionError(section) from e return list(self.__defaults.keys())+opts def read(self, filenames): if isinstance(filenames , str): filenames = [filenames] for filename in filenames: with contextlib.suppress(OSError), open(filename) as fp: self.__read(fp, filename) def readfp(self, fp, filename=None): if filename is None: try: filename = fp.name except AttributeError: filename = '' self.__read(fp, filename) def set(self, section, option, value): if section in self.__sections_dict: sectdict = self.__sections_dict[section] sectlist = [] self.__sections_list.append((section, sectlist)) elif section == DEFAULTSECT: sectdict = self.__defaults sectlist = None else: sectdict = {} self.__sections_dict[section] = sectdict sectlist = [] self.__sections_list.append((section, sectlist)) xform = self.optionxform(option) sectdict[xform] = value if sectlist is not None: sectlist.append([xform, value]) def get(self, section, option, raw=0, vars=None): d = self.__defaults.copy() try: d.update(self.__sections_dict[section]) except KeyError as e: if section != DEFAULTSECT: raise NoSectionError(section) from e if vars: d.update(vars) option = self.optionxform(option) try: rawval = d[option] except KeyError as e: raise NoOptionError(option, section) from e if raw: return rawval return self.__interpolate(rawval, d, option, section) def getall(self, section, option, raw=0, vars=None): option = self.optionxform(option) values = [] d = self.__defaults.copy() if section != DEFAULTSECT: for sectname, options in self.__sections_list: if sectname == section: for optname, value in options: if optname == option: values.append(value) d[optname] = value if raw: return values if vars: d.update(vars) for i in range(len(values)): values[i] = self.__interpolate(values[i], d, option, section) return values def walk(self, section, option=None, raw=0, vars=None): # Build dictionary for interpolation try: d = self.__sections_dict[section].copy() except KeyError as e: if section == DEFAULTSECT: d = {} else: raise NoSectionError(section) from e d.update(self.__defaults) if vars: d.update(vars) # Start walking if option: option = self.optionxform(option) if section != DEFAULTSECT: for sectname, options in self.__sections_list: if sectname == section: for optname, value in options: if not option or optname == option: if not raw: value = self.__interpolate(value, d, option, section) yield (optname, value) def __interpolate(self, value, vars, option, section): rawval = value depth = 0 while depth < 10: depth = depth + 1 if value.find("%(") >= 0: try: value = value % vars except KeyError as key: raise InterpolationError(key, option, section, rawval) from key else: break if value.find("%(") >= 0: raise InterpolationDepthError(option, section, rawval) return value def __get(self, section, conv, option): return conv(self.get(section, option)) def getint(self, section, option): return self.__get(section, int, option) def getfloat(self, section, option): return self.__get(section, float, option) def getboolean(self, section, option): states = {'1': 1, 'yes': 1, 'true': 1, 'on': 1, '0': 0, 'no': 0, 'false': 0, 'off': 0} v = self.get(section, option) if v.lower() not in states: raise ValueError('Not a boolean: %s' % v) return states[v.lower()] def optionxform(self, optionstr): #return optionstr.lower() return optionstr def has_option(self, section, option): """Check for the existence of a given option in a given section.""" if not section or section == "DEFAULT": return option in self.__defaults if not self.has_section(section): return 0 option = self.optionxform(option) return option in self.__sections_dict[section] SECTCRE = re.compile(r'\[(?P
[^]]+)\]') OPTCRE = re.compile(r'(?P