Python Forum

Full Version: ConfigParser(dict_type=) not behaving as expected
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I am using the configparser module. I am having trouble understanding the
ConfigParser(dict_type=)
method. My code:
class MultiDict(OrderedDict):
    def __init__(self):
        self.x = 0

    def __setitem__(self, key, value):
        if key == 'textsize':
            key += str(self.x)
        OrderedDict.__setitem__(self, key, value)
        print(self)
        self.x += 1
...
config1 = cp.ConfigParser(dict_type=MultiDict)
data = config1.read('ini_file.ini')
INI file:
[Menu]
MainMenuRandomizer=0
OptionsInfo=1
RandomizerQty=3
TextFont                 = Calibri
TextSize                 = 22
TextFontStatus           = Courier New
TextSize                 = 11
TextColorNormal          = 250,240,180
TextShadowColorNormal    = 50,50,50
TextColorSelected        = 255,255,255
TextShadowColorSelected  = 50,50,50
TextColorEditing         = 255,100,50
TextShadowColorEditing   = 50,50,50
PositionX                = 800
PositionY                = 120
InfoPositionX            = 480
InfoPositionY            = 800
TitleColumnSize          = 1000
MainItemColumnSize       = 100
ItemColumnSize           = 300
InfoColumnSize           = 960
RowSpace                 = 0
RowsPerPage              = 30
KeyEnable                = 24
KeyUp                    = 200
KeyDown                  = 208
KeyLeft                  = 203
KeyRight                 = 205
KeyPageUp                = 201
KeyPageDown              = 209
KeyAdd                   = 78
KeySubtract              = 74
KeySave                  = 28
KeyEditing               = 156
StepValue                =0.1
Decimals                 = 4
As you can see from the config file, there are two options named "TextSize". When I run the above code, I get the following error:
configparser.DuplicateOptionError: While reading from 'ini_file.ini' [line 182]: option 'textsize' in section 'Menu' already exists
The print statement in my class shows that the ordered dictionary is getting updated, like so:
MultiDict([('mainmenurandomizer', ['0']), ('optionsinfo', ['1']), ('randomizerqty', ['3']), ('textfont', ['Calibri']), ('textsize4', ['22'])]
Why is the read operation still throwing an exception? I don't understand.
Use strict=False in the ConfigParser constructor as per the documentation.
I know I can do it that way, thanks. I've got code that does what I want using strict=False. However, I'd like to figure out why I can't modify the dictionary passed to read(). Ideally, I'd like to keep the configuration file complete, just renaming options that are identical in the config file.
This code apparently does what you want
from configparser import ConfigParser
import itertools as itt

confstr="""\
[Menu]
MainMenuRandomizer=0
OptionsInfo=1
RandomizerQty=3
TextFont                 = Calibri
TextSize                 = 22
TextFontStatus           = Courier New
TextSize                 = 11
TextColorNormal          = 250,240,180
TextShadowColorNormal    = 50,50,50
TextColorSelected        = 255,255,255
TextShadowColorSelected  = 50,50,50
TextColorEditing         = 255,100,50
TextShadowColorEditing   = 50,50,50
PositionX                = 800
PositionY                = 120
InfoPositionX            = 480
InfoPositionY            = 800
TitleColumnSize          = 1000
MainItemColumnSize       = 100
ItemColumnSize           = 300
InfoColumnSize           = 960
RowSpace                 = 0
RowsPerPage              = 30
KeyEnable                = 24
KeyUp                    = 200
KeyDown                  = 208
KeyLeft                  = 203
KeyRight                 = 205
KeyPageUp                = 201
KeyPageDown              = 209
KeyAdd                   = 78
KeySubtract              = 74
KeySave                  = 28
KeyEditing               = 156
StepValue                =0.1
Decimals                 = 4
"""

class MyDict(dict):
    def __init__(self, *args, **kwargs):
        self.c = itt.count()
        super().__init__(*args, **kwargs)
        
    def __setitem__(self, k, v):
        if k == 'textsize':
            n = next(self.c)
            k = k + str(n)
        print('setitem:', id(self), k, v)
        super().__setitem__(k, v)
        

conf = ConfigParser(dict_type=MyDict, strict=False)
conf.read_string(confstr)
print(dict(conf['Menu']))
You didn't call __init__() for OrderedDict. Not your problem here, but always a good idea to call super()__init__().

Notice that the error occurs in "configparser.py", not your program file, not in your special dictionary. Allowing or disallowing duplicate keys is an attribute of the configparser. The test for duplicates is performed using a set (elements_added) that is a local variable in the read_dict() method. Other than subclassing configparser and modifying that method the only way to allow duplicate keys in a section is to set "strict=False".
Necro time. Been away from these forums (using two others for help, but this place is incredibly helpful as well. So, here I am back for help), but want to keep it in rotation.

This script was an aside of mine, and I haven't picked it back up since back in February. Having read the replies, it looks like I can't do what I was trying to do? I don't know, I'd have to dig up the old script somewhere on my backup drive.

But, I necro'd just to say thanks you two (sorry if it's frowned upon). If I pick the script up again, I'll refer back here.