How to read and write INI file with Python3?

Question:

I need to read, write and create an INI file with Python3.

FILE.INI

default_path = "/path/name/"
default_file = "file.txt"

Python File:

#    Read file and and create if it not exists
config = iniFile( 'FILE.INI' )

#    Get "default_path"
config.default_path

#    Print (string)/path/name
print config.default_path

#    Create or Update
config.append( 'default_path', 'var/shared/' )
config.append( 'default_message', 'Hey! help me!!' )

UPDATED FILE.INI

default_path    = "var/shared/"
default_file    = "file.txt"
default_message = "Hey! help me!!"
Asked By: Jorge Olaf

||

Answers:

http://docs.python.org/library/configparser.html

Python’s standard library might be helpful in this case.

Answered By: Alex

This can be something to start with:

import configparser

config = configparser.ConfigParser()
config.read('FILE.INI')
print(config['DEFAULT']['path'])     # -> "/path/name/"
config['DEFAULT']['path'] = '/var/shared/'    # update
config['DEFAULT']['default_message'] = 'Hey! help me!!'   # create

with open('FILE.INI', 'w') as configfile:    # save
    config.write(configfile)

You can find more at the official configparser documentation.

Answered By: Rik Poggi

Here’s a complete read, update and write example.

Input file, test.ini

[section_a]
string_val = hello
bool_val = false
int_val = 11
pi_val = 3.14

Working code.

try:
    from configparser import ConfigParser
except ImportError:
    from ConfigParser import ConfigParser  # ver. < 3.0

# instantiate
config = ConfigParser()

# parse existing file
config.read('test.ini')

# read values from a section
string_val = config.get('section_a', 'string_val')
bool_val = config.getboolean('section_a', 'bool_val')
int_val = config.getint('section_a', 'int_val')
float_val = config.getfloat('section_a', 'pi_val')

# update existing value
config.set('section_a', 'string_val', 'world')

# add a new section and some values
config.add_section('section_b')
config.set('section_b', 'meal_val', 'spam')
config.set('section_b', 'not_found_val', '404')

# save to a file
with open('test_update.ini', 'w') as configfile:
    config.write(configfile)

Output file, test_update.ini

[section_a]
string_val = world
bool_val = false
int_val = 11
pi_val = 3.14

[section_b]
meal_val = spam
not_found_val = 404

The original input file remains untouched.

Answered By: Agostino

The standard ConfigParser normally requires access via config['section_name']['key'], which is no fun. A little modification can deliver attribute access:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

AttrDict is a class derived from dict which allows access via both dictionary keys and attribute access: that means a.x is a['x']

We can use this class in ConfigParser:

config = configparser.ConfigParser(dict_type=AttrDict)
config.read('application.ini')

and now we get application.ini with:

[general]
key = value

as

>>> config._sections.general.key
'value'
Answered By: Robert Siemer

ConfigObj is a good alternative to ConfigParser which offers a lot more flexibility:

  • Nested sections (subsections), to any level
  • List values
  • Multiple line values
  • String interpolation (substitution)
  • Integrated with a powerful validation system including automatic type checking/conversion repeated sections and allowing default values
  • When writing out config files, ConfigObj preserves all comments and the order of members and sections
  • Many useful methods and options for working with configuration files (like the ‘reload’ method)
  • Full Unicode support

It has some draw backs:

  • You cannot set the delimiter, it has to be =… (pull request)
  • You cannot have empty values, well you can but they look liked: fuabr = instead of just fubar which looks weird and wrong.

contents in my backup_settings.ini file

[Settings]
year = 2020

python code for reading

import configparser
config = configparser.ConfigParser()
config.read('backup_settings.ini') #path of your .ini file
year = config.get("Settings","year") 
print(year)

for writing or updating

from pathlib import Path
import configparser
myfile = Path('backup_settings.ini')  #Path of your .ini file
config.read(myfile)
config.set('Settings', 'year','2050') #Updating existing entry 
config.set('Settings', 'day','sunday') #Writing new entry
config.write(myfile.open("w"))

output

[Settings]
year = 2050
day = sunday
Answered By: RK-Muscles God

There are some problems I found when used configparser such as – I got an error when I tryed to get value from param:

destination=my-serverbackup$%USERNAME%

It was because parser can’t get this value with special character ‘%’. And then I wrote a parser for reading ini files based on ‘re’ module:

import re

# read from ini file.
def ini_read(ini_file, key):
    value = None
    with open(ini_file, 'r') as f:
        for line in f:
            match = re.match(r'^ *' + key + ' *= *.*$', line, re.M | re.I)
            if match:
                value = match.group()
                value = re.sub(r'^ *' + key + ' *= *', '', value)
                break
    return value


# read value for a key 'destination' from 'c:/myconfig.ini'
my_value_1 = ini_read('c:/myconfig.ini', 'destination')

# read value for a key 'create_destination_folder' from 'c:/myconfig.ini'
my_value_2 = ini_read('c:/myconfig.ini', 'create_destination_folder')


# write to an ini file.
def ini_write(ini_file, key, value, add_new=False):
    line_number = 0
    match_found = False
    with open(ini_file, 'r') as f:
        lines = f.read().splitlines()
    for line in lines:
        if re.match(r'^ *' + key + ' *= *.*$', line, re.M | re.I):
            match_found = True
            break
        line_number += 1
    if match_found:
        lines[line_number] = key + ' = ' + value
        with open(ini_file, 'w') as f:
            for line in lines:
                f.write(line + 'n')
        return True
    elif add_new:
        with open(ini_file, 'a') as f:
            f.write(key + ' = ' + value)
        return True
    return False


# change a value for a key 'destination'.
ini_write('my_config.ini', 'destination', '//server/backups$/%USERNAME%')

# change a value for a key 'create_destination_folder'
ini_write('my_config.ini', 'create_destination_folder', 'True')

# to add a new key, we need to use 'add_new=True' option.
ini_write('my_config.ini', 'extra_new_param', 'True', True)
Answered By: Aleksandr Ivannikov

Use nested dictionaries. Take a look:

INI File: example.ini

[Section]
Key = Value

Code:

class IniOpen:
    def __init__(self, file):
        self.parse = {}
        self.file = file
        self.open = open(file, "r")
        self.f_read = self.open.read()
        split_content = self.f_read.split("n")

        section = ""
        pairs = ""

        for i in range(len(split_content)):
            if split_content[i].find("[") != -1:
                section = split_content[i]
                section = string_between(section, "[", "]")  # define your own function
                self.parse.update({section: {}})
            elif split_content[i].find("[") == -1 and split_content[i].find("="):
                pairs = split_content[i]
                split_pairs = pairs.split("=")
                key = split_pairs[0].trim()
                value = split_pairs[1].trim()
                self.parse[section].update({key: value})

    def read(self, section, key):
        try:
            return self.parse[section][key]
        except KeyError:
            return "Sepcified Key Not Found!"

    def write(self, section, key, value):
        if self.parse.get(section) is  None:
            self.parse.update({section: {}})
        elif self.parse.get(section) is not None:
            if self.parse[section].get(key) is None:
                self.parse[section].update({key: value})
            elif self.parse[section].get(key) is not None:
                return "Content Already Exists"

Apply code like so:

ini_file = IniOpen("example.ini")
print(ini_file.parse) # prints the entire nested dictionary
print(ini_file.read("Section", "Key") # >> Returns Value
ini_file.write("NewSection", "NewKey", "New Value"
Answered By: user10940449

You could use python-benedict, it’s a dict subclass that provides normalized I/O support for most common formats, including ini.

from benedict import benedict

# path can be a ini string, a filepath or a remote url
path = 'path/to/config.ini'

d = benedict.from_ini(path)

# do stuff with your dict
# ...

# write it back to disk
d.to_ini(filepath=path)

It’s well tested and documented, check the README to see all the features:

Documentation: https://github.com/fabiocaccamo/python-benedict

Installation: pip install python-benedict

Note: I am the author of this project

Answered By: Fabio Caccamo
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.