Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Doc/library/configparser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1132,13 +1132,24 @@ ConfigParser Objects
strings; if not, :exc:`TypeError` is raised.


.. method:: write(fileobject, space_around_delimiters=True)
.. method:: write(fileobject, space_around_delimiters=True, trim_final_blankline=False, blankline_around_sections=True)

Write a representation of the configuration to the specified :term:`file
object`, which must be opened in text mode (accepting strings). This
representation can be parsed by a future :meth:`read` call. If
*space_around_delimiters* is true, delimiters between
keys and values are surrounded by spaces.
If *blankline_around_sections* is true, a blank line
will be inserted after each section. Set it to false for
some rudimentary programs which do not allow blank lines in INI file.
If *trim_final_blankline* is true, the final blank line
after the last section will not be inserted.

.. note::

*trim_final_blankline* does *not* trim the final
newline character (EOL) that makes the final line
has no EOL, which is common on Windows.


.. method:: remove_option(section, option)
Expand Down
34 changes: 27 additions & 7 deletions Lib/configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,16 @@
set(section, option, value)
Set the given option.

write(fp, space_around_delimiters=True)
write(fp, space_around_delimiters=True,
trim_final_blankline=False,
blankline_around_sections=True)
Write the configuration state in .ini format. If
`space_around_delimiters' is True (the default), delimiters
between keys and values are surrounded by spaces.
If `trim_final_blankline' is True (not default), the final
blank line will be trimmed. If `blankline_around_sections'
is True (the default), a blank line will be inserted
between sections.
"""

from collections.abc import MutableMapping
Expand Down Expand Up @@ -900,24 +906,38 @@ def set(self, section, option, value=None):
raise NoSectionError(section) from None
sectdict[self.optionxform(option)] = value

def write(self, fp, space_around_delimiters=True):
def write(self, fp, space_around_delimiters=True,
trim_final_blankline=False, blankline_around_sections=True):
"""Write an .ini-format representation of the configuration state.

If `space_around_delimiters' is True (the default), delimiters
between keys and values are surrounded by spaces.

If `trim_final_blankline' is True (not default), the final
blank line will be trimmed.

If `blankline_around_sections' is True (the default), a blank
line will be inserted between sections.
"""
if space_around_delimiters:
d = " {} ".format(self._delimiters[0])
else:
d = self._delimiters[0]
if self._defaults:
self._write_section(fp, self.default_section,
self._defaults.items(), d)
for section in self._sections:
self._defaults.items(), d,
(blankline_around_sections and
(not trim_final_blankline or
self._sections)))
for i, section in enumerate(self._sections.keys()):
self._write_section(fp, section,
self._sections[section].items(), d)
self._sections[section].items(), d,
(blankline_around_sections and
(not trim_final_blankline or
i + 1 != len(self._sections))))

def _write_section(self, fp, section_name, section_items, delimiter):
def _write_section(self, fp, section_name, section_items, delimiter,
final_blankline=True):
"""Write a single section to the specified `fp'."""
fp.write("[{}]\n".format(section_name))
for key, value in section_items:
Expand All @@ -928,7 +948,7 @@ def _write_section(self, fp, section_name, section_items, delimiter):
else:
value = ""
fp.write("{}{}\n".format(key, value))
fp.write("\n")
if final_blankline: fp.write("\n")

def remove_option(self, section, option):
"""Remove an option."""
Expand Down
65 changes: 36 additions & 29 deletions Lib/test/test_configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,35 +663,42 @@ def test_write(self):

cf = self.fromstring(config_string)
for space_around_delimiters in (True, False):
output = io.StringIO()
cf.write(output, space_around_delimiters=space_around_delimiters)
delimiter = self.delimiters[0]
if space_around_delimiters:
delimiter = " {} ".format(delimiter)
expect_string = (
"[{default_section}]\n"
"foo{equals}another very\n"
"\tlong line\n"
"\n"
"[Long Line]\n"
"foo{equals}this line is much, much longer than my editor\n"
"\tlikes it.\n"
"\n"
"[Long Line - With Comments!]\n"
"test{equals}we\n"
"\talso\n"
"\tcomments\n"
"\tmultiline\n"
"\n".format(equals=delimiter,
default_section=self.default_section)
)
if self.allow_no_value:
expect_string += (
"[Valueless]\n"
"option-without-value\n"
"\n"
)
self.assertEqual(output.getvalue(), expect_string)
for trim_final_blankline in (True, False):
for blankline_around_sections in (True, False):
output = io.StringIO()
cf.write(output,
space_around_delimiters=space_around_delimiters,
trim_final_blankline=trim_final_blankline,
blankline_around_sections=blankline_around_sections)
delimiter = self.delimiters[0]
if space_around_delimiters:
delimiter = " {} ".format(delimiter)
expect_string = (
"[{default_section}]\n"
"foo{equals}another very\n"
"\tlong line\n" +
("\n" if blankline_around_sections else "") +
"[Long Line]\n"
"foo{equals}this line is much, much longer than my editor\n"
"\tlikes it.\n" +
("\n" if blankline_around_sections else "") +
"[Long Line - With Comments!]\n"
"test{equals}we\n"
"\talso\n"
"\tcomments\n"
"\tmultiline\n" +
('\n' if blankline_around_sections else "")
).format(equals=delimiter,
default_section=self.default_section)
if self.allow_no_value:
expect_string += (
"[Valueless]\n"
"option-without-value\n" +
('\n' if blankline_around_sections else "")
)
if trim_final_blankline and blankline_around_sections:
expect_string = expect_string[:-1]
self.assertEqual(output.getvalue(), expect_string)

def test_set_string_types(self):
cf = self.fromstring("[sect]\n"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
New arguments *trim_final_blankline* and *blankline_around_sections* for
``configparser.ConfigParser.write``