Question

I read the part of the docs and saw that the ConfigParser returns a list of key/value pairs for the options within a section. I figured that keys did not need to be unique within a section, otherwise the parser would just return a mapping. I designed my config file schema around this assumption, then sadly realized that this is not the case:

>>> from ConfigParser import ConfigParser
>>> from StringIO import StringIO
>>> fh = StringIO("""
... [Some Section]
... spam: eggs
... spam: ham
... """)
>>> parser = ConfigParser()
>>> parser.readfp(fh)
>>> print parser.items('Some Section')
[('spam', 'ham')]

Then I went back and found the part of the docs that I should have read:

Sections are normally stored in a builtin dictionary. An alternative dictionary type can be passed to the ConfigParser constructor. For example, if a dictionary type is passed that sorts its keys, the sections will be sorted on write-back, as will be the keys within each section.

To keep my existing configuration file scheme (which I really like now ;) I'm thinking of passing a mapping-like object as mentioned above that accumulates values instead of clobbering them. Is there a simpler way to prevent key/value collapse that I'm missing? Instead of making a crazy adapter (that could break if ConfigParser's implementation changes) should I just write a variant of the ConfigParser itself?

I feel like this may be one of those 'duh' moments where I'm only seeing the difficult solutions.

[Edit:] Here's a more precise example of how I'd like to use the same key multiple times:

[Ignored Paths]
ignore-extension: .swp
ignore-filename: tags
ignore-directory: bin

I dislike the comma-delimited-list syntax because it's hard on the eyes when you scale it to many values; for example, a comma delimited list of fifty extensions would not be particularly readable.

Was it helpful?

Solution

ConfigParser isn't designed to handle such conditions. Furthermore, your config file doesn't make sense to me.

ConfigParser gives you a dict-like structure for each section, so when you call parser.items(section), I'm expecting similar output to dict.items(), which is just a list of key/value tuples. I would never expect to see something like:

[('spam', 'eggs'), ('spam', 'ham')]

Not to mention, how would you expect the following to behave?:

parser.get('Some Section', 'spam')

Which is the intended way to retrieve values.

If you want to store multiple values for the same key, I would suggest something like this in your config file:

[Some Section]
spam: eggs, ham

And this in your code:

spam_values = [v.strip() for v in parser.get('Some Section', 'spam').split(',')]

Of course, this will only work for values that don't contain commas themselves or handle quoting. For that, you should employ a more advanced technique (see this and this).

EDIT: If you don't mind the extra dependency, You could check out ConfigObj, which natively supports lists as a value type.

OTHER TIPS

This deficiency of ConfigParser is the reason why pyglet used patched version of epydoc to replace ConfigParser ini with this simple format:

name: pyglet
url: http://www.pyglet.org/

output: html
target: doc/api/
...    
module: pyglet

exclude: pyglet.gl.gl
exclude: pyglet.gl.agl
exclude: pyglet.gl.lib_agl
exclude: pyglet.gl.wgl
...

If you don't need sections - this approach can be useful.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top