Parsing configure file with same section name in python

15,341

Solution 1

If what you want is to simply merge identically named sections (latest one wins), simply pass the strict=False option to the constructor (added in Python 3.2). You effectively get dict.update() behavior as the duplicate sections are merged in.

Config = configparser.ConfigParser(strict=False)

However, it's clear from the OP's sample data that identically named sections need to be kept separate, to avoid loss of data. ConfigParser stores the sections it reads in a dictionary, so it can't handle multiple sections with the same name. Fortunately the constructor accepts a dict_type argument that allows you to specify a different dictionary-like object. You can use that to support identically named sections. Here's a crude solution that mangles the section names by appending a unique number whenever a section name has been seen before.

from collections import OrderedDict

class multidict(OrderedDict):
    _unique = 0   # class variable

    def __setitem__(self, key, val):
        if isinstance(val, dict):
            self._unique += 1
            key += str(self._unique)
        OrderedDict.__setitem__(self, key, val)

Config = configparser.ConfigParser(defaults=None, dict_type=multidict, strict=False)

With a little work you should be able to construct a cleaner solution.

Solution 2

Unfortunately, the format of the provided ini file is not correct according standards. A section's name must be unique in the document.

If you can change the file-format (I already read that you cannot, but for completeness...), then a solution like this would be appropriate:

[accounts]
keys= account1, account2

[account1]
User = first

[account2]
User = second

If you really can't alternate the file's format, then I fear that your only option is to parse manually the configuration file.

Solution 3

" If you're deviating from an RFC standard and creating your own config format, you're going to have to write your own parser." This http://www.tek-tips.com/viewthread.cfm?qid=1110829 worked for me. I made a couple of small changes. ** formatting did not come out correctly when posted

def configToDict(file):
# open the file
file = open('settings.cfg')

# create an empty dict
sections = {}

for line in file.readlines():
    # get rid of the newline
    line = line[:-1]
    try:
        # this will break if you have whitespace on the "blank" lines
        if line:
            # skip comment lines
            if line[0] == '#': next
            # this assumes everything starts on the first column
            if line[0] == '[':
                # strip the brackets
                section = line[1:-1]
                # create a new section if it doesn't already exist
                if not sections.has_key(section):
                    sections[section] = {}
            else:
                # split on first the equal sign
                (key, val) = line.split('=', 1)
                # create the attribute as a list if it doesn't
                # exist under the current section, this will
                # break if there's no section set yet
                if not sections[section].has_key(key):
                    sections[section][key] = []
                # append the new value to the list
                sections[section][key].append(val)
    except Exception as e:
        print str(e) + "line:" +line
return sections

Solution 4

On the latest python there is an option that may do what you want : ConfigParser(strict=True)

Cf : https://docs.python.org/3/library/configparser.html#configparser.ConfigParser

Share:
15,341
ExyTab
Author by

ExyTab

Updated on June 24, 2022

Comments

  • ExyTab
    ExyTab almost 2 years

    I try to parse file like:

    [account]
    User = first
    
    [account]
    User = second
    

    I use ConfigParser in Python, but when i read file:

    Config = configparser.ConfigParser()
    Config.read(file)
    print (Config.sections())
    

    I have error:

    While reading from ... : section 'account' already exists
    

    How can i parse this file? Are any another library? (prefer for python3)

  • alexis
    alexis over 6 years
    Nope, it doesn't-- at least it doesn't do what the OP was after, and accepted. strict=True is the default. Setting it to False permits multiple sections with the same name, but simply merges their options.
  • Nuno André
    Nuno André over 4 years
    A pretty neat implementation of this data structure is Armin Ronacher's MultiDict.
  • alexis
    alexis over 4 years
    That's a nice interface, I agree. It should work with configparser (I haven't tried it), but it would require installing all of flask/Werkzeug as a dependency just to get the MultiDict class.
  • Orsiris de Jong
    Orsiris de Jong over 3 years
    Does not work for me. Reading works, but accessing sections by Config['SectionName'] does not work anymore, even if Config.sections() shows the section name. Using Python 3.8