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?
The configparser module from Python's standard library defines functionality for reading and writing configuration files as used by Microsoft Windows OS. Such files usually have . INI extension.
configparser comes from Python 3 and as such it works well with Unicode. The library is generally cleaned up in terms of internal data storage and reading/writing files.
Just use a StringIO object and the configparser's write method. It looks like the only method for "printing" the contents of a config object is ConfigParser. write which takes a file-like object.
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
For those that may be looking for another easier answer, instead of having to convert the data types yourself, you can use the localconfig module that does the conversion for you. The conversion is done by guessing the data type based on the value (I.e. 123 is an int, 123.4 is a float, true is a bool, and so on).
Here is an example following the OP's:
>>> from localconfig import config
>>> config.read('[one]\nkey = 42\nkey2 = None')
>>> config.one.key, type(config.one.key)
(42, <type 'int'>)
>>> config.one.key2, type(config.one.key2)
(None, <type 'NoneType'>)
>>> config.get('one', 'key'), config.get('one', 'key2')
(42, None)
It is a wrapper on top of ConfigParser, so it is fully compatible.
Check it out at https://pypi.python.org/pypi/localconfig
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With