From 450c6c166e75752d524a07ef38af3f1752770218 Mon Sep 17 00:00:00 2001 From: Pedro Sousa Lacerda Date: Fri, 16 Aug 2024 17:30:56 -0300 Subject: [PATCH 01/11] Add support to unnamed section on `RawConfigParser.add_section` May fix #123049. --- Lib/configparser.py | 21 ++++++++++++------- Lib/test/test_configparser.py | 5 +++++ ...-08-16-16-53-52.gh-issue-123049.izx_fH.rst | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst diff --git a/Lib/configparser.py b/Lib/configparser.py index 4344a9e8baca44..60dfa73a9c8bc4 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -692,6 +692,10 @@ def add_section(self, section): if section == self.default_section: raise ValueError('Invalid section name: %r' % section) + if section is UNNAMED_SECTION: + if not self._allow_unnamed_section: + raise ValueError("Unnamed section not enabled") + if section in self._sections: raise DuplicateSectionError(section) self._sections[section] = self._dict() @@ -1203,20 +1207,21 @@ def _convert_to_boolean(self, value): return self.BOOLEAN_STATES[value.lower()] def _validate_value_types(self, *, section="", option="", value=""): - """Raises a TypeError for non-string values. + """Raises a TypeError for incorrect non-string values. - The only legal non-string value if we allow valueless - options is None, so we need to check if the value is a - string if: - - we do not allow valueless options, or - - we allow valueless options but the value is not None + Legal non-string values are UNNAMED_SECTION and valueless values if + they are are allowed. For compatibility reasons this method is not used in classic set() for RawConfigParsers. It is invoked in every case for mapping protocol access and in ConfigParser.set(). """ - if not isinstance(section, str): - raise TypeError("section names must be strings") + if section is UNNAMED_SECTION: + if not self._allow_unnamed_section: + raise ValueError("UNNAMED_SECTION is not allowed") + else: + if not isinstance(section, str): + raise TypeError("section names must be strings or UNNAMED_SECTION") if not isinstance(option, str): raise TypeError("option keys must be strings") if not self._allow_no_value or value: diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index a934e493a76391..6f171c2cc46369 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -2161,6 +2161,11 @@ def test_no_section(self): self.assertEqual('1', cfg2[configparser.UNNAMED_SECTION]['a']) self.assertEqual('2', cfg2[configparser.UNNAMED_SECTION]['b']) + def test_add_section(self): + cfg = configparser.ConfigParser(allow_unnamed_section=True) + cfg.add_section(configparser.UNNAMED_SECTION) + cfg.set(configparser.UNNAMED_SECTION, 'a', '1') + self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a']) class MiscTestCase(unittest.TestCase): def test__all__(self): diff --git a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst new file mode 100644 index 00000000000000..f40017f4ea6b42 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst @@ -0,0 +1 @@ +Add support for the unnamed section in :meth:`RawConfigParser.add_section`. From 29c6e596e75bf710701e7b9e65064bb3e1fee32b Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Fri, 16 Aug 2024 17:52:02 -0300 Subject: [PATCH 02/11] Fix docstring in Lib/configparser.py Co-authored-by: Jason R. Coombs --- Lib/configparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index 60dfa73a9c8bc4..72c61b956b30b9 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -1207,7 +1207,7 @@ def _convert_to_boolean(self, value): return self.BOOLEAN_STATES[value.lower()] def _validate_value_types(self, *, section="", option="", value=""): - """Raises a TypeError for incorrect non-string values. + """Raises a TypeError for illegal values. Legal non-string values are UNNAMED_SECTION and valueless values if they are are allowed. From 0f97db7e2adee88b89696f0be7e85456d723b6f6 Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Fri, 16 Aug 2024 17:52:58 -0300 Subject: [PATCH 03/11] Update Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst Co-authored-by: Jason R. Coombs --- .../next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst index f40017f4ea6b42..3c9e3dd3cb36cb 100644 --- a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst +++ b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst @@ -1 +1 @@ -Add support for the unnamed section in :meth:`RawConfigParser.add_section`. +Add support for the unnamed section in :meth:`configparser.ConfigParser.add_section`. From ddf0ef7f415b170a80e91cd045a015406832c381 Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Sat, 17 Aug 2024 16:48:19 -0300 Subject: [PATCH 04/11] Update Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst index 3c9e3dd3cb36cb..2faf85092a0f8a 100644 --- a/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst +++ b/Misc/NEWS.d/next/Library/2024-08-16-16-53-52.gh-issue-123049.izx_fH.rst @@ -1 +1,2 @@ -Add support for the unnamed section in :meth:`configparser.ConfigParser.add_section`. +Add support for :const:`~configparser.UNNAMED_SECTION` +in :meth:`configparser.ConfigParser.add_section`. From 0d3d4ce33a95419710f75f3f40318970cb3ba639 Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Sat, 17 Aug 2024 16:50:04 -0300 Subject: [PATCH 05/11] Update Lib/configparser.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/configparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index 72c61b956b30b9..44061e4b8511c9 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -1210,7 +1210,7 @@ def _validate_value_types(self, *, section="", option="", value=""): """Raises a TypeError for illegal values. Legal non-string values are UNNAMED_SECTION and valueless values if - they are are allowed. + they are allowed. For compatibility reasons this method is not used in classic set() for RawConfigParsers. It is invoked in every case for mapping protocol From e126ab14d31e4cd548ac19a0520a5403f5beff6f Mon Sep 17 00:00:00 2001 From: Pedro Sousa Lacerda Date: Sun, 18 Aug 2024 11:20:48 -0300 Subject: [PATCH 06/11] New fixes --- Doc/library/configparser.rst | 12 +++++++++--- Lib/configparser.py | 23 +++++++++++++++-------- Lib/test/test_configparser.py | 8 ++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 7aaad932c0104a..f3f79a6a4d5307 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1314,13 +1314,19 @@ RawConfigParser Objects .. method:: add_section(section) - Add a section named *section* to the instance. If a section by the given - name already exists, :exc:`DuplicateSectionError` is raised. If the - *default section* name is passed, :exc:`ValueError` is raised. + Add a section named *section* or :const:`UNNAMED_SECTION` to the instance. + + If the given section already exists, :exc:`DuplicateSectionError` is + raised. If the *default section* name is passed, :exc:`ValueError` is + raised. If :const:`UNNAMED_SECTION` is passed and support is disabled, + :exc:`UnnamedSectionDisabledError` is raised. Type of *section* is not checked which lets users create non-string named sections. This behaviour is unsupported and may cause internal errors. + .. versionchanged:: 3.14 + Added support for :const:`UNNAMED_SECTION`. + .. method:: set(section, option, value) diff --git a/Lib/configparser.py b/Lib/configparser.py index 44061e4b8511c9..75e69d912be126 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -160,7 +160,7 @@ "NoOptionError", "InterpolationError", "InterpolationDepthError", "InterpolationMissingOptionError", "InterpolationSyntaxError", "ParsingError", "MissingSectionHeaderError", - "MultilineContinuationError", + "MultilineContinuationError", "UnnamedSectionDisabledError", "ConfigParser", "RawConfigParser", "Interpolation", "BasicInterpolation", "ExtendedInterpolation", "SectionProxy", "ConverterMapping", @@ -362,6 +362,14 @@ def __init__(self, filename, lineno, line): self.line = line self.args = (filename, lineno, line) + +class UnnamedSectionDisabledError(Error): + """Raised when an attempt to use UNNAMED_SECTION is made with the + feature disabled.""" + def __init__(self): + Error.__init__(self, "Support for UNNAMED_SECTION is disabled.") + + class _UnnamedSection: def __repr__(self): @@ -694,7 +702,7 @@ def add_section(self, section): if section is UNNAMED_SECTION: if not self._allow_unnamed_section: - raise ValueError("Unnamed section not enabled") + raise UnnamedSectionDisabledError() if section in self._sections: raise DuplicateSectionError(section) @@ -1207,9 +1215,9 @@ def _convert_to_boolean(self, value): return self.BOOLEAN_STATES[value.lower()] def _validate_value_types(self, *, section="", option="", value=""): - """Raises a TypeError for illegal values. + """Raises a TypeError for illegal non-string values. - Legal non-string values are UNNAMED_SECTION and valueless values if + Legal non-string values are UNNAMED_SECTION and falsey values if they are allowed. For compatibility reasons this method is not used in classic set() @@ -1218,10 +1226,9 @@ def _validate_value_types(self, *, section="", option="", value=""): """ if section is UNNAMED_SECTION: if not self._allow_unnamed_section: - raise ValueError("UNNAMED_SECTION is not allowed") - else: - if not isinstance(section, str): - raise TypeError("section names must be strings or UNNAMED_SECTION") + raise UnnamedSectionDisabledError() + elif not isinstance(section, str): + raise TypeError("section names must be strings or UNNAMED_SECTION") if not isinstance(option, str): raise TypeError("option keys must be strings") if not self._allow_no_value or value: diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 6f171c2cc46369..e3c5d08dd1e7d1 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -2167,6 +2167,14 @@ def test_add_section(self): cfg.set(configparser.UNNAMED_SECTION, 'a', '1') self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a']) + def test_disabled_error(self): + with self.assertRaises(configparser.MissingSectionHeaderError): + configparser.ConfigParser().read_string("a = 1") + + with self.assertRaises(configparser.UnnamedSectionDisabledError): + configparser.ConfigParser().add_section(configparser.UNNAMED_SECTION) + + class MiscTestCase(unittest.TestCase): def test__all__(self): support.check__all__(self, configparser, not_exported={"Error"}) From 7c20762e252bbb76e147ba2355fa1af2d4dce5a4 Mon Sep 17 00:00:00 2001 From: Pedro Sousa Lacerda Date: Sun, 18 Aug 2024 11:28:04 -0300 Subject: [PATCH 07/11] Update docs --- Doc/library/configparser.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index f3f79a6a4d5307..2a8f3b5def968f 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1409,8 +1409,7 @@ Exceptions .. exception:: MissingSectionHeaderError Exception raised when attempting to parse a file which has no section - headers. - + headers.. .. exception:: ParsingError @@ -1427,6 +1426,13 @@ Exceptions .. versionadded:: 3.13 +.. exception:: UnnamedSectionDisabledError + + Exception raised when attempting to use the unnamed section without enabling + it. + + .. versionadded:: 3.14 + .. rubric:: Footnotes .. [1] Config parsers allow for heavy customization. If you are interested in From e352270770503bbcc15832cbbd3e8911520f4f28 Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Sun, 18 Aug 2024 11:30:20 -0300 Subject: [PATCH 08/11] Update Doc/library/configparser.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/configparser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 2a8f3b5def968f..06e9e510d65968 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1325,7 +1325,7 @@ RawConfigParser Objects sections. This behaviour is unsupported and may cause internal errors. .. versionchanged:: 3.14 - Added support for :const:`UNNAMED_SECTION`. + Added support for :const:`UNNAMED_SECTION`. .. method:: set(section, option, value) From 918c7d082416f399cf02ff6b0b809ead271c3ca1 Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Sun, 18 Aug 2024 11:59:38 -0300 Subject: [PATCH 09/11] Update Doc/library/configparser.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/configparser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 06e9e510d65968..4c9b023405357e 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1409,7 +1409,7 @@ Exceptions .. exception:: MissingSectionHeaderError Exception raised when attempting to parse a file which has no section - headers.. + headers. .. exception:: ParsingError From 444b557b6b8e54a2892adc0376701d70f82f1f57 Mon Sep 17 00:00:00 2001 From: Pedro Sousa Lacerda Date: Sun, 18 Aug 2024 12:00:48 -0300 Subject: [PATCH 10/11] Ommit parenthesis --- Lib/configparser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index 75e69d912be126..420dce77c234e1 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -702,7 +702,7 @@ def add_section(self, section): if section is UNNAMED_SECTION: if not self._allow_unnamed_section: - raise UnnamedSectionDisabledError() + raise UnnamedSectionDisabledError if section in self._sections: raise DuplicateSectionError(section) @@ -1226,7 +1226,7 @@ def _validate_value_types(self, *, section="", option="", value=""): """ if section is UNNAMED_SECTION: if not self._allow_unnamed_section: - raise UnnamedSectionDisabledError() + raise UnnamedSectionDisabledError elif not isinstance(section, str): raise TypeError("section names must be strings or UNNAMED_SECTION") if not isinstance(option, str): From e35ca616eb3fb0ad7e53eab1b101d2ae20af2f7d Mon Sep 17 00:00:00 2001 From: Pedro Lacerda Date: Sun, 18 Aug 2024 13:01:03 -0300 Subject: [PATCH 11/11] Update Doc/library/configparser.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/configparser.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 4c9b023405357e..587fe50fd51164 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1428,8 +1428,8 @@ Exceptions .. exception:: UnnamedSectionDisabledError - Exception raised when attempting to use the unnamed section without enabling - it. + Exception raised when attempting to use the + :const:`UNNAMED_SECTION` without enabling it. .. versionadded:: 3.14