Make Your Python Program Configurable

DONG Yuxuan @ Jan 04, 2021 CST

Programs are used by endpoint users but deployed by other developers, thus making your program easy to configure and conform to Unix system administrators’ mental conventions is important. Using python-dotenv with some little tricks would make it easy to implement in Python.

Principals

There’re five basic ways to configure a Unix program and the later should overwrite the earlier.

The first two are most common, for example, /etc/vimrc and ~/.vimrc. They make a program have the ability to be used by different users with their own configs.

Development config files are popular in Web frontend projects, for example, .env.local under the source tree. This file is not for system administrators but developers working on the project. They may want to specify a development database among other things.

Callings of a program may differ from each other and they all need some changes to global options. This is where environment variables and command line options come into play.

A Simple Solution for Python

python-dotenv is a Python package reads key-value pairs from .env files and adds them to environment variables. The benefits here are that we could use it to load all config files into environment variables and then we just need to handle environment variables.

python-dotenv can be installed by pip install python-dotenv and use the load_dotenv function to read a .env file into environment variables. If the function is called without arguments it reads from ./.env else it reads from the file set by the argument. An important feature of load_env is that if a key is already in environment variables it will not be overwritten. Thus we could implement our principals with the following loading order.

from dotenv import load_dotenv
import os

... # parse command line and put options to
... # environment variables **with** overwritting

load_dotenv() # development configs
load_dotenv(os.path.expanduser('~/.local.env')) # local configs
load_dotenv('/etc/global.env') # global configs

# Now, all options we need are in environment variables.