Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python RawConfigParser

I'm using the RawConfigParser to read and update an ini style configuration file. This works all without problems in the standard configuration. My problem is that I'm reading different config files in the same script. Without going too much into detail, when I read the second config file its values are merged with the first ini file.

Original contents of both ini files

infile_1.ini
[section]
option = Original value
extraoption = not in ini file 2

inifile_2.ini
[section]
option = Original value

This is the code I use to alter the contents of the ini file. It's a short piece of code to reproduce the problem

import ConfigParser

class status_file:
   myConfig = ConfigParser.RawConfigParser()
   myConfig.optionxform = str

   def __init__(self, str_statusfile):
      self.myConfig.read( str_statusfile)
      self.statusfile = str_statusfile

   def option(self, new_value):
      self.myConfig.set("section","option",new_value)
      with open( self.statusfile, "w") as ini_out:
            self.myConfig.write( ini_out )


statusfiles = ['inifile_1.ini', 'inifile_2.ini']
for myStatus in statusfiles:
   myConfig = status_file(myStatus)
   myConfig.option("Something new")

After this code is executed the content of the ini files has changed as wished. But in the second ini file, options from the first ini file are merged.

infile_1.ini
[section]
option = Something New
extraoption = not in ini file 2

inifile_2.ini
[section]
option = Something New
extraoption = not in ini file 2

Is there some way I can reset the ConfigParser content or some other solution? I guess it's related to construction and deconstruction of the ConfigParser object? I tried it without the class and then there is no problem. I'm a beginner in Python so this may not be the best way of handling this. The real application is dynamic in the sense that the number of ini files and the location change during use of the application. The list of ini files is built with os.listdir(folder)

like image 366
Johan De Pontieu Avatar asked Sep 29 '22 21:09

Johan De Pontieu


2 Answers

The confusion you are making is that defining the ConfigParser like this:

class status_file:
   myConfig = ConfigParser.RawConfigParser()
   myConfig.optionxform = str

   def __init__(self, str_statusfile):
       ...

makes the myConfig attribute a class attribute for status_file, unlike, say, Java. Thus, when you parse the second file, the same config will parse it, and merge its options with he first file it parsed.

To avoid your problem, just create the parser as an instance attribute, inside the __init__ method:

class status_file(object):

   def __init__(self, str_statusfile):
       self.myConfig = ConfigParser.RawConfigParser()
       self.myConfig.optionxform = str
       ...

As a side note, if you are using Python version 2.x, your class should inherit from object. Otherwise you will have old-style (pre-python2.2) classes that might surprise you with lots of subtle problems.

like image 59
jsbueno Avatar answered Oct 03 '22 00:10

jsbueno


This is common python mistake for beginners. I assume you know language like Java or C++, don't you?

In your class myConfig is attribute of the class, not it's instances. Default Python behaviour is to look first in instance attributes, then in class attributes, so self.myConfig is exactly the same parser in both instances. See this for extended details.

Solution for you is to create and configure parser in constructor (__init__), instead of class declaration.

This may help you understand why myConfig is class attribute, not instance attribute: When you write something like this:

class A(B, C):
    def foo(x):
        return 2*x

it is just syntax sugar for:

def foo(x):
    return 2*x
A = type("A", (B, C), {"foo": foo})
del foo

This may come in handy if you ever need to create new class dynamically. As A is class, it's __call__ method finally leads to calling it's __new__ and __init__ methods, which will cause creation of new instance, which will share the same object A as it's __class__ attribute (this is simplification, it's not all that happens inside, but for general Pythoning it's enough ;) ).

like image 38
Filip Malczak Avatar answered Oct 03 '22 00:10

Filip Malczak