1

I am looking at Python 3.6 documentation where it says

By default, section names are case sensitive but keys are not [1].

For the footnote it says

[1] (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) Config parsers allow for heavy customization. If you are interested in changing the behaviour outlined by the footnote reference, consult the Customizing Parser Behaviour section.

So I look at "14.2.7. Customizing Parser Behaviour" but I cannot find the description of how to make sections case-insensitive.

I want a section like this:

[SETTINGS]
...

To be accessible like this config['section'], but currently I get an error. This is the only change to the config parser I want to apply.

senevoldsen
  • 337
  • 3
  • 8
  • `[SETTINGS]` is not a 'keys in sections', it is a section. So maybe the quote does not apply. –  Apr 10 '18 at 13:57
  • @Lutz Horn, sorry, I got the quote wrong. I have updated the question. – senevoldsen Apr 10 '18 at 14:02
  • Might be a dupe, didn't look too closely: https://stackoverflow.com/questions/26179728/how-to-get-case-sensitivity-in-section-names Either way, you probably want to override the [`SECTCRE`](https://docs.python.org/3.4/library/configparser.html#configparser.SECTCRE) attribute. – user3483203 Apr 10 '18 at 14:03
  • Question wise it is a dupe. I will use the answer proposed over there unless someone has a better one. Although it seems clear that ConfigParser only intended one to be able to change the matching, and not modify it. – senevoldsen Apr 10 '18 at 14:11

1 Answers1

3

You can do this fairly easily in Python 3.x by passing something as the optional dict_type= keyword argument described in the ConfigParser documentation—which in this case we'd like the type to be a case-insensitive ordered dictionary.

Unfortunately there isn't one in standard library, nor a conical implementation of one that I know of...so I cobbled one together to use as an example. It hasn't been rigorously tested, but works well enough to illustrate the general idea.

Note: For testing I used the following simple.ini file (which I swiped from pymotw):

# This is a simple example with comments.
[bug_tracker]
url = http://localhost:8080/bugs/
username = dhellmann
; You should not store passwords in plain text
; configuration files.
password = SECRET

Here's a demonstration showing using one to do what's needed:

import collections
from configparser import ConfigParser

class CaseInsensitiveDict(collections.MutableMapping):
    """ Ordered case insensitive mutable mapping class. """
    def __init__(self, *args, **kwargs):
        self._d = collections.OrderedDict(*args, **kwargs)
        self._convert_keys()
    def _convert_keys(self):
        for k in list(self._d.keys()):
            v = self._d.pop(k)
            self._d.__setitem__(k, v)
    def __len__(self):
        return len(self._d)
    def __iter__(self):
        return iter(self._d)
    def __setitem__(self, k, v):
        self._d[k.lower()] = v
    def __getitem__(self, k):
        return self._d[k.lower()]
    def __delitem__(self, k):
        del self._d[k.lower()]


parser = ConfigParser(dict_type=CaseInsensitiveDict)
parser.read('simple.ini')

print(parser.get('bug_tracker', 'url'))  # -> http://localhost:8080/bugs/
print(parser.get('Bug_tracker', 'url'))  # -> http://localhost:8080/bugs/
martineau
  • 119,623
  • 25
  • 170
  • 301
  • I have accepted this answer since it solves my problem, even though I believe it also affects more than just section headers; like options (though they are by default case-insensitive). – senevoldsen Apr 11 '18 at 13:15
  • senevoldsen: Yes, it makes option names case-insensitive, too, but as you point out, that's the default behavior anyway...and unfortunately that can't be overridden via the usual technique of providing a custom `optionxform()` function when using the suggested `dict_type`. pings that are used for the option names with each section. cont... – martineau Apr 11 '18 at 15:36
  • 1
    _cont_ Furthermore, after looking at the `configparser` [source](https://github.com/python/cpython/blob/3.6/Lib/configparser.py), I don't think there's a way to have section names be case-insensitive, but the not the option names because the `dict_type` is used for both the mapping of section names as well as for the mapping of option names to values. – martineau Apr 11 '18 at 15:37