Hardcoded values are a terrible idea. Use configparser to read .ini configuration files instead
Hardcoding configuration values in Python apps is fun and games until something breaks. No one likes searching and replacing values in hundreds of files just due to a small API endpoint URL change. Luckily, there’s a way around it - and it’s by writing app configuration in a separate file.
Today you’ll learn all about working with .ini
files in Python. I find them to provide more flexibility than JSON or YAML, but just a tad worse than Python-based configuration files. Why? Well, conditional logic, for starters.
Up next, you’ll see how to install and use the configparser
Python library with .ini
configuration files in Python.
How to Install ConfigParser Python Library
You’ll need the configparser
module to work with .ini
configuration files. It doesn’t ship with Python, so you’ll have to install it. The installation command varies, depending on whether you’re using Pip or Anaconda. Here’s an installation command for both:
Pip:
pip install configparser
Anaconda:
conda install -c conda-forge -y configparser
And that’s all we need to get started working with .ini
files in Python.
How to Read .ini Configuration Files with ConfigParser
I’ve created a new folder with two files:
app.py
- Contains Python code for today.config.ini
- Contains configuration data we don’t want to hardcode in Python scripts.
As for the contents of the .ini
file, it’s best to organize it into sections. Below you’ll see two sections with the same keys and different values. The goal is to use different file save locations in different environments. For example, when in the development environment, the file will be saved to Desktop, while in production the same file will be saved in the temp directory:
[dev]
api_url = https://gorest.co.in/public/v2/users
save_dir = /Users/dradecic/Desktop/users_data
save_file = users.json
[prod]
api_url = https://gorest.co.in/public/v2/users
save_dir = /tmp/users_data
save_file = users.json
But how can you read this file in Python? The configparser
module makes it incredibly easy. Just make a new instance of the ConfigParser
class and read the .ini
file:
import configparser
config = configparser.ConfigParser()
config.read("config.ini")
We’ll now play around with the different methods you can use to access sections or individual keys.
For example, the snippet below shows you how to print all sections of a config.ini
file:
print(config.sections())
If you want to access a single element, remember to access the section first. Python’s regular dictionary notation will do:
print(config["dev"]["api_url"])
You can also use the get()
method to access individual keys:
print(config.get("dev", "api_url"))
If you have any doubt that the key won’t exist, or you want to be extra careful, specify the fallback
argument when calling get()
:
print(config.get("dev", "not_exist", fallback=-1))
You can also iterate over an entire section and access its keys and values:
for key in config["dev"]:
print(key)
But now comes the fun part. We’ve split the config.ini
file into two sections - dev and prod. By default, that has no real-world meaning. What we can do is check which OS Python is running on. For example, if the code is running on macOS we can assume it’s a development environment:
import platform
env = "dev" if platform.system().lower() == "darwin" else "prod"
print(env)
We can now use the env
variable to access keys and values in the correct section. I’m running the code on a Mac, so the contents of the dev
section get printed:
import platform
env = "dev" if platform.system().lower() == "darwin" else "prod"
for key in config[env]:
print(f"{key} = {config[env][key]}")
And that’s the basics of working with ini
files in Python. Up next, you’ll see how to use this type of configuration file when connecting to remote APIs.
How to Use ConfigParser Module in Python Apps
We’ll now make a small Python script that connects to a remote REST API and downloads the data in JSON format. We already have URLs and paths in config.ini
file. Create a new Python script and you’re good to go.
The code snippet below makes a GET request to the API endpoint and saves the response locally. It also creates the directory structure if it doesn’t exist:
import json
import platform
import pathlib
import configparser
import requests
env = "dev" if platform.system().lower() == "darwin" else "prod"
config = configparser.ConfigParser()
config.read("config.ini")
def get_users() -> dict:
r = requests.get(config[env]["api_url"])
return r.text
def save_users(users: dict) -> None:
path = pathlib.Path(config[env]["save_dir"])
if not path.exists():
path.mkdir()
with open(f"{config[env]['save_dir']}/{config[env]['save_file']}", "w") as f:
json.dump(users, f)
if __name__ == "__main__":
users = get_users()
save_users(users=users)
Below you’ll see the contents of the users_data
directory:
And that’s how you can integrate ini
configuration files into your Python projects. Let’s make a short recap next.
Summary of .ini Configuration Files with ConfigParser in Python
Hardcoding values in Python apps is always a terrible idea. It’s easy to change a couple of things in a single file, but imagine you had hundreds of them. It’s guaranteed you’ll miss a couple of places and give headache to yourself and whoever you’re working with.
Today you’ve learned how to work with ini
configuration files in Python. The entire setup is as easy as they come, but it’s not a be-all-end-all solution. For example, you can’t use programming logic in .ini
files. This shortcoming is easily addressed by using Python files for configuration. Stay tuned if you want to learn more about that.
Recommended reads
- 5 Best Books to Learn Data Science Prerequisites (Math, Stats, and Programming)
- Top 5 Books to Learn Data Science in 2022
- JSON Configuration Files in Python
Stay connected
- Hire me as a technical writer
- Subscribe on YouTube
- Connect on LinkedIn