Davey
Davey

Reputation:

Python ConfigParser - values between quotes

When using ConfigParser module I would like to use values containing of multiple words set in cfg file. In this case seems trivial for me to surround the string with quotes like (example.cfg):

[GENERAL]
onekey = "value in some words"

My problem is that in this case python appends the quotes to the string as well when using the value like this:

config = ConfigParser()
config.read(["example.cfg"])
print config.get('GENERAL', 'onekey')

I am sure there is an in-built feature to manage to print only 'value in some words' instead of '"value in some words"'. How is it possible? Thanks.

Upvotes: 25

Views: 22803

Answers (9)

Jer Syl
Jer Syl

Reputation: 1

Just use a custom converter.

import configparser

config = configparser.ConfigParser(
  converters={
    'string': (lambda s: s.strip('"\'')),
  }
)
config.read("example.cfg")
print(config.getstring('GENERAL', 'onekey'))

You could change the converter anonymous function to

'string': (lambda s: s.strip('"\'').strip())

if you don't want leading/trailing whitespace in your converted string, in case of something like

[GENERAL]
onekey = "  value in some words  "

Upvotes: 0

Rajeshwar Mukund
Rajeshwar Mukund

Reputation: 21

can write configuration reading function as follows, which returns configuration in dictionary form.

def config_reader():
"""
Reads configuration from configuration file.
"""
configuration = ConfigParser.ConfigParser()
configuration.read(__file__.split('.')[0] + '.cfg')
config = {}
for section in configuration.sections():
    config[section] = {}
    for option in configuration.options(section):
        config[section][option] = (configuration.get(section, option)).strip('"').strip("'")
return config

Upvotes: 2

Jabba
Jabba

Reputation: 20684

I had to face the same problem. Instead of a configparser object, I prefer to work with normal dictionaries. So first I read the .ini file, then convert the configparser object to dict, and finally I remove quotes (or apostrophes) from string values. Here is my solution:

preferences.ini

[GENERAL]
onekey = "value in some words"

[SETTINGS]
resolution = '1024 x 768'

example.py

#!/usr/bin/env python3

from pprint import pprint
import preferences

prefs = preferences.Preferences("preferences.ini")
d = prefs.as_dict()
pprint(d)

preferences.py

import sys
import configparser
import json
from pprint import pprint

def remove_quotes(original):
    d = original.copy()
    for key, value in d.items():
        if isinstance(value, str):
            s = d[key]
            if s.startswith(('"', "'")):
                s = s[1:]
            if s.endswith(('"', "'")):
                s = s[:-1]
            d[key] = s
            # print(f"string found: {s}")
        if isinstance(value, dict):
            d[key] = remove_quotes(value)
    #
    return d

class Preferences:
    def __init__(self, preferences_ini):
        self.preferences_ini = preferences_ini

        self.config = configparser.ConfigParser()
        self.config.read(preferences_ini)

        self.d = self.to_dict(self.config._sections)

    def as_dict(self):
        return self.d

    def to_dict(self, config):
        """
        Nested OrderedDict to normal dict.
        Also, remove the annoying quotes (apostrophes) from around string values.
        """
        d = json.loads(json.dumps(config))
        d = remove_quotes(d)
        return d

The line d = remove_quotes(d) is responsible for removing the quotes. Comment / uncomment this line to see the difference.

Output:

$ ./example.py

{'GENERAL': {'onekey': 'value in some words'},
 'SETTINGS': {'resolution': '1024 x 768'}}

Upvotes: 1

Anatoly Orlov
Anatoly Orlov

Reputation: 406

import ConfigParser

class MyConfigParser(ConfigParser.RawConfigParser):
    def get(self, section, option):
        val = ConfigParser.RawConfigParser.get(self, section, option)
        return val.strip('"')

if __name__ == "__main__":
    #config = ConfigParser.RawConfigParser()
    config = MyConfigParser()

    config.read(["example.cfg"])
    print config.get('GENERAL', 'onekey') 

Upvotes: 11

Jim Dennis
Jim Dennis

Reputation: 17530

Davey,

As you say you can just leave the quotes off your string.

For a project I'm working on I wanted to be able to represent almost any Python string literal as a value for some of my config options and more to the point I wanted to be able to handle some of them as raw string literals. (I want that config to be able to handle things like \n, \x1b, and so on).

In that case I used something like:

def EvalStr(s, raw=False):
    r'''Attempt to evaluate a value as a Python string literal or
       return s unchanged.

       Attempts are made to wrap the value in one, then the 
       form of triple quote.  If the target contains both forms
       of triple quote, we'll just punt and return the original
       argument unmodified.

       Examples: (But note that this docstring is raw!)
       >>> EvalStr(r'this\t is a test\n and only a \x5c test')
       'this\t is a test\n and only a \\ test'

       >>> EvalStr(r'this\t is a test\n and only a \x5c test', 'raw')
       'this\\t is a test\\n and only a \\x5c test'
    '''

    results = s  ## Default returns s unchanged
    if raw:
       tmplate1 = 'r"""%s"""'
       tmplate2 = "r'''%s'''"
    else:
       tmplate1 = '"""%s"""'
       tmplate2 = "'''%s'''"

    try:
       results = eval(tmplate1 % s)
     except SyntaxError:
    try:
        results = eval(tmplate2 %s)
    except SyntaxError:
        pass
    return results

... which I think will handle anything that doesn't contain both triple-single and triple-double quoted strings.

(That one corner case is way beyond my requirements).

There is an oddity of this code here on SO; the Syntax highlighter seems to be confused by the fact that my docstring is a raw string. That was necessary to make doctest happy for this particular function).

Upvotes: 1

Eacon
Eacon

Reputation: 11

At this situation, the most simple solution is "eval()".

However, you may worry about the security stuff.But you could still do this by:

def literal_eval(node_or_string):
    """
    Safely evaluate an expression node or a string containing a Python
    expression.  The string or node provided may only consist of the following
    Python literal structures: strings, numbers, tuples, lists, dicts,booleans,
    and None.
    """

as a sample:

import ast
config = ConfigParser()
config.read(["example.cfg"])
print ast.literal_eval(config.get('GENERAL', 'onekey'))
# value in some words

Upvotes: -3

estani
estani

Reputation: 26567

The question is quite old already, but in 2.6 at least you don't need to use quotes as spaces are retained.

from ConfigParser import RawConfigParser
from StringIO import StringIO

s = RawConfigParser()
s.readfp(StringIO('[t]\na= 1 2 3'))
s.get('t','a')
> '1 2 3'

That doesn't apply though either to leading or trailing spaces! If you want to retain those, you will need to enclose them in quotes an proceed as suggested. Refrain from using the eval keyword as you'll have a huge security hole.

Upvotes: 5

Davey
Davey

Reputation:

Sorry, the solution was trivial as well - I can simply leave the quotes, it looks python simply takes the right side of equal sign.

Upvotes: 6

Mark Rushakoff
Mark Rushakoff

Reputation: 258578

I didn't see anything in the configparser manual, but you could just use the .strip method of strings to get rid of the leading and trailing double quotes.

>>> s = '"hello world"'
>>> s
'"hello world"'
>>> s.strip('"')
'hello world'
>>> s2 = "foo"
>>> s2.strip('"')
'foo'

As you can see, .strip does not modify the string if it does not start and end with the specified string.

Upvotes: 16

Related Questions