Using Configparser to Read a File Without Section Name

Using ConfigParser to read a file without section name

Alex Martelli provided a solution for using ConfigParser to parse .properties files (which are apparently section-less config files).

His solution is a file-like wrapper that will automagically insert a dummy section heading to satisfy ConfigParser's requirements.

How to use python's configparser to write a file without sections

Stumbled on a less ugly way of doing this:

text = '\n'.join(['='.join(item) for item in parser.items('top')])
with open('foo.conf', 'w') as config_file:
config_file.write(text)

Is there a way to read/write config files without section headers in python?

Seems like a very simple config file syntax. Why not just write your own config parser?

conf = {}
with open('config.cfg') as fp:
for line in fp:
if line.startswith('#'):
continue
key, val = line.strip().split('=')
conf[key] = val

Configparser set with no section

You could use the csv module to do most of work of parsing the file and writing it back out after you made changes -- so it should be relatively easy to use. I got the idea from one of the answers to a similar question titled Using ConfigParser to read a file without section name.

However I've made a number of changes to it, including coding it to work in both Python 2 & 3, unhardcoding the key/value delimiter it uses so it could be almost anything (but be a colon by default), along with several optimizations.

from __future__ import print_function  # For main() test function.
import csv
import sys
PY3 = sys.version_info.major > 2

def read_properties(filename, delimiter=':'):
""" Reads a given properties file with each line in the format:
key<delimiter>value. The default delimiter is ':'.

Returns a dictionary containing the pairs.

filename -- the name of the file to be read
"""
open_kwargs = dict(mode='r', newline='') if PY3 else dict(mode='rb')

with open(filename, **open_kwargs) as csvfile:
reader = csv.reader(csvfile, delimiter=delimiter, escapechar='\\',
quoting=csv.QUOTE_NONE)
return {row[0]: row[1] for row in reader}

def write_properties(filename, dictionary, delimiter=':'):
""" Writes the provided dictionary in key-sorted order to a properties
file with each line of the format: key<delimiter>value
The default delimiter is ':'.

filename -- the name of the file to be written
dictionary -- a dictionary containing the key/value pairs.
"""
open_kwargs = dict(mode='w', newline='') if PY3 else dict(mode='wb')

with open(filename, **open_kwargs) as csvfile:
writer = csv.writer(csvfile, delimiter=delimiter, escapechar='\\',
quoting=csv.QUOTE_NONE)
writer.writerows(sorted(dictionary.items()))

def main():
data = {
'Answer': '6*7 = 42',
'Knights': 'Ni!',
'Spam': 'Eggs',
}

filename = 'test.properties'
write_properties(filename, data) # Create csv from data dictionary.

newdata = read_properties(filename) # Read it back into a new dictionary.
print('Properties read: ')
print(newdata)
print()

# Show the actual contents of file.
with open(filename, 'rb') as propfile:
contents = propfile.read().decode()
print('File contains: (%d bytes)' % len(contents))
print('contents:', repr(contents))
print()

# Tests whether data is being preserved.
print(['Failure!', 'Success!'][data == newdata])

if __name__ == '__main__':
main()

Python ConfigParser.NoSectionError: No section:

You're defining your path with backslashes:

configFilePath = 'E:\Python\configfile\test.txt'

These get interpreted as escapes, and as a result the correct file isn't being loaded. (Unfortunately, the error message doesn't help much in this instance.) You either need to escape them, or use a raw string:

configFilePath = r'E:\Python\configfile\test.txt'

configparser does not show sections

From the docs, config.read() takes in a filename (or list of them), not a file descriptor object:

read(filenames, encoding=None)

Attempt to read and parse an iterable of filenames, returning a list of filenames which were successfully parsed.

If filenames is a string, a bytes object or a path-like object, it is treated as a single filename. ...

If none of the named files exist, the ConfigParser instance will contain an empty dataset. ...

A file object is an iterable of strings, so basically the config parser is trying to read each string in the file as a filename. Which is sort of interesting and silly, because if you passed it a file that contained the filename of your actual config...it would work.

Anyways, you should pass the filename directly to config.read(), i.e.
config.read("ini/inifile.ini")

Or, if you want to use a file descriptor object instead, simply use config.read_file(f). Read the docs for read_file() for more information.


As an aside, you are duplicating some of the work the context manager is doing for no gain. You can use the with block without creating the object explicitly first or closing it after (it will get closed automatically). Keep it simple:

with open("path/to/file.txt") as f:
do_stuff_with_file(f)

How to write ini-files without sections?

[NB: the following is written for Python 3; you would need to make a couple of minor changes to make it run under Python 2.]

Maybe something like this; here, I write to an io.StringIO object in memory, then take everything but the first line and write that out to the target file.

import configparser
import io

buf = io.StringIO()

ini_writer = configparser.ConfigParser()
ini_writer.set('DEFAULT', 'option1', '99')
ini_writer.set('DEFAULT', 'option2', '34')
ini_writer.set('DEFAULT', 'do_it', 'True')
ini_writer.write(buf)

buf.seek(0)
next(buf)
with open('my.ini', 'w') as fd:
fd.write(buf.read())

By using the section name DEFAULT we avoid having to create a new section first.

This results in:

$ cat my.ini
option1 = 99
option2 = 34
do_it = True

DEFAULT section with no values in config text file

DEFAULT is a “special” section that is always present in a ConfigParser instance. It stores fallback values that are used as defaults when a value in another section is missing.

If you want to iterate over the sections in your configuration and want to exclude the default, use sections():

>>> for key in config.sections():
... print(key)
1
2
3
4
5


Related Topics



Leave a reply



Submit