Skip to content

gh-157456: Fix configparser parsing an empty value with a whitespace-ending delimiter - #157457

Open
winklemad wants to merge 1 commit into
python:mainfrom
winklemad:configparser-ws-delimiter-empty-value
Open

gh-157456: Fix configparser parsing an empty value with a whitespace-ending delimiter#157457
winklemad wants to merge 1 commit into
python:mainfrom
winklemad:configparser-ws-delimiter-empty-value

Conversation

@winklemad

@winklemad winklemad commented Sep 13, 2026

Copy link
Copy Markdown

The whitespace-in-delimiters feature (gh-156353) can't parse an option with an empty value when the delimiter ends in whitespace — including its own write() output.

_read matches option lines against line.clean, which is str.strip-ed on both sides (plus comment removal). For a whitespace delimiter the delimiter is the trailing whitespace separating the key from the (empty) value, so strip() removes it and OPTCRE no longer matches.

>>> import configparser, io
>>> cp = configparser.ConfigParser(delimiters=(' ',))
>>> cp.read_string("[s]\nkey \n")          # ParsingError  (before); {'s': {'key': ''}}  (after)
>>> w = configparser.ConfigParser(delimiters=(' ',)); w['s'] = {'key': ''}
>>> buf = io.StringIO(); w.write(buf); buf.getvalue()
'[s]\nkey   \n\n'
>>> configparser.ConfigParser(delimiters=(' ',)).read_string(buf.getvalue())   # ParsingError before; now OK

Empty values are first-class for every other delimiter (key=, key:, key->, key||{'key': ''}), so whitespace delimiters should match.

Fix: match the option regex against a form that preserves trailing whitespace (the delimiter). The matched value is .strip()-ed immediately afterwards, so ordinary values keep no trailing whitespace, and the other uses of line.clean (blank-line detection, continuation values, section headers) are unchanged. With allow_no_value=True a whitespace delimiter can't distinguish an empty value from a valueless option, so it reads as None there (unchanged, and self-consistent on round-trip); the regression test covers both modes.

AI-tools disclosure (per the devguide policy): I used an AI assistant to help locate the bug and draft the patch and test. I reproduced and verified the behaviour and the fix against a locally built interpreter, understand the change, and stand by it.

…space-ending delimiter

An option whose delimiter ends in whitespace (e.g. ``delimiters=(' ',)``) and
has an empty value could not be parsed, and the parser could not read back the
output produced by ``write()``: ``_read`` matched option lines against
``line.clean``, which is ``str.strip``-ed on both sides, so for a whitespace
delimiter the trailing whitespace that separates the key from the (empty) value
was removed and ``OPTCRE`` no longer matched.

Match the option regex against a form that preserves trailing whitespace. The
matched value is stripped immediately afterwards, so ordinary values keep no
trailing whitespace, and the other uses of ``line.clean`` are unchanged.

Add a regression test; the pythongh-156353 whitespace-delimiter tests only used
non-empty values, so this edge was unpinned.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

configparser: whitespace-ending delimiter with an empty value cannot be parsed (write() output is unreadable)

1 participant