Configuration File Management in Python
This challenge focuses on creating a Python script that can read, write, and update configuration files in a simple, structured format (INI-like). Configuration files are essential for managing application settings, database credentials, API keys, and other parameters without hardcoding them into the source code. This exercise will help you understand how to persist data and manage application behavior through external configuration.
Problem Description
You are tasked with building a Python script that manages a configuration file. The configuration file will be a plain text file where each section is denoted by a header enclosed in square brackets (e.g., [SectionName]). Within each section, key-value pairs are separated by an equals sign (e.g., key = value). Your script should provide the following functionalities:
- Read Configuration: The script should be able to read the configuration file and return a dictionary-like structure where the keys are section names and the values are dictionaries containing the key-value pairs within that section.
- Write Configuration: The script should be able to write a dictionary-like structure to the configuration file, formatting it according to the INI-like format described above. If a file doesn't exist, it should create it.
- Update Configuration: The script should be able to update a specific key-value pair within a section of the configuration file. If the section doesn't exist, it should create it.
Key Requirements:
- The script should handle file I/O errors gracefully (e.g., file not found, permission errors).
- The script should be modular and well-structured.
- The configuration file should be easily readable and editable by humans.
- The script should not overwrite the entire file when updating a single value; it should modify the existing file.
Expected Behavior:
- Reading a non-existent file should return an empty dictionary.
- Writing to a new file should create the file and populate it with the provided configuration.
- Updating an existing key should modify the value in the file.
- Updating a key in a non-existent section should create the section and add the key-value pair.
Examples
Example 1:
Input: config_file = "config.ini", config_data = {"database": {"host": "localhost", "port": 5432, "user": "admin"}, "api": {"key": "12345"}}
Action: Write Configuration
Output: config.ini file content:
[database]
host = localhost
port = 5432
user = admin
[api]
key = 12345
Explanation: The script creates a file named "config.ini" and writes the provided configuration data in the specified format.
Example 2:
Input: config_file = "config.ini", section = "database", key = "password", value = "secret"
Action: Update Configuration
Output: config.ini file content:
[database]
host = localhost
port = 5432
user = admin
password = secret
[api]
key = 12345
Explanation: The script updates the "password" key in the "database" section of the "config.ini" file.
Example 3:
Input: config_file = "config.ini", section = "new_section", key = "setting", value = "value"
Action: Update Configuration
Output: config.ini file content:
[database]
host = localhost
port = 5432
user = admin
password = secret
[api]
key = 12345
[new_section]
setting = value
Explanation: The script creates a new section named "new_section" and adds the key-value pair "setting = value" to it.
Constraints
- The configuration file path will be a string.
- Section names and keys will be strings.
- Values can be strings. The script does not need to handle different data types (e.g., integers, booleans) beyond strings.
- The script should be able to handle configuration files up to 1MB in size.
- The script should be reasonably efficient; reading and writing the entire file for every update is not ideal, but a full rewrite on update is acceptable for this challenge.
Notes
- Consider using a dictionary to represent the configuration data in memory.
- Think about how to handle potential errors during file I/O.
- The INI format is relatively simple, but pay attention to the correct syntax (square brackets, equals signs, whitespace).
- You can use Python's built-in file I/O functions or libraries like
configparser(though usingconfigparseris discouraged for this exercise to focus on the core file manipulation logic). The goal is to understand the underlying process of reading and writing structured text files. - Focus on clarity and readability in your code. Good variable names and comments are encouraged.