0

I need to create a file in the following format:

option1 = 99
option2 = 34
do_it = True
...

When I use ConfigParser, I have to put all my data into a section with an artificial name, and then it creates a file which starts with [SECTION].

import ConfigParser

ini_writer = ConfigParser.ConfigParser()
ini_writer.add_section('SECTION')
ini_writer.set('SECTION', 'option1', 99)
ini_writer.set('SECTION', 'option2', 34)
ini_writer.set('SECTION', 'do_it', True)
with open('my.ini', 'w') as f:
    ini_writer.write(f)

How can I change it so it outputs the file without the dummy section header? I would like to do it using Python 2.7, but a Python 3 solution would help too (the idea is that I could port it to Python 2.7).

This related question shows how to read such files using minor tweaks to the code.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • Does this answer your question? [How to use python's configparser to write a file without sections](https://stackoverflow.com/questions/56566749/how-to-use-pythons-configparser-to-write-a-file-without-sections) – Tomerikoo Feb 10 '21 at 13:39
  • The first link asks the same question, but I like the answers here more. – anatolyg Feb 10 '21 at 13:58
  • Yeah I actually think so too. Maybe an opposite direction dupe is in place even though the other question is older... – Tomerikoo Feb 10 '21 at 13:59

2 Answers2

1

[NB: the following is written for Python 3; you would need to make a couple of minor changes to make it run under Python 2.]

Maybe something like this; here, I write to an io.StringIO object in memory, then take everything but the first line and write that out to the target file.

import configparser
import io


buf = io.StringIO()

ini_writer = configparser.ConfigParser()
ini_writer.set('DEFAULT', 'option1', '99')
ini_writer.set('DEFAULT', 'option2', '34')
ini_writer.set('DEFAULT', 'do_it', 'True')
ini_writer.write(buf)

buf.seek(0)
next(buf)
with open('my.ini', 'w') as fd:
    fd.write(buf.read())

By using the section name DEFAULT we avoid having to create a new section first.

This results in:

$ cat my.ini
option1 = 99
option2 = 34
do_it = True

larsks
  • 277,717
  • 41
  • 399
  • 399
  • 1
    Wouldn't it be better to do one `buf.readline()` (or `next(buf)`) and then just `for line in buf:`? Of course this is just 4 lines and using `readlines()` creates a minimal list, but in general it is better to avoid creating such list when you can directly iterate the buffer/file – Tomerikoo Feb 10 '21 at 13:44
0

As ConfigParser doesn't support this I personally would probably opt to monkeypatch the write method to support non-section writing.

from configparser import ConfigParser


def _write_section_custom(self, fp, section_name, section_items, delimiter):
    for key, value in section_items:
        value = self._interpolation.before_write(self, section_name, key, value)
        if value is not None or not self._allow_no_value:
            value = delimiter + str(value).replace('\n', '\n\t')
        else:
            value = ''
        fp.write('{}{}\n'.format(key, value))
    fp.write('\n')


ini_writer = ConfigParser()
ConfigParser._write_section = _write_section_custom
ini_writer.add_section('SECTION')
ini_writer.set('SECTION', 'option1', '99')
ini_writer.set('SECTION', 'option2', '34')
ini_writer.set('SECTION', 'do_it', 'True')
with open('my.ini', 'w') as f:
    ini_writer.write(f)

With that I get:

$ cat my.ini 
option1 = 99
option2 = 34
do_it = True

I've tested this under Python 3.8 so you would need to test/adjust for 2.7. Also bear in mind that the reading of the custom ini would need to be adapted/monkeypatched. You could also wrap this into a custom ConfigParser class of your own so that you have it reusable wherever you need it in your project.

yvesonline
  • 4,609
  • 2
  • 21
  • 32