10000 gh-123049: configparser: Allow to create the unnamed section from scr… · python/cpython@be257c5 · GitHub
[go: up one dir, main page]

Skip to content

Commit be257c5

Browse files
pslacerdajaracopicnixz
authored
gh-123049: configparser: Allow to create the unnamed section from scratch. (#123077)
--------- Co-authored-by: Jason R. Coombs <jaraco@jaraco.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent c15bfa9 commit be257c5

File tree

4 files changed

+52
-13
lines changed

4 files changed

+52
-13
lines changed

Doc/library/configparser.rst

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,13 +1314,19 @@ RawConfigParser Objects
13141314

13151315
.. method:: add_section(section)
13161316

1317-
Add a section named *section* to the instance. If a section by the given
1318-
name already exists, :exc:`DuplicateSectionError` is raised. If the
1319-
*default section* name is passed, :exc:`ValueError` is raised.
1317+
Add a section named *section* or :const:`UNNAMED_SECTION` to the instance.
1318+
1319+
If the given section already exists, :exc:`DuplicateSectionError` is
1320+
raised. If the *default section* name is passed, :exc:`ValueError` is
1321+
raised. If :const:`UNNAMED_SECTION` is passed and support is disabled,
1322+
:exc:`UnnamedSectionDisabledError` is raised.
13201323

13211324
Type of *section* is not checked which lets users create non-string named
13221325
sections. This behaviour is unsupported and may cause internal errors.
13231326

1327+
.. versionchanged:: 3.14
1328+
Added support for :const:`UNNAMED_SECTION`.
1329+
13241330

13251331
.. method:: set(section, option, value)
13261332

@@ -1405,7 +1411,6 @@ Exceptions
14051411
Exception raised when attempting to parse a file which has no section
14061412
headers.
14071413

1408-
14091414
.. exception:: ParsingError
14101415

14111416
Exception raised when errors occur attempting to parse a file.
@@ -1421,6 +1426,13 @@ Exceptions
14211426

14221427
.. versionadded:: 3.13
14231428

1429+
.. exception:: UnnamedSectionDisabledError
1430+
1431+
Exception raised when attempting to use the
1432+
:const:`UNNAMED_SECTION` without enabling it.
1433+
1434+
.. versionadded:: 3.14
1435+
14241436
.. rubric:: Footnotes
14251437

14261438
.. [1] Config parsers allow for heavy customization. If you are interested in

Lib/configparser.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
"NoOptionError", "InterpolationError", "InterpolationDepthError",
161161
"InterpolationMissingOptionError", "InterpolationSyntaxError",
162162
"ParsingError", "MissingSectionHeaderError",
163-
"MultilineContinuationError",
163+
"MultilineContinuationError", "UnnamedSectionDisabledError",
164164
"ConfigParser", "RawConfigParser",
165165
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
166166
"SectionProxy", "ConverterMapping",
@@ -362,6 +362,14 @@ def __init__(self, filename, lineno, line):
362362
self.line = line
363363
self.args = (filename, lineno, line)
364364

365+
366+
class UnnamedSectionDisabledError(Error):
367+
"""Raised when an attempt to use UNNAMED_SECTION is made with the
368+
feature disabled."""
369+
def __init__(self):
370+
Error.__init__(self, "Support for UNNAMED_SECTION is disabled.")
371+
372+
365373
class _UnnamedSection:
366374

367375
def __repr__(self):
@@ -692,6 +700,10 @@ def add_section(self, section):
692700
if section == self.default_section:
693701
raise ValueError('Invalid section name: %r' % section)
694702

703+
if section is UNNAMED_SECTION:
704+
if not self._allow_unnamed_section:
705+
raise UnnamedSectionDisabledError
706+
695707
if section in self._sections:
696708
raise DuplicateSectionError(section)
697709
self._sections[section] = self._dict()
@@ -1203,20 +1215,20 @@ def _convert_to_boolean(self, value):
12031215
return self.BOOLEAN_STATES[value.lower()]
12041216

12051217
def _validate_value_types(self, *, section="", option="", value=""):
1206-
"""Raises a TypeError for non-string values.
1218+
"""Raises a TypeError for illegal non-string values.
12071219
1208-
The only legal non-string value if we allow valueless
1209-
options is None, so we need to check if the value is a
1210-
string if:
1211-
- we do not allow valueless options, or
1212-
- we allow valueless options but the value is not None
1220+
Legal non-string values are UNNAMED_SECTION and falsey values if
1221+
they are allowed.
12131222
12141223
For compatibility reasons this method is not used in classic set()
12151224
for RawConfigParsers. It is invoked in every case for mapping protocol
12161225
access and in ConfigParser.set().
12171226
"""
1218-
if not isinstance(section, str):
1219-
raise TypeError("section names must be strings")
1227+
if section is UNNAMED_SECTION:
1228+
if not self._allow_unnamed_section:
1229+
raise UnnamedSectionDisabledError
1230+
elif not isinstance(section, str):
1231+
raise TypeError("section names must be strings or UNNAMED_SECTION")
12201232
if not isinstance(option, str):
12211233
raise TypeError("option keys must be strings")
12221234
if not self._allow_no_value or value:

Lib/test/test_configparser.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,19 @@ def test_no_section(self):
21612161
self.assertEqual('1', cfg2[configparser.UNNAMED_SECTION]['a'])
21622162
self.assertEqual('2', cfg2[configparser.UNNAMED_SECTION]['b'])
21632163

2164+
def test_add_section(self):
2165+
cfg = configparser.ConfigParser(allow_unnamed_section=True)
2166+
cfg.add_section(configparser.UNNAMED_SECTION)
2167+
cfg.set(configparser.UNNAMED_SECTION, 'a', '1')
2168+
self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a'])
2169+
2170+
def test_disabled_error(self):
2171+
with self.assertRaises(configparser.MissingSectionHeaderError):
2172+
configparser.ConfigParser().read_string("a = 1")
2173+
2174+
with self.assertRaises(configparser.UnnamedSectionDisabledError):
2175+
configparser.ConfigParser().add_section(configparser.UNNAMED_SECTION)
2176+
21642177

21652178
class MiscTestCase(unittest.TestCase):
21662179
def test__all__(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add support for :const:`~configparser.UNNAMED_SECTION`
2+
in :meth:`configparser.ConfigParser.add_section`.

0 commit comments

Comments
 (0)
0