https://github.com/python/cpython/commit/c95e3de17e94db75f8b98e6141a51ed0dc41459c
commit: c95e3de17e94db75f8b98e6141a51ed0dc41459c
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: hugovk <[email protected]>
date: 2026-08-29T11:05:39Z
summary:

[3.15] gh-156353: Fix configparser space delimiter parsing (GH-156382) (#156557)

Co-authored-by: sundeep8967 <[email protected]>
Co-authored-by: Petr Viktorin <[email protected]>
Signed-off-by: sundeep8967 <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-08-26-02-30-00.gh-issue-156353.abcdef.rst
M Lib/configparser.py
M Lib/test/test_configparser.py

diff --git a/Lib/configparser.py b/Lib/configparser.py
index 3c452afe8ade48..88015ef6086569 100644
--- a/Lib/configparser.py
+++ b/Lib/configparser.py
@@ -618,7 +618,8 @@ class RawConfigParser(MutableMapping):
     _OPT_TMPL = r"""
         (?P<option>                        # very permissive!
             (?:(?!{delim})\S)*             # non-delimiter non-whitespace
-            (?:\s+(?:(?!{delim})\S)+)*)    # optionally more words
+            (?:(?:(?!{delim})\s)+          # optionally more
+             (?:(?!{delim})\S)+)*)         #   space-separated words
         \s*(?P<vi>{delim})\s*              # any number of space/tab,
                                            # followed by any of the
                                            # allowed delimiters,
@@ -628,7 +629,8 @@ class RawConfigParser(MutableMapping):
     _OPT_NV_TMPL = r"""
         (?P<option>                        # very permissive!
             (?:(?!{delim})\S)*             # non-delimiter non-whitespace
-            (?:\s+(?:(?!{delim})\S)+)*)    # optionally more words
+            (?:(?:(?!{delim})\s)+          # optionally more
+             (?:(?!{delim})\S)+)*)         #   space-separated words
         \s*(?:                             # any number of space/tab,
         (?P<vi>{delim})\s*                 # optionally followed by
                                            # any of the allowed
diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py
index 4783943f71a109..7d1e68fe38100e 100644
--- a/Lib/test/test_configparser.py
+++ b/Lib/test/test_configparser.py
@@ -43,7 +43,7 @@ class CfgParserTestCaseClass:
     default_section = configparser.DEFAULTSECT
     interpolation = configparser._UNSET
 
-    def newconfig(self, defaults=None):
+    def newconfig(self, defaults=None, **kwargs):
         arguments = dict(
             defaults=defaults,
             allow_no_value=self.allow_no_value,
@@ -56,6 +56,7 @@ def newconfig(self, defaults=None):
             default_section=self.default_section,
             interpolation=self.interpolation,
         )
+        arguments.update(kwargs)
         instance = self.config_class(**arguments)
         return instance
 
@@ -358,6 +359,32 @@ def test_basic(self):
                 the larch {0[1]} 1
             """.format(self.delimiters)))
 
+    @support.subTests('data', [
+        'foo bar=baz',
+        'foo   bar=baz',
+        'foo=bar=baz',
+        'foo = bar=baz',
+        'foo\t \t=\t \tbar=baz',
+    ])
+    def test_space_delimiter(self, data):
+        # gh-156353: Space should be accepted as a delimiter
+        cf = self.newconfig(delimiters=(' ', '='))
+        cf.read_string(f"[all]\n{data}")
+        self.assertEqual(cf.options('all'), ['foo'])
+        self.assertEqual(cf.get('all', 'foo'), 'bar=baz')
+
+    @support.subTests('delimiter', ' =:;#x\t\0\N{RS}\N{CEDILLA}\N{CAT}')
+    @support.subTests('space_before', ['', ' ', '\t', ' \t'])
+    @support.subTests('space_after', ['', ' ', '\t', ' \t'])
+    def test_any_delimiter(self, delimiter, space_before, space_after):
+        cf = self.newconfig(
+            delimiters=(delimiter,),
+            inline_comment_prefixes=None,
+        )
+        
cf.read_string(f"[all]\nfoo{space_before}{delimiter}{space_after}bar=baz")
+        self.assertEqual(cf.options('all'), ['foo'])
+        self.assertEqual(cf.get('all', 'foo'), 'bar=baz')
+
     def test_basic_from_dict(self):
         config = {
             "Foo Bar": {
@@ -1991,8 +2018,8 @@ class ConvertersTestCase(BasicTestCase, 
unittest.TestCase):
 
     config_class = configparser.ConfigParser
 
-    def newconfig(self, defaults=None):
-        instance = super().newconfig(defaults=defaults)
+    def newconfig(self, defaults=None, **kwargs):
+        instance = super().newconfig(defaults=defaults, **kwargs)
         instance.converters['list'] = lambda v: [e.strip() for e in v.split()
                                                  if e.strip()]
         return instance
diff --git 
a/Misc/NEWS.d/next/Library/2026-08-26-02-30-00.gh-issue-156353.abcdef.rst 
b/Misc/NEWS.d/next/Library/2026-08-26-02-30-00.gh-issue-156353.abcdef.rst
new file mode 100644
index 00000000000000..0dd925cf596277
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-26-02-30-00.gh-issue-156353.abcdef.rst
@@ -0,0 +1 @@
+Fix :mod:`configparser` parsing when using whitespace in *delimiters*.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to