From ec49bca2e65950b1ee67b8b98e96c0c40c2f521f Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 13:42:13 +0530 Subject: [PATCH 01/22] gh-107625: Raise ParsingError if a key contains empty value - raise ParsingError instaed of AttributeError if a key contains empty value in a non recommended scenario where extra space and blankline is present within the section --- Doc/library/configparser.rst | 26 ++++++++++++++++++++++++++ Lib/configparser.py | 7 +++++-- Lib/test/test_configparser.py | 16 ++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index a7f75fd6e84f4c..ad25c7cc3686d8 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1036,6 +1036,12 @@ ConfigParser Objects files using :meth:`read_file` before calling :meth:`read` for any optional files:: + Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` + when the configuration contains a key without a corresponding value. + This change is intended to handle scenarios where a key lacks a value + in a configuration. Please note that it's not recommended to have extra + spaces or blank lines within sections of the configuration. + import configparser, os config = configparser.ConfigParser() @@ -1053,6 +1059,12 @@ ConfigParser Objects .. versionadded:: 3.7 The *filenames* parameter accepts a :class:`bytes` object. + .. versionchanged:: 3.13 + Parsing errors will result in a ParsingError being raised instead + of an AttributeError when encountering a key without a corresponding + value. This change is designed to handle situations where a key is + present without a value, particularly in scenarios not recommended, + such as having extra spaces or blank lines within sections. .. method:: read_file(f, source=None) @@ -1063,9 +1075,23 @@ ConfigParser Objects not given and *f* has a :attr:`name` attribute, that is used for *source*; the default is ``''``. + Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` + when the configuration contains a key without a corresponding value. + This change is intended to handle scenarios where a key lacks a value + in a configuration. Please note that it's not recommended to have extra + spaces or blank lines within sections of the configuration. + .. versionadded:: 3.2 Replaces :meth:`readfp`. + .. versionchanged:: 3.13 + Parsing errors will result in a ParsingError being raised instead + of an AttributeError when encountering a key without a corresponding + value. This change is designed to handle situations where a key is + present without a value, particularly in scenarios not recommended, + such as having extra spaces or blank lines within sections. + + .. method:: read_string(string, source='') Parse configuration data from a string. diff --git a/Lib/configparser.py b/Lib/configparser.py index 71362d23ec3757..0539c7393696b2 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -986,8 +986,11 @@ def _read(self, fp, fpname): first_nonspace = self.NONSPACECRE.search(line) cur_indent_level = first_nonspace.start() if first_nonspace else 0 if (cursect is not None and optname and - cur_indent_level > indent_level): - cursect[optname].append(value) + cur_indent_level > indent_level): + if cursect[optname]: + cursect[optname].append(value) + else: + raise ParsingError(f"No-value option {optname} cannot be continued") # a section header or option header? else: indent_level = cur_indent_level diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 53163d7528b64a..4f71b6d11eb4c6 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1555,6 +1555,22 @@ def test_source_as_bytes(self): "'[badbad'" ) + def test_gh_107625(self): + #test key without value with extra whitespace within sections + lines = [ + '[SECT]\n', + 'KEY1\n', + ' KEY2 = VAL2\n', # note the Space before the key! + ] + with self.assertRaises(configparser.ParsingError): + parser = configparser.ConfigParser( + comment_prefixes ="", + allow_no_value =True, + strict =False, + delimiters =( '=', ), + interpolation =None, + ) + class CoverageOneHundredTestCase(unittest.TestCase): """Covers edge cases in the codebase.""" From 1bcab3f2a7ade55e31e8fb05d493885b4d67c905 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 13:58:50 +0530 Subject: [PATCH 02/22] Fix doc --- Doc/library/configparser.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index ad25c7cc3686d8..2ae6fc272d5cf1 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1059,12 +1059,12 @@ ConfigParser Objects .. versionadded:: 3.7 The *filenames* parameter accepts a :class:`bytes` object. - .. versionchanged:: 3.13 - Parsing errors will result in a ParsingError being raised instead - of an AttributeError when encountering a key without a corresponding - value. This change is designed to handle situations where a key is - present without a value, particularly in scenarios not recommended, - such as having extra spaces or blank lines within sections. + .. versionchanged:: 3.13 + Parsing errors will result in a ParsingError being raised instead + of an AttributeError when encountering a key without a corresponding + value. This change is designed to handle situations where a key is + present without a value, particularly in scenarios not recommended, + such as having extra spaces or blank lines within sections. .. method:: read_file(f, source=None) @@ -1084,12 +1084,12 @@ ConfigParser Objects .. versionadded:: 3.2 Replaces :meth:`readfp`. - .. versionchanged:: 3.13 - Parsing errors will result in a ParsingError being raised instead - of an AttributeError when encountering a key without a corresponding - value. This change is designed to handle situations where a key is - present without a value, particularly in scenarios not recommended, - such as having extra spaces or blank lines within sections. + .. versionchanged:: 3.13 + Parsing errors will result in a ParsingError being raised instead + of an AttributeError when encountering a key without a corresponding + value. This change is designed to handle situations where a key is + present without a value, particularly in scenarios not recommended, + such as having extra spaces or blank lines within sections. .. method:: read_string(string, source='') From 35fe7f153dd2948906334f0e4658ad664fbf0719 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 14:07:10 +0530 Subject: [PATCH 03/22] Fix doc --- 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 2ae6fc272d5cf1..bc0d5ca57990c4 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1034,7 +1034,7 @@ ConfigParser Objects instance will contain an empty dataset. An application which requires initial values to be loaded from a file should load the required file or files using :meth:`read_file` before calling :meth:`read` for any - optional files:: + optional files Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` when the configuration contains a key without a corresponding value. From 0660a7e85dde127c52e774b29673dbc804004f7a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 5 Aug 2023 08:42:01 +0000 Subject: [PATCH 04/22] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst diff --git a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst new file mode 100644 index 00000000000000..b38069408f9d51 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst @@ -0,0 +1 @@ +Raise an :exc:`ParsingError` instead of an :exc:`AttributeError` when the configuration contains a key without a corresponding value in a scenario where extra space or a new line is present within the section. From 317681c2e067befe9078adea79b802f6e8db82a1 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 14:53:31 +0530 Subject: [PATCH 05/22] Fix test --- Doc/library/configparser.rst | 1 + Lib/test/test_configparser.py | 1 + 2 files changed, 2 insertions(+) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index bc0d5ca57990c4..aad19f0f7db0ea 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1066,6 +1066,7 @@ ConfigParser Objects present without a value, particularly in scenarios not recommended, such as having extra spaces or blank lines within sections. + .. method:: read_file(f, source=None) Read and parse configuration data from *f* which must be an iterable diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 4f71b6d11eb4c6..491b5535c8baad 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1570,6 +1570,7 @@ def test_gh_107625(self): delimiters =( '=', ), interpolation =None, ) + parser.read_file(lines) class CoverageOneHundredTestCase(unittest.TestCase): From ff8f339a9d79c7b438eca417323bed7cf46e4d8c Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 17:27:13 +0530 Subject: [PATCH 06/22] Fix doc --- Doc/library/configparser.rst | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index aad19f0f7db0ea..0d357b79a02591 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1034,13 +1034,14 @@ ConfigParser Objects instance will contain an empty dataset. An application which requires initial values to be loaded from a file should load the required file or files using :meth:`read_file` before calling :meth:`read` for any - optional files + optional files:: - Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` + Raise :exc:`ParsingError` instead of :exc:`AttributeError` when the configuration contains a key without a corresponding value. This change is intended to handle scenarios where a key lacks a value - in a configuration. Please note that it's not recommended to have extra - spaces or blank lines within sections of the configuration. + in a configuration which contains extra space or newline within a section. + Please note that it's not recommended to have extra spaces + or blank lines within sections of the configuration. import configparser, os @@ -1059,13 +1060,6 @@ ConfigParser Objects .. versionadded:: 3.7 The *filenames* parameter accepts a :class:`bytes` object. - .. versionchanged:: 3.13 - Parsing errors will result in a ParsingError being raised instead - of an AttributeError when encountering a key without a corresponding - value. This change is designed to handle situations where a key is - present without a value, particularly in scenarios not recommended, - such as having extra spaces or blank lines within sections. - .. method:: read_file(f, source=None) @@ -1076,22 +1070,16 @@ ConfigParser Objects not given and *f* has a :attr:`name` attribute, that is used for *source*; the default is ``''``. - Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` + Raise :exc:`ParsingError` instead of :exc:`AttributeError` when the configuration contains a key without a corresponding value. This change is intended to handle scenarios where a key lacks a value - in a configuration. Please note that it's not recommended to have extra - spaces or blank lines within sections of the configuration. + in a configuration which contains extra space or newline within a section. + Please note that it's not recommended to have extra spaces + or blank lines within sections of the configuration. .. versionadded:: 3.2 Replaces :meth:`readfp`. - .. versionchanged:: 3.13 - Parsing errors will result in a ParsingError being raised instead - of an AttributeError when encountering a key without a corresponding - value. This change is designed to handle situations where a key is - present without a value, particularly in scenarios not recommended, - such as having extra spaces or blank lines within sections. - .. method:: read_string(string, source='') From 778841d3572d96a09f8f68e55ee10a7873376f3c Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 19:29:19 +0530 Subject: [PATCH 07/22] Fix doc --- Doc/library/configparser.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 0d357b79a02591..35ef748837e1ff 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1030,18 +1030,18 @@ ConfigParser Objects directory), and all existing configuration files in the iterable will be read. - If none of the named files exist, the :class:`ConfigParser` - instance will contain an empty dataset. An application which requires - initial values to be loaded from a file should load the required file or - files using :meth:`read_file` before calling :meth:`read` for any - optional files:: - Raise :exc:`ParsingError` instead of :exc:`AttributeError` when the configuration contains a key without a corresponding value. This change is intended to handle scenarios where a key lacks a value in a configuration which contains extra space or newline within a section. Please note that it's not recommended to have extra spaces or blank lines within sections of the configuration. + + If none of the named files exist, the :class:`ConfigParser` + instance will contain an empty dataset. An application which requires + initial values to be loaded from a file should load the required file or + files using :meth:`read_file` before calling :meth:`read` for any + optional files:: import configparser, os From ed50361618042378f3e49dd37253611540154090 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 19:34:06 +0530 Subject: [PATCH 08/22] Fix Doc --- 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 35ef748837e1ff..424252a7998d7a 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1036,7 +1036,7 @@ ConfigParser Objects in a configuration which contains extra space or newline within a section. Please note that it's not recommended to have extra spaces or blank lines within sections of the configuration. - + If none of the named files exist, the :class:`ConfigParser` instance will contain an empty dataset. An application which requires initial values to be loaded from a file should load the required file or From dc1faeb7323834425c33a805eca8b877cc966e37 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 22:28:27 +0530 Subject: [PATCH 09/22] Fix whitespace issues --- Lib/configparser.py | 8 ++++---- Lib/test/test_configparser.py | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index 0539c7393696b2..e5871c07d81805 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -987,10 +987,10 @@ def _read(self, fp, fpname): 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]: - cursect[optname].append(value) - else: - raise ParsingError(f"No-value option {optname} cannot be continued") + if cursect[optname]: + cursect[optname].append(value) + else: + raise ParsingError(f"No-value option {optname} cannot be continued") # a section header or option header? else: indent_level = cur_indent_level diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 491b5535c8baad..d028e40ea9fc2a 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1556,21 +1556,21 @@ def test_source_as_bytes(self): ) def test_gh_107625(self): - #test key without value with extra whitespace within sections - lines = [ - '[SECT]\n', - 'KEY1\n', - ' KEY2 = VAL2\n', # note the Space before the key! - ] - with self.assertRaises(configparser.ParsingError): - parser = configparser.ConfigParser( - comment_prefixes ="", - allow_no_value =True, - strict =False, - delimiters =( '=', ), - interpolation =None, - ) - parser.read_file(lines) + #test key without value with extra whitespace within sections + lines = [ + '[SECT]\n', + 'KEY1\n', + ' KEY2 = VAL2\n', # note the Space before the key! + ] + with self.assertRaises(configparser.ParsingError): + parser = configparser.ConfigParser( + comment_prefixes ="", + allow_no_value =True, + strict =False, + delimiters =( '=', ), + interpolation =None, + ) + parser.read_file(lines) class CoverageOneHundredTestCase(unittest.TestCase): From 1234b75188d46e81f671b371569627bb4cdea19f Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 23:20:35 +0530 Subject: [PATCH 10/22] Update Lib/configparser.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- Lib/configparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index e5871c07d81805..45ec6828a44e97 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -986,7 +986,7 @@ def _read(self, fp, fpname): first_nonspace = self.NONSPACECRE.search(line) cur_indent_level = first_nonspace.start() if first_nonspace else 0 if (cursect is not None and optname and - cur_indent_level > indent_level): + cur_indent_level > indent_level): if cursect[optname]: cursect[optname].append(value) else: From 726264d77ca4382c5222dd72aa78d8070bd56ee5 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 23:20:46 +0530 Subject: [PATCH 11/22] Update Lib/test/test_configparser.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- Lib/test/test_configparser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index d028e40ea9fc2a..4c815c7b314f14 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1555,8 +1555,7 @@ def test_source_as_bytes(self): "'[badbad'" ) - def test_gh_107625(self): - #test key without value with extra whitespace within sections + def test_keys_without_value_with_extra_whitespace(self): lines = [ '[SECT]\n', 'KEY1\n', From 7ae72b6902b72af620414f413b8f86cb8bfa3823 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 23:20:57 +0530 Subject: [PATCH 12/22] Update Lib/test/test_configparser.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- Lib/test/test_configparser.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 4c815c7b314f14..bb59d1377d621f 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1560,15 +1560,15 @@ def test_keys_without_value_with_extra_whitespace(self): '[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.ParsingError): - parser = configparser.ConfigParser( - comment_prefixes ="", - allow_no_value =True, - strict =False, - delimiters =( '=', ), - interpolation =None, - ) parser.read_file(lines) From da065f84a54ee72510f7c8bec80257b31d458320 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 23:36:41 +0530 Subject: [PATCH 13/22] Resolve comments --- Doc/library/configparser.rst | 12 +++++------- .../2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst | 5 ++++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 424252a7998d7a..00385e38b8fe55 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -956,6 +956,11 @@ ConfigParser Objects converter gets its own corresponding :meth:`get*()` method on the parser object and section proxies. + Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` for + :meth:`read` and :meth:`read_file` if the configuration contains + a key without a corresponding value in scenarios where configuration + contains extra space or newline within a section. + .. versionchanged:: 3.1 The default *dict_type* is :class:`collections.OrderedDict`. @@ -1030,13 +1035,6 @@ ConfigParser Objects directory), and all existing configuration files in the iterable will be read. - Raise :exc:`ParsingError` instead of :exc:`AttributeError` - when the configuration contains a key without a corresponding value. - This change is intended to handle scenarios where a key lacks a value - in a configuration which contains extra space or newline within a section. - Please note that it's not recommended to have extra spaces - or blank lines within sections of the configuration. - If none of the named files exist, the :class:`ConfigParser` instance will contain an empty dataset. An application which requires initial values to be loaded from a file should load the required file or diff --git a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst index b38069408f9d51..00f919da1e7675 100644 --- a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst +++ b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst @@ -1 +1,4 @@ -Raise an :exc:`ParsingError` instead of an :exc:`AttributeError` when the configuration contains a key without a corresponding value in a scenario where extra space or a new line is present within the section. +Emit :exc:`ParsingError` from :meth:`read` and :meth:`read_file` +of :class:`ConfigParser` if configuration contains a key +without a corresponding value in a scenario where extra space +or a new line is present within the section. From ee11915c45f8ed2c84c2232cd086e69d3a5e38e8 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sat, 5 Aug 2023 23:43:19 +0530 Subject: [PATCH 14/22] Fix doc --- Doc/library/configparser.rst | 2 +- .../next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 00385e38b8fe55..074c28e7f70136 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -959,7 +959,7 @@ ConfigParser Objects Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` for :meth:`read` and :meth:`read_file` if the configuration contains a key without a corresponding value in scenarios where configuration - contains extra space or newline within a section. + contains extra space within a section. .. versionchanged:: 3.1 The default *dict_type* is :class:`collections.OrderedDict`. diff --git a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst index 00f919da1e7675..25081f5df5f018 100644 --- a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst +++ b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst @@ -1,4 +1,4 @@ Emit :exc:`ParsingError` from :meth:`read` and :meth:`read_file` of :class:`ConfigParser` if configuration contains a key without a corresponding value in a scenario where extra space -or a new line is present within the section. +is present within the section. From 0b87a9f3daec99293d301a09380c724769ffefcb Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sun, 6 Aug 2023 00:11:26 +0530 Subject: [PATCH 15/22] Add versionchnaged section inside documentation --- Doc/library/configparser.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 074c28e7f70136..46194377d3d1e5 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -981,6 +981,10 @@ ConfigParser Objects The default *dict_type* is :class:`dict`, since it now preserves insertion order. + .. versionchanged:: 3.13 + Raise a :exc:`ParsingError` if a key is present with a value + in a scenario where an extra space is present within a section. + .. method:: defaults() Return a dictionary containing the instance-wide defaults. From 8c4907fc103a03348fe8ec60ebaa529b25742037 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sun, 6 Aug 2023 00:21:36 +0530 Subject: [PATCH 16/22] Update Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- .../Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst index 25081f5df5f018..3994f6ce2e6fec 100644 --- a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst +++ b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst @@ -1,4 +1,5 @@ -Emit :exc:`ParsingError` from :meth:`read` and :meth:`read_file` -of :class:`ConfigParser` if configuration contains a key +Emit :exc:`configparser.ParsingError` from :meth:`~configparser.ConfigParser.read` +and :meth:`~configparser.ConfigParser.read_file` methods of +:class:`configparser.ConfigParser` if configuration contains a key without a corresponding value in a scenario where extra space is present within the section. From 2b06e6874f4a7f1aa043d1c64d2bd08fc9d64498 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sun, 6 Aug 2023 08:37:19 +0530 Subject: [PATCH 17/22] Fix doc --- 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 46194377d3d1e5..8d5c761ac02e96 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -982,8 +982,8 @@ ConfigParser Objects insertion order. .. versionchanged:: 3.13 - Raise a :exc:`ParsingError` if a key is present with a value - in a scenario where an extra space is present within a section. + Raise a :exc:`ParsingError` if a key is present without a corresponding + value in a scenario where an extra space is present within a section. .. method:: defaults() From e58b11f5b626829afacd221a5f6924c5a6972ef1 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Sun, 6 Aug 2023 09:05:06 +0530 Subject: [PATCH 18/22] Fix doc --- Doc/library/configparser.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index 8d5c761ac02e96..da984f4c88ff7a 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -1072,13 +1072,6 @@ ConfigParser Objects not given and *f* has a :attr:`name` attribute, that is used for *source*; the default is ``''``. - Raise :exc:`ParsingError` instead of :exc:`AttributeError` - when the configuration contains a key without a corresponding value. - This change is intended to handle scenarios where a key lacks a value - in a configuration which contains extra space or newline within a section. - Please note that it's not recommended to have extra spaces - or blank lines within sections of the configuration. - .. versionadded:: 3.2 Replaces :meth:`readfp`. From ca4839d38cc5c09df396f70e73ff0cc5c96f3e96 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Fri, 11 Aug 2023 09:25:02 +0530 Subject: [PATCH 19/22] Raise MultilineContinuationError instead of ParsingError --- Doc/library/configparser.rst | 9 +++++++-- Lib/configparser.py | 21 +++++++++++++++++---- Lib/test/test_configparser.py | 10 +++++++++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index da984f4c88ff7a..d720def74cddd7 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -956,7 +956,7 @@ ConfigParser Objects converter gets its own corresponding :meth:`get*()` method on the parser object and section proxies. - Raise a :exc:`ParsingError` instead of an :exc:`AttributeError` for + Raise a :exc:`MultilineContinuationError` instead of an :exc:`AttributeError` for :meth:`read` and :meth:`read_file` if the configuration contains a key without a corresponding value in scenarios where configuration contains extra space within a section. @@ -1075,7 +1075,6 @@ ConfigParser Objects .. versionadded:: 3.2 Replaces :meth:`readfp`. - .. method:: read_string(string, source='') Parse configuration data from a string. @@ -1353,6 +1352,12 @@ Exceptions Exception raised when errors occur attempting to parse a file. +.. exception:: MultilineContinuationError + + Exception raised if the configuration contains a key without + a corresponding value in scenarios where configuration + contains extra space within a section. + .. versionchanged:: 3.12 The ``filename`` attribute and :meth:`__init__` constructor argument were removed. They have been available using the name ``source`` since 3.2. diff --git a/Lib/configparser.py b/Lib/configparser.py index 45ec6828a44e97..fc845296e1ae95 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -151,7 +151,7 @@ __all__ = ("NoSectionError", "DuplicateOptionError", "DuplicateSectionError", "NoOptionError", "InterpolationError", "InterpolationDepthError", "InterpolationMissingOptionError", "InterpolationSyntaxError", - "ParsingError", "MissingSectionHeaderError", + "ParsingError", "MissingSectionHeaderError","MultilineContinuationError", "ConfigParser", "RawConfigParser", "Interpolation", "BasicInterpolation", "ExtendedInterpolation", "SectionProxy", "ConverterMapping", @@ -322,6 +322,19 @@ def __init__(self, filename, lineno, line): self.args = (filename, lineno, line) +class MultilineContinuationError(ParsingError): + """Raised when a key is present without value if any extra space is present within section""" + def __init__(self, filename, lineno, line): + Error.__init__( + self, + "The file contains a key without value in the" + " unintended scenario, please don't add any extra space within the section..\nfile: %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,10 +1000,10 @@ def _read(self, fp, fpname): 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]: - cursect[optname].append(value) + if not cursect[optname]: + raise MultilineContinuationError(fpname,lineno,line) else: - raise ParsingError(f"No-value option {optname} cannot be continued") + cursect[optname].append(value) # a section header or option header? else: indent_level = cur_indent_level diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index bb59d1377d621f..364e646bd88138 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1568,8 +1568,16 @@ def test_keys_without_value_with_extra_whitespace(self): delimiters=('=',), interpolation=None, ) - with self.assertRaises(configparser.ParsingError): + with self.assertRaises(configparser.MultilineContinuationError) as dse: parser.read_file(lines) + self.assertEqual( + str(dse.exception), + "The file contains a key without value in the" + " unintended scenario, please don't add any extra space within the section..\nfile: '', line: 3\n" + "' KEY2 = VAL2\\n'" + ) + + class CoverageOneHundredTestCase(unittest.TestCase): From 2d367f1470becad9e7e6269264f3ca292c0b10dc Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 4 Mar 2024 15:35:34 +0100 Subject: [PATCH 20/22] Simplify the docs & error messages --- Doc/library/configparser.rst | 16 ++++++---------- Lib/configparser.py | 11 ++++++----- Lib/test/test_configparser.py | 4 ++-- ...023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst | 7 +++---- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst index e7cd9b1bf29edb..445626c267fb6f 100644 --- a/Doc/library/configparser.rst +++ b/Doc/library/configparser.rst @@ -958,11 +958,6 @@ ConfigParser Objects converter gets its own corresponding :meth:`!get*()` method on the parser object and section proxies. - Raise a :exc:`MultilineContinuationError` instead of an :exc:`AttributeError` for - :meth:`read` and :meth:`read_file` if the configuration contains - a key without a corresponding value in scenarios where configuration - contains extra space within a section. - .. versionchanged:: 3.1 The default *dict_type* is :class:`collections.OrderedDict`. @@ -984,8 +979,8 @@ ConfigParser Objects insertion order. .. versionchanged:: 3.13 - Raise a :exc:`ParsingError` if a key is present without a corresponding - value in a scenario where an extra space is present within a section. + Raise a :exc:`MultilineContinuationError` when *allow_no_value* is + ``True``, and a key without a value is continued with an indented line. .. method:: defaults() @@ -1360,9 +1355,10 @@ Exceptions .. exception:: MultilineContinuationError - Exception raised if the configuration contains a key without - a corresponding value in scenarios where configuration - contains extra space within a section. + Exception raised when a key without a corresponding value is continued with + an indented line. + + .. versionadded:: 3.13 .. rubric:: Footnotes diff --git a/Lib/configparser.py b/Lib/configparser.py index fc845296e1ae95..c08e0f234de2b1 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -151,7 +151,8 @@ __all__ = ("NoSectionError", "DuplicateOptionError", "DuplicateSectionError", "NoOptionError", "InterpolationError", "InterpolationDepthError", "InterpolationMissingOptionError", "InterpolationSyntaxError", - "ParsingError", "MissingSectionHeaderError","MultilineContinuationError", + "ParsingError", "MissingSectionHeaderError", + "MultilineContinuationError", "ConfigParser", "RawConfigParser", "Interpolation", "BasicInterpolation", "ExtendedInterpolation", "SectionProxy", "ConverterMapping", @@ -323,12 +324,12 @@ def __init__(self, filename, lineno, line): class MultilineContinuationError(ParsingError): - """Raised when a key is present without value if any extra space is present within section""" + """Raised when a key without value is followed by continuation line""" def __init__(self, filename, lineno, line): Error.__init__( self, - "The file contains a key without value in the" - " unintended scenario, please don't add any extra space within the section..\nfile: %r, line: %d\n%r" + "Key without value continued with an indented line.\n" + "file: %r, line: %d\n%r" %(filename, lineno, line)) self.source = filename self.lineno = lineno @@ -1001,7 +1002,7 @@ def _read(self, fp, fpname): if (cursect is not None and optname and cur_indent_level > indent_level): if not cursect[optname]: - raise MultilineContinuationError(fpname,lineno,line) + raise MultilineContinuationError(fpname, lineno, line) else: cursect[optname].append(value) # a section header or option header? diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 513cf5013e7d9d..5d58e34740adaf 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -1572,8 +1572,8 @@ def test_keys_without_value_with_extra_whitespace(self): parser.read_file(lines) self.assertEqual( str(dse.exception), - "The file contains a key without value in the" - " unintended scenario, please don't add any extra space within the section..\nfile: '', line: 3\n" + "Key without value continued with an indented line.\n" + "file: '', line: 3\n" "' KEY2 = VAL2\\n'" ) diff --git a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst index 3994f6ce2e6fec..bf779c454e6388 100644 --- a/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst +++ b/Misc/NEWS.d/next/Library/2023-08-05-08-41-58.gh-issue-107625.cVSHCT.rst @@ -1,5 +1,4 @@ -Emit :exc:`configparser.ParsingError` from :meth:`~configparser.ConfigParser.read` +Raise :exc:`configparser.ParsingError` from :meth:`~configparser.ConfigParser.read` and :meth:`~configparser.ConfigParser.read_file` methods of -:class:`configparser.ConfigParser` if configuration contains a key -without a corresponding value in a scenario where extra space -is present within the section. +:class:`configparser.ConfigParser` if a key without a corresponding value +is continued (that is, followed by an indented line). From 9dc65ed3db21ac220c4314c7bc1ab5ecfa63c7be Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Tue, 5 Mar 2024 14:03:00 +0530 Subject: [PATCH 21/22] Update Lib/configparser.py Co-authored-by: Jason R. Coombs --- Lib/configparser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index c08e0f234de2b1..310dd00ebc5cea 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -1003,8 +1003,7 @@ def _read(self, fp, fpname): cur_indent_level > indent_level): if not cursect[optname]: raise MultilineContinuationError(fpname, lineno, line) - else: - cursect[optname].append(value) + cursect[optname].append(value) # a section header or option header? else: indent_level = cur_indent_level From 030372888ed479d8073dbdf4aecbd397e187dbdc Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 6 Mar 2024 14:39:01 +0100 Subject: [PATCH 22/22] Test with `is None` rather than `not` --- Lib/configparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/configparser.py b/Lib/configparser.py index 310dd00ebc5cea..241f10aee93ec4 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -1001,7 +1001,7 @@ def _read(self, fp, fpname): 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 not cursect[optname]: + if cursect[optname] is None: raise MultilineContinuationError(fpname, lineno, line) cursect[optname].append(value) # a section header or option header?