Search code examples
pythonevalconfigparser

Converting ConfigParser values to python data types


ConfigParser requires all sections, keys and values to be strings; no surprise. It has methods to convert the values to datatypes with getfloat, getint, getboolean. If you don't know the datatype, you can wrap the get() with an eval() to get have the string evaluated such as:

>>> from ConfigParser import SafeConfigParser
>>> cp = SafeConfigParser()
>>> cp.add_section('one')
>>> cp.set('one', 'key', '42')
>>> print cp.get('one', 'key')
'42'
>>> print eval(cp.get('one', 'key'))
42
>>> cp.set('one', 'key', 'None')
>>> print eval(cp.get('one', 'key'))
None
>>> 

Is there a better way? I assume there some grave security concerns with evaluating text from a file- which I acknowledge; I completely trust the file.

I thought I would use pickle for this, but I would really like to keep the config file human readable.

How would you do it?


Solution

  • If you are using Python 2.6 or above you can use ast.literal_eval:

    ast.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.

    This can be used for safely evaluating strings containing Python expressions from untrusted sources without the need to parse the values oneself.

    This will work like eval when the string is safe:

    >>> literal_eval("{'key': 10}")
    {'key': 10}
    

    But it will fail if anything besides the types listed in the documentation appear:

    >>> literal_eval("import os; os.system('rm -rf somepath')")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib64/python2.6/ast.py", line 49, in literal_eval
        node_or_string = parse(node_or_string, mode='eval')
      File "/usr/lib64/python2.6/ast.py", line 37, in parse
        return compile(expr, filename, mode, PyCF_ONLY_AST)
      File "<unknown>", line 1
        import os; os.system('rm -rf somepath')
             ^
    SyntaxError: invalid syntax