Skip to content

Commit e53e133

Browse files
Agent-Hellboymerwokencukoujaraco
authored andcommitted
pythongh-107625: configparser: Raise error if a missing value is continued (pythonGH-107651)
Co-authored-by: Éric <[email protected]> Co-authored-by: Petr Viktorin <[email protected]> Co-authored-by: Jason R. Coombs <[email protected]>
1 parent c3d9d46 commit e53e133

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

Doc/library/configparser.rst

+11
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,10 @@ ConfigParser Objects
978978
The default *dict_type* is :class:`dict`, since it now preserves
979979
insertion order.
980980

981+
.. versionchanged:: 3.13
982+
Raise a :exc:`MultilineContinuationError` when *allow_no_value* is
983+
``True``, and a key without a value is continued with an indented line.
984+
981985
.. method:: defaults()
982986

983987
Return a dictionary containing the instance-wide defaults.
@@ -1349,6 +1353,13 @@ Exceptions
13491353
The ``filename`` attribute and :meth:`!__init__` constructor argument were
13501354
removed. They have been available using the name ``source`` since 3.2.
13511355

1356+
.. exception:: MultilineContinuationError
1357+
1358+
Exception raised when a key without a corresponding value is continued with
1359+
an indented line.
1360+
1361+
.. versionadded:: 3.13
1362+
13521363
.. rubric:: Footnotes
13531364

13541365
.. [1] Config parsers allow for heavy customization. If you are interested in

Lib/configparser.py

+16
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"NoOptionError", "InterpolationError", "InterpolationDepthError",
153153
"InterpolationMissingOptionError", "InterpolationSyntaxError",
154154
"ParsingError", "MissingSectionHeaderError",
155+
"MultilineContinuationError",
155156
"ConfigParser", "RawConfigParser",
156157
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
157158
"SectionProxy", "ConverterMapping",
@@ -322,6 +323,19 @@ def __init__(self, filename, lineno, line):
322323
self.args = (filename, lineno, line)
323324

324325

326+
class MultilineContinuationError(ParsingError):
327+
"""Raised when a key without value is followed by continuation line"""
328+
def __init__(self, filename, lineno, line):
329+
Error.__init__(
330+
self,
331+
"Key without value continued with an indented line.\n"
332+
"file: %r, line: %d\n%r"
333+
%(filename, lineno, line))
334+
self.source = filename
335+
self.lineno = lineno
336+
self.line = line
337+
self.args = (filename, lineno, line)
338+
325339
# Used in parser getters to indicate the default behaviour when a specific
326340
# option is not found it to raise an exception. Created to enable `None` as
327341
# a valid fallback value.
@@ -987,6 +1001,8 @@ def _read(self, fp, fpname):
9871001
cur_indent_level = first_nonspace.start() if first_nonspace else 0
9881002
if (cursect is not None and optname and
9891003
cur_indent_level > indent_level):
1004+
if cursect[optname] is None:
1005+
raise MultilineContinuationError(fpname, lineno, line)
9901006
cursect[optname].append(value)
9911007
# a section header or option header?
9921008
else:

Lib/test/test_configparser.py

+24
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,30 @@ def test_source_as_bytes(self):
15551555
"'[badbad'"
15561556
)
15571557

1558+
def test_keys_without_value_with_extra_whitespace(self):
1559+
lines = [
1560+
'[SECT]\n',
1561+
'KEY1\n',
1562+
' KEY2 = VAL2\n', # note the Space before the key!
1563+
]
1564+
parser = configparser.ConfigParser(
1565+
comment_prefixes="",
1566+
allow_no_value=True,
1567+
strict=False,
1568+
delimiters=('=',),
1569+
interpolation=None,
1570+
)
1571+
with self.assertRaises(configparser.MultilineContinuationError) as dse:
1572+
parser.read_file(lines)
1573+
self.assertEqual(
1574+
str(dse.exception),
1575+
"Key without value continued with an indented line.\n"
1576+
"file: '<???>', line: 3\n"
1577+
"' KEY2 = VAL2\\n'"
1578+
)
1579+
1580+
1581+
15581582

15591583
class CoverageOneHundredTestCase(unittest.TestCase):
15601584
"""Covers edge cases in the codebase."""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Raise :exc:`configparser.ParsingError` from :meth:`~configparser.ConfigParser.read`
2+
and :meth:`~configparser.ConfigParser.read_file` methods of
3+
:class:`configparser.ConfigParser` if a key without a corresponding value
4+
is continued (that is, followed by an indented line).

0 commit comments

Comments
 (0)