From c35c7353eb8fbccff2d3a6ab664426b31af00d4d Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 16 Apr 2025 13:39:11 +0300 Subject: [PATCH] gh-130941: Fix `configparser` parsing values with `allow_no_value` and `interpolation` set (GH-130949) --- Lib/configparser.py | 2 + Lib/test/test_configparser.py | 41 +++++++++++++++++++ ...-03-07-17-47-32.gh-issue-130941.7_GvhW.rst | 2 + 3 files changed, 45 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-03-07-17-47-32.gh-issue-130941.7_GvhW.rst diff --git a/Lib/configparser.py b/Lib/configparser.py index 70cc651edabd..239fda60a02c 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -541,6 +541,8 @@ def _interpolate_some(self, parser, option, accum, rest, section, map, except (KeyError, NoSectionError, NoOptionError): raise InterpolationMissingOptionError( option, section, rawval, ":".join(path)) from None + if v is None: + continue if "$" in v: self._interpolate_some(parser, opt, accum, v, sect, dict(parser.items(sect, raw=True)), diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 1313ec2b9e88..23904d17d326 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1328,6 +1328,47 @@ class ConfigParserTestCaseNoValue(ConfigParserTestCase): allow_no_value = True +class NoValueAndExtendedInterpolation(CfgParserTestCaseClass): + interpolation = configparser.ExtendedInterpolation() + allow_no_value = True + + def test_interpolation_with_allow_no_value(self): + config = textwrap.dedent(""" + [dummy] + a + b = ${a} + """) + cf = self.fromstring(config) + + self.assertIs(cf["dummy"]["a"], None) + self.assertEqual(cf["dummy"]["b"], "") + + def test_explicit_none(self): + config = textwrap.dedent(""" + [dummy] + a = None + b = ${a} + """) + cf = self.fromstring(config) + + self.assertEqual(cf["dummy"]["a"], "None") + self.assertEqual(cf["dummy"]["b"], "None") + + +class ConfigParserNoValueAndExtendedInterpolationTest( + NoValueAndExtendedInterpolation, + unittest.TestCase, +): + config_class = configparser.ConfigParser + + +class RawConfigParserNoValueAndExtendedInterpolationTest( + NoValueAndExtendedInterpolation, + unittest.TestCase, +): + config_class = configparser.RawConfigParser + + class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass, unittest.TestCase): config_class = configparser.ConfigParser delimiters = {'='} diff --git a/Misc/NEWS.d/next/Library/2025-03-07-17-47-32.gh-issue-130941.7_GvhW.rst b/Misc/NEWS.d/next/Library/2025-03-07-17-47-32.gh-issue-130941.7_GvhW.rst new file mode 100644 index 000000000000..4f0cda8d03e9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-07-17-47-32.gh-issue-130941.7_GvhW.rst @@ -0,0 +1,2 @@ +Fix :class:`configparser.ConfigParser` parsing empty interpolation with +``allow_no_value`` set to ``True``.