Python Config parser reads comment along with value

I have a configuration file,

[local] variable1 : val1 ;#comment1 variable2 : val2 ;#comment2 

code like this only reads the key value:

 class Config(object): def __init__(self): self.config = ConfigParser.ConfigParser() self.config.read('config.py') def get_path(self): return self.config.get('local', 'variable1') if __name__ == '__main__': c = Config() print c.get_path() 

but I also want to read the comment provided along with the meaning, any suggestions in this regard will be very useful.

+7
source share
4 answers

Your only solutions are to write another ConfigParser overriding the _read() method. In ConfigParser you must remove all comments deletion checks. This is a dangerous decision , but should work.

 class ValuesWithCommentsConfigParser(ConfigParser.ConfigParser): def _read(self, fp, fpname): from ConfigParser import DEFAULTSECT, MissingSectionHeaderError, ParsingError cursect = None # None, or a dictionary optname = None lineno = 0 e = None # None, or an exception while True: line = fp.readline() if not line: break lineno = lineno + 1 # comment or blank line? if line.strip() == '' or line[0] in '#;': continue if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR": # no leading whitespace continue # continuation line? if line[0].isspace() and cursect is not None and optname: value = line.strip() if value: cursect[optname].append(value) # a section header or option header? else: # is it a section header? mo = self.SECTCRE.match(line) if mo: sectname = mo.group('header') if sectname in self._sections: cursect = self._sections[sectname] elif sectname == DEFAULTSECT: cursect = self._defaults else: cursect = self._dict() cursect['__name__'] = sectname self._sections[sectname] = cursect # So sections can't start with a continuation line optname = None # no section header in the file? elif cursect is None: raise MissingSectionHeaderError(fpname, lineno, line) # an option line? else: mo = self._optcre.match(line) if mo: optname, vi, optval = mo.group('option', 'vi', 'value') optname = self.optionxform(optname.rstrip()) # This check is fine because the OPTCRE cannot # match if it would set optval to None if optval is not None: optval = optval.strip() # allow empty values if optval == '""': optval = '' cursect[optname] = [optval] else: # valueless option handling cursect[optname] = optval else: # a non-fatal parsing error occurred. set up the # exception but keep going. the exception will be # raised at the end of the file and will contain a # list of all bogus lines if not e: e = ParsingError(fpname) e.append(lineno, repr(line)) # if any parsing errors occurred, raise an exception if e: raise e # join the multi-line values collected while reading all_sections = [self._defaults] all_sections.extend(self._sections.values()) for options in all_sections: for name, val in options.items(): if isinstance(val, list): options[name] = '\n'.join(val) 

In ValuesWithCommentsConfigParser I fixed some import data and deleted the corresponding sections of code.

Using the same config.ini from my previous answer , I can prove that the previous code is correct.

 config = ValuesWithCommentsConfigParser() config.read('config.ini') assert config.get('local', 'variable1') == 'value1 ; comment1' assert config.get('local', 'variable2') == 'value2 # comment2' 
+2
source

Alas, this is not easy to do in the general case. Comments should be ignored by the parser.

In your particular case, this is easy because # only serves as a comment character if it starts a line. So the value of variable1 will be "val1 #comment1" . I suppose you are using something like this, only less fragile:

 val1_line = c.get('local', 'var1') val1, comment = val1_line.split(' #') 

If the value "comment" is necessary, perhaps this is not a valid comment? Consider adding explicit keys for “comments,” for example:

 [local] var1: 108.5j var1_comment: remember, the flux capacitor capacitance is imaginary! 
+8
source

According to the ConfigParser documentation,

Configuration files may include comments, prefix characters (# and;). Comments may appear on their own, otherwise an empty line or may be entered into lines containing values ​​or section names. In the latter case, they must be preceded by spaces character, which will be recognized as a comment. (For backward compatibility, only; launches the inline comment, but # does not.)

If you want to read a “comment” with a value, you can skip the space before the character ; or use # . But in this case, the lines comment1 and comment2 become part of the value and are no longer considered comments.

A better approach would be to use another property name, such as variable1_comment , or to define another section in the comment configuration:

 [local] variable1 = value1 [comments] variable1 = comment1 

The first solution requires that you generate a new key using another (i.e., calculate variable1_comment from variable1 ), and the other - use the same key for different sections in the configuration file.

As with Python 2.7.2, you can always read a comment along a line if you use the # character. As the docs say, for backward compatibility. The following code should work smoothly:

 config = ConfigParser.ConfigParser() config.read('config.ini') assert config.get('local', 'variable1') == 'value1' assert config.get('local', 'variable2') == 'value2 # comment2' 

for the following config.ini file:

 [local] variable1 = value1 ; comment1 variable2 = value2 # comment2 

If you make this decision, be sure to manually analyze the get() result for the values ​​and comments.

+2
source

as instructed: Lines starting with '#' or ';' are ignored and can be used to provide comments.

therefore, the value of variable1 is "val1 # comment1". Commentary is part of the meaning.

you can check your configuration if you put in front of your comment

+1
source

All Articles