Index: Doc/library/configparser.rst =================================================================== --- Doc/library/configparser.rst (revision 60075) +++ Doc/library/configparser.rst (working copy) @@ -29,12 +29,12 @@ The configuration file consists of sections, led by a ``[section]`` header and followed by ``name: value`` entries, with continuations in the style of -:rfc:`822`; ``name=value`` is also accepted. Note that leading whitespace is -removed from values. The optional values can contain format strings which refer -to other values in the same section, or values in a special ``DEFAULT`` section. -Additional defaults can be provided on initialization and retrieval. Lines -beginning with ``'#'`` or ``';'`` are ignored and may be used to provide -comments. +:rfc:`822`; ``name=value`` is also accepted. Note that trailing and leading +whitespaces are removed from values, unless wrapped inside double quotes. The +optional values can contain format strings which refer to other values in the +same section, or values in a special ``DEFAULT`` section. Additional defaults +can be provided on initialization and retrieval. Lines beginning with ``'#'`` +or ``';'`` are ignored and may be used to provide comments. For example:: Index: Lib/ConfigParser.py =================================================================== --- Lib/ConfigParser.py (revision 60075) +++ Lib/ConfigParser.py (working copy) @@ -488,9 +488,9 @@ if pos != -1 and optval[pos-1].isspace(): optval = optval[:pos] optval = optval.strip() - # allow empty values - if optval == '""': - optval = '' + # allow double quotes to prevent trailing and leading + # spaces from being stripped + optval = optval.strip('"') optname = self.optionxform(optname.rstrip()) cursect[optname] = optval else: Index: Lib/test/test_cfgparser.py =================================================================== --- Lib/test/test_cfgparser.py (revision 60075) +++ Lib/test/test_cfgparser.py (working copy) @@ -145,6 +145,16 @@ cf.get("DEFAULT", "Foo"), "Bar", "could not locate option, expecting case-insensitive defaults") + def test_double_quotes(self): + cf = self.fromstring( + "[Spam]\n" + "egg=\"\"\n" + "bacon= \" with trailing and leading spaces \"\n" + ) + eq = self.assertEqual + eq(cf.get('Spam', 'egg'), '') + eq(cf.get('Spam', 'bacon'), ' with trailing and leading spaces ') + def test_parse_errors(self): self.newconfig() self.parse_error(ConfigParser.ParsingError,