gh-107625: configparser: Raise error if a missing value is continued (GH-107651)

Co-authored-by: Éric <merwok@netwok.org>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
This commit is contained in:
Prince Roshan 2024-03-06 19:35:54 +05:30 committed by GitHub
parent 27858e2a17
commit e800265aa1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 0 deletions

View File

@ -978,6 +978,10 @@ ConfigParser Objects
The default *dict_type* is :class:`dict`, since it now preserves
insertion order.
.. versionchanged:: 3.13
Raise a :exc:`MultilineContinuationError` when *allow_no_value* is
``True``, and a key without a value is continued with an indented line.
.. method:: defaults()
Return a dictionary containing the instance-wide defaults.
@ -1349,6 +1353,13 @@ Exceptions
The ``filename`` attribute and :meth:`!__init__` constructor argument were
removed. They have been available using the name ``source`` since 3.2.
.. exception:: MultilineContinuationError
Exception raised when a key without a corresponding value is continued with
an indented line.
.. versionadded:: 3.13
.. rubric:: Footnotes
.. [1] Config parsers allow for heavy customization. If you are interested in

View File

@ -152,6 +152,7 @@ __all__ = ("NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
"NoOptionError", "InterpolationError", "InterpolationDepthError",
"InterpolationMissingOptionError", "InterpolationSyntaxError",
"ParsingError", "MissingSectionHeaderError",
"MultilineContinuationError",
"ConfigParser", "RawConfigParser",
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
"SectionProxy", "ConverterMapping",
@ -322,6 +323,19 @@ class MissingSectionHeaderError(ParsingError):
self.args = (filename, lineno, line)
class MultilineContinuationError(ParsingError):
"""Raised when a key without value is followed by continuation line"""
def __init__(self, filename, lineno, line):
Error.__init__(
self,
"Key without value continued with an indented line.\n"
"file: %r, line: %d\n%r"
%(filename, lineno, line))
self.source = filename
self.lineno = lineno
self.line = line
self.args = (filename, lineno, line)
# Used in parser getters to indicate the default behaviour when a specific
# option is not found it to raise an exception. Created to enable `None` as
# a valid fallback value.
@ -987,6 +1001,8 @@ class RawConfigParser(MutableMapping):
cur_indent_level = first_nonspace.start() if first_nonspace else 0
if (cursect is not None and optname and
cur_indent_level > indent_level):
if cursect[optname] is None:
raise MultilineContinuationError(fpname, lineno, line)
cursect[optname].append(value)
# a section header or option header?
else:

View File

@ -1555,6 +1555,30 @@ class ReadFileTestCase(unittest.TestCase):
"'[badbad'"
)
def test_keys_without_value_with_extra_whitespace(self):
lines = [
'[SECT]\n',
'KEY1\n',
' KEY2 = VAL2\n', # note the Space before the key!
]
parser = configparser.ConfigParser(
comment_prefixes="",
allow_no_value=True,
strict=False,
delimiters=('=',),
interpolation=None,
)
with self.assertRaises(configparser.MultilineContinuationError) as dse:
parser.read_file(lines)
self.assertEqual(
str(dse.exception),
"Key without value continued with an indented line.\n"
"file: '<???>', line: 3\n"
"' KEY2 = VAL2\\n'"
)
class CoverageOneHundredTestCase(unittest.TestCase):
"""Covers edge cases in the codebase."""

View File

@ -0,0 +1,4 @@
Raise :exc:`configparser.ParsingError` from :meth:`~configparser.ConfigParser.read`
and :meth:`~configparser.ConfigParser.read_file` methods of
:class:`configparser.ConfigParser` if a key without a corresponding value
is continued (that is, followed by an indented line).