Index: Lib/configparser.py =================================================================== --- Lib/configparser.py (revision 83161) +++ Lib/configparser.py (working copy) @@ -24,12 +24,24 @@ methods: - __init__(defaults=None) - create the parser and specify a dictionary of intrinsic defaults. The - keys must be strings, the values must be appropriate for %()s string - interpolation. Note that `__name__' is always an intrinsic default; - its value is the section's name. + __init__(defaults=None, dict_type=collections.OrderedDict, + delimiters=('=', ':'), allow_no_value=False) + create the parser. When `defaults' is given, it is initialized into the + dictionary or intrinsic defaults. The keys must be strings, the values + must be appropriate for %()s string interpolation. Note that `__name__' + is always an intrinsic default; its value is the section's name. + + When `dict_type' is given, it will be used to create the dictionary + objects for the list of sections, for the options within a section, and + for the default values. + + When `delimiters' is given, it will be used as the set of substrings + that divide keys from values. + + When `allow_no_value' is `True' (default: `False'), options without + values are accepted; the value presented for these is ``None``. + sections() return all the configuration section names, sans DEFAULT @@ -94,6 +106,8 @@ _default_dict = dict import re +import sre_parse +import sys __all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError", "InterpolationError", "InterpolationDepthError", @@ -229,17 +243,27 @@ class RawConfigParser: def __init__(self, defaults=None, dict_type=_default_dict, - allow_no_value=False): + delimiters=('=', ':'), comment_prefixes=('#', ';'), + empty_lines_in_values=True, allow_no_value=False): self._dict = dict_type self._sections = self._dict() self._defaults = self._dict() - if allow_no_value: - self._optcre = self.OPTCRE_NV - else: - self._optcre = self.OPTCRE if defaults: for key, value in defaults.items(): self._defaults[self.optionxform(key)] = value + self._delimiters = tuple(delimiters) + if delimiters != ('=', ':'): + spec = sre_parse.SPECIAL_CHARS + escape = lambda d: d if d not in spec else r'\{}'.format(d) + delim = "|".join((escape(d) for d in delimiters)) + self.OPTCRE = re.compile(self._OPT_TMPL.format(delim=delim), + re.VERBOSE) + self.OPTCRE_NV = re.compile(self._OPT_NV_TMPL.format(delim=delim), + re.VERBOSE) + self._comment_prefixes = tuple(comment_prefixes) + self._empty_lines_in_values = empty_lines_in_values + if allow_no_value: + self.OPTCRE = self.OPTCRE_NV def defaults(self): return self._defaults @@ -395,12 +419,17 @@ raise NoSectionError(section) sectdict[self.optionxform(option)] = value - def write(self, fp): + def write(self, fp, space_around_delimiters=True): """Write an .ini-format representation of the configuration state.""" + if space_around_delimiters: + d = " {} ".format(self._delimiters[0]) + else: + d = self._delimiters[0] if self._defaults: fp.write("[%s]\n" % DEFAULTSECT) for (key, value) in self._defaults.items(): - fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) + fp.write("%s%s%s\n" % (key, d, + str(value).replace('\n', '\n\t'))) fp.write("\n") for section in self._sections: fp.write("[%s]\n" % section) @@ -408,7 +437,7 @@ if key == "__name__": continue if value is not None: - key = " = ".join((key, str(value).replace('\n', '\n\t'))) + key = d.join((key, str(value).replace('\n', '\n\t'))) fp.write("%s\n" % (key)) fp.write("\n") @@ -437,28 +466,33 @@ # # Regular expressions for parsing section headers and options. # - SECTCRE = re.compile( - r'\[' # [ - r'(?P
[^]]+)' # very permissive! - r'\]' # ] - ) - OPTCRE = re.compile( - r'(?P