Skip to content

Commit 47a9a4b

Browse files
committed
Fixes python#24142: [configparser] always join multiline values to not leave the parser in an invalid state
1 parent c7b1a0b commit 47a9a4b

File tree

4 files changed

+29
-1
lines changed

4 files changed

+29
-1
lines changed

Lib/configparser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,10 +1102,10 @@ def _read(self, fp, fpname):
11021102
# raised at the end of the file and will contain a
11031103
# list of all bogus lines
11041104
e = self._handle_error(e, fpname, lineno, line)
1105+
self._join_multiline_values()
11051106
# if any parsing errors occurred, raise an exception
11061107
if e:
11071108
raise e
1108-
self._join_multiline_values()
11091109

11101110
def _join_multiline_values(self):
11111111
defaults = self.default_section, self._defaults

Lib/test/test_configparser.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from test import support
1111

12+
1213
class SortedDict(collections.UserDict):
1314

1415
def items(self):
@@ -64,6 +65,7 @@ def fromstring(self, string, defaults=None):
6465
cf.read_string(string)
6566
return cf
6667

68+
6769
class BasicTestCase(CfgParserTestCaseClass):
6870

6971
def basic_test(self, cf):
@@ -828,6 +830,21 @@ def test_setitem(self):
828830
self.assertEqual(set(cf['section3'].keys()), set())
829831
self.assertEqual(cf.sections(), ['section1', 'section2', 'section3'])
830832

833+
def test_invalid_multiline_value(self):
834+
if self.allow_no_value:
835+
self.skipTest('if no_value is allowed, ParsingError is not raised')
836+
837+
invalid = textwrap.dedent("""\
838+
[DEFAULT]
839+
test {0} test
840+
invalid""".format(self.delimiters[0])
841+
)
842+
cf = self.newconfig()
843+
with self.assertRaises(configparser.ParsingError):
844+
cf.read_string(invalid)
845+
self.assertEqual(cf.get('DEFAULT', 'test'), 'test')
846+
self.assertEqual(cf['DEFAULT']['test'], 'test')
847+
831848

832849
class StrictTestCase(BasicTestCase, unittest.TestCase):
833850
config_class = configparser.RawConfigParser
@@ -981,14 +998,17 @@ def test_set_malformatted_interpolation(self):
981998
cf.set("sect", "option2", "foo%%bar")
982999
self.assertEqual(cf.get("sect", "option2"), "foo%%bar")
9831000

1001+
9841002
class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
9851003
delimiters = (':=', '$')
9861004
comment_prefixes = ('//', '"')
9871005
inline_comment_prefixes = ('//', '"')
9881006

1007+
9891008
class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
9901009
default_section = 'general'
9911010

1011+
9921012
class MultilineValuesTestCase(BasicTestCase, unittest.TestCase):
9931013
config_class = configparser.ConfigParser
9941014
wonderful_spam = ("I'm having spam spam spam spam "
@@ -1017,6 +1037,7 @@ def test_dominating_multiline_values(self):
10171037
self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
10181038
self.wonderful_spam.replace('\t\n', '\n'))
10191039

1040+
10201041
class RawConfigParserTestCase(BasicTestCase, unittest.TestCase):
10211042
config_class = configparser.RawConfigParser
10221043

@@ -1059,11 +1080,13 @@ def test_set_nonstring_types(self):
10591080
cf.set('non-string', 1, 1)
10601081
self.assertEqual(cf.get('non-string', 1), 1)
10611082

1083+
10621084
class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
10631085
delimiters = (':=', '$')
10641086
comment_prefixes = ('//', '"')
10651087
inline_comment_prefixes = ('//', '"')
10661088

1089+
10671090
class RawConfigParserTestSambaConf(CfgParserTestCaseClass, unittest.TestCase):
10681091
config_class = configparser.RawConfigParser
10691092
comment_prefixes = ('#', ';', '----')
@@ -1258,6 +1281,7 @@ def test_other_errors(self):
12581281
class ConfigParserTestCaseNoValue(ConfigParserTestCase):
12591282
allow_no_value = True
12601283

1284+
12611285
class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass, unittest.TestCase):
12621286
config_class = configparser.ConfigParser
12631287
delimiters = {'='}

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ Jeremy Hylton
655655
Ludwig Hähne
656656
Gerhard Häring
657657
Fredrik Håård
658+
Florian Höch
658659
Catalin Iacob
659660
Mihai Ibanescu
660661
Ali Ikinci

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ Library
472472

473473
- Issue #28703: Fix asyncio.iscoroutinefunction to handle Mock objects.
474474

475+
- Issue #24142: Reading a corrupt config file left the parser in an
476+
invalid state. Original patch by Florian Höch.
477+
475478
IDLE
476479
----
477480

0 commit comments

Comments
 (0)