How to Use Configparser to Parse INI Configuration Files in Python

# Python Configuration File Management with `configparser`

Configuration files offer a **structured** and **readable** way to manage application settings, often more maintainable than relying solely on environment variables.

**INI files**—short for *initialization files*—use a **section-based format** that is easy to read and parse.  
Python’s built-in [`configparser` module](https://docs.python.org/3/library/configparser.html) makes working with INI files **straightforward** and **powerful**.

This guide walks you through reading, parsing, and creating `.ini` files with `configparser`.

🔗 [**View the code on GitHub**](https://github.com/balapriyac/python-basics/tree/main/config-management-basics/parsing-ini-files)

---

## Prerequisites

To follow along, ensure you have:

- **Python 3.7+** installed  
- Basic knowledge of **Python syntax** and **data structures** (dicts, strings)  
- Familiarity with **file I/O** in Python  
- A **text editor or IDE**  
- Understanding of **configuration files** in applications  

> No external packages are required — `configparser` is part of Python’s standard library.

---

## Table of Contents

- [Understanding the INI File Format](#understanding-the-ini-file-format)  
- [Basic `ConfigParser` Usage](#basic-configparser-usage)  
- [Type Conversion and Default Values](#type-conversion-and-default-values)  
- [Creating a Simple Config Manager](#creating-a-simple-config-manager)  
- [Working with Multiple Sections](#working-with-multiple-sections)  
- [Writing Configuration Files](#writing-configuration-files)  
- [Conclusion](#conclusion)  

---

## Understanding the INI File Format

INI files group configuration settings into **sections**, each with **key-value pairs**.  
This is ideal for applications with multiple components or environments.

### Example: `app.ini`

[database]

host = localhost

port = 5432

username = app_user

password = secure_password

pool_size = 10

ssl_enabled = true

[server]

host = 0.0.0.0

port = 8000

debug = false

[logging]

level = INFO

file = app.log


**Sections:**  
- `database`  
- `server`  
- `logging`  

---

## Basic `ConfigParser` Usage

`ConfigParser` can **read**, **parse**, and **access** values in INI files.

import configparser

config = configparser.ConfigParser()

config.read('app.ini')

Access values from sections

db_host = config['database']['host']

db_port = config['database']['port']

print(f"Database: {db_host}:{db_port}")

print(f"Sections: {config.sections()}")


### Steps:
1. **Create** a `ConfigParser` object  
2. **Read** the INI file  
3. **Access** values using dictionary-like syntax

### Output:

Database: localhost:5432

Sections: ['database', 'server', 'logging']


---

## Type Conversion and Default Values

Values in INI files are **strings**, but `ConfigParser` supports automatic type conversion:

import configparser

config = configparser.ConfigParser()

config.read('app.ini')

Automatic type conversion

db_port = config.getint('database', 'port')

ssl_enabled = config.getboolean('database', 'ssl_enabled')

With fallback defaults

max_retries = config.getint('database', 'max_retries', fallback=3)

timeout = config.getfloat('database', 'timeout', fallback=30.0)

print(f"Port: {db_port}, SSL: {ssl_enabled}")


**Benefits:**
- Use `.getint()`, `.getboolean()`, `.getfloat()` for type safety  
- `fallback` avoids `KeyError` exceptions  

---

## Creating a Simple Config Manager

Encapsulating `ConfigParser` in a **class** can improve validation and usability:

import configparser

from pathlib import Path

class ConfigManager:

def __init__(self, config_file='app.ini'):

if not Path(config_file).exists():

raise FileNotFoundError(f"Config file not found: {config_file}")

self.config = configparser.ConfigParser()

self.config.read(config_file)

def get_database_config(self):

db = self.config['database']

return {

'host': db.get('host'),

'port': db.getint('port'),

'username': db.get('username'),

'password': db.get('password'),

'pool_size': db.getint('pool_size', fallback=5)

}


**Usage:**

config = ConfigManager('app.ini')

db_config = config.get_database_config()

print(db_config)


**Example Output:**

{'host': 'localhost', 'port': 5432, 'username': 'app_user', 'password': 'secure_password', 'pool_size': 10}


---

## Working with Multiple Sections

Access settings for multiple sections:

import configparser

config = configparser.ConfigParser()

config.read('app.ini')

Dictionary conversion

db_settings = dict(config['database'])

server_settings = dict(config['server'])

Optional section handling

if config.has_section('cache'):

cache_enabled = config.getboolean('cache', 'enabled')

else:

cache_enabled = False

print(f"Database settings: {db_settings}")

print(f"Caching enabled: {cache_enabled}")


**Output:**

Database settings: {'host': 'localhost', 'port': '5432', 'username': 'app_user', 'password': 'secure_password', 'pool_size': '10', 'ssl_enabled': 'true'}

Caching enabled: False


---

## Writing Configuration Files

You can also **generate** and **save** INI files:

import configparser

config = configparser.ConfigParser()

Add sections and values

config['database'] = {

'host': 'localhost',

'port': '5432',

'username': 'myapp'

}

config['server'] = {

'host': '0.0.0.0',

'port': '8000',

'debug': 'false'

}

Write to file

with open('generated.ini', 'w') as configfile:

config.write(configfile)

print("Configuration file created!")


---

## Conclusion

**INI files** are:
- **Human-readable**  
- Supported by Python’s `configparser`  
- Great for grouping settings by component

**Best Practices:**
- Group related settings into **sections**  
- Use **type conversion methods** (`getint`, `getboolean`, `getfloat`)  
- Set **fallback defaults** for optional keys  
- Validate configuration **early** at startup  
- Avoid storing sensitive data directly — use templates like `.ini.example`

---

**Next:** Learn how to work with **TOML** files in Python.

Until then — happy coding!

Read more