4

I can use the ConfigParser module in python to create ini-files using the methods add_section and set (see sample in http://docs.python.org/library/configparser.html). But I don't see anything about adding comments. Is that possible? I know about using # and ; but how to get the ConfigParser object to add that for me? I don't see anything about this in the docs for configparser.

Niclas Nilsson
  • 5,691
  • 3
  • 30
  • 43
  • 3
    See the accepted answer to the question [Python ConfigParser question about writing comments to files](http://stackoverflow.com/questions/6620637/python-configparser-question-about-writing-comments-to-files) – Chris Dec 16 '11 at 12:24
  • Oh. I did'nt see that answer. Sorry! It's not a beautiful solution but I guess that's the way I have to do it. Thanks! – Niclas Nilsson Dec 16 '11 at 12:30
  • Yes, it is a shame about the trailing `=` sign, but there doesn't seem to be a lot you can do about that! – Chris Dec 16 '11 at 12:33
  • I guess another thing I could do is to place the comment on the same line like this: config.set('Section', 'option', 'value ; comment') I'll try that when I have some time... – Niclas Nilsson Dec 16 '11 at 12:48

3 Answers3

5

If you want to get rid of the trailing =, you can subclass ConfigParser.ConfigParser as suggested by atomocopter and implement your own write method to replace the original one:

import sys
import ConfigParser

class ConfigParserWithComments(ConfigParser.ConfigParser):
    def add_comment(self, section, comment):
        self.set(section, '; %s' % (comment,), None)

    def write(self, fp):
        """Write an .ini-format representation of the configuration state."""
        if self._defaults:
            fp.write("[%s]\n" % ConfigParser.DEFAULTSECT)
            for (key, value) in self._defaults.items():
                self._write_item(fp, key, value)
            fp.write("\n")
        for section in self._sections:
            fp.write("[%s]\n" % section)
            for (key, value) in self._sections[section].items():
                self._write_item(fp, key, value)
            fp.write("\n")

    def _write_item(self, fp, key, value):
        if key.startswith(';') and value is None:
            fp.write("%s\n" % (key,))
        else:
            fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t')))


config = ConfigParserWithComments()
config.add_section('Section')
config.set('Section', 'key', 'value')
config.add_comment('Section', 'this is the comment')
config.write(sys.stdout)

The output of this script is:

[Section]
key = value
; this is the comment

Notes:

  • If you use an option name whose name starts with ; and value is set to None, it will be considered a comment.
  • This will let you add comments and write them to files, but not read them back. To do that, you'll have implement your own _read method that takes care of parsing comments and maybe add a comments method to make it possible to get the comments for each section.
jcollado
  • 39,419
  • 8
  • 102
  • 133
  • It works great. Thanks alot. But I don't get what the write method does. I don't need it, or am I missing something? – Niclas Nilsson Dec 20 '11 at 20:16
  • The `write` method is the one you use to write to the configuration file. You need it to avoid using the default implementation. – jcollado Dec 20 '11 at 20:57
1

Make a subclass, or easier:

import sys
import ConfigParser

ConfigParser.ConfigParser.add_comment = lambda self, section, option, value: self.set(section, '; '+option, value)

config = ConfigParser.ConfigParser()
config.add_section('Section')
config.set('Section', 'a', '2')
config.add_comment('Section', 'b', '9')
config.write(sys.stdout)

Produces this output:

[Section]
a = 2
; b = 9
atomocopter
  • 948
  • 10
  • 20
  • Thanks for the solution. I could of course do what you said (+1 for the add_comment method). But it would'nt solve the problem with the ugly trailing = – Niclas Nilsson Dec 16 '11 at 13:25
0

To avoid the trailing "=" you can use the sed command with subprocess module, once you have written the config instance to a file

**subprocess.call(['sed','-in','s/\\(^#.*\\)=/\\n\\1/',filepath])**

filepath is the INI file you generated using the ConfigParser

Ram
  • 1,115
  • 8
  • 20