Config Parser

Config Parser is commonly used with Python applications to configure application settings. ConfigParser is included as a core package in Python. It is common to have multiple files: one for each OS and/or environment.

Creating a Config File

For starters, we can use ConfigParser to dynamically create a configuration file. The first step will involve importing ConfigParser and initializing the class.

config_file_create.py

from configparser import ConfigParser


config = ConfigParser()

These types of config files are divided into sections. In this example, we will setup three sections:

  • settings
  • db
  • files

config_file_create.py

from configparser import ConfigParser

config = ConfigParser()

config['settings'] = {
    'debug': 'true',
    'secret_key': 'abc123',
    'log_path': '/my_app/log'
}

config['db'] = {
    'db_name': 'myapp_dev',
    'db_host': 'localhost',
    'db_port': '8889'
}

config['files'] = {
    'use_cdn': 'false',
    'images_path': '/my_app/images'
}

Now that we have our three sections with multiple options set in each one, we can now create the config file. Using a context manager to open the file, we can write it to an external file dev.ini.

config_file_create.py

from configparser import ConfigParser
# ...

with open('./dev.ini', 'w') as f:
      config.write(f)

We should now see the dev.ini file in our local working directory with the following contents:

[settings]
debug = true
secret_key = abc123
log_path = /my_app/log

[db]
db_name = myapp_dev
db_host = localhost
db_port = 8889

[files]
use_cdn = false
images_path = /my_app/images

Now that we have successfully generated a config file, we can now read it.

Reading a Config File

Similar to the creation of the file, we will need to import ConfigParser and initialize the class.

from configparser import ConfigParser

config = ConfigParser()

Next we will need to read the file:

parser.read('dev.ini')

Once this variable is set, we can grab any of the settings in the file using the following methods:

  • sections method will return a list of each section
  • get method will return a single option within a section
  • options method will list each available option in a section

The in operator can be used to check if a section exists, returning a boolean value.

print(parser.sections())  # ['settings', 'db', 'files']
print(parser.get('settings', 'secret_key'))  # abc123
print(parser.options('settings'))  # ['debug', 'secret_key', 'log_path']

print('db' in parser)  # True

When loading from a config file, all data types will be returned as strings. We could convert the data type using methods like int() or float(), however, ConfigParser has it’s own methods for handling this:

  • getint()
  • getfloat()
  • getboolean()

Below, the parser is being used to get the database port. The getint() method is the preferred way. In addition, we can set a fallback parameter in case the value is not set in the config file, which is the case for db_default_port.

print(parser.get('db', 'db_port'), type(parser.get('db', 'db_port')))  # 8889 <class 'str'>
print(int(parser.get('db', 'db_port')))  # 8889 (as int)
print(parser.getint('db', 'db_default_port', fallback=3306))  # 3306

Using the getboolean() method will work for any values that are truthy of falsey. In the config file, we have our settings debug option set to the string value ‘true’. The other string values that would have worked for this include: ‘1’, ‘yes’, and ‘on’. False values, on the other hand, include ‘0’, ‘no’, ‘false’, and ‘off’.

print(parser.getboolean('settings', 'debug', fallback=False))  # True

Using String Interpolation

String interpolation can be used to derive values from other settings. To show how this works, let’s add to our original create file:

from configparser import ConfigParser
# ...

config['settings'] = {
    'debug': 'true',
    'secret_key': 'abc123',
    'log_path': '/my_app/log',
    'python_version': '3',
    'packages_path': '/usr/local'
}

# ...

config['files'] = {
    'use_cdn': 'false',
    'images_path': '/my_app/images',
    'python_path': '${settings:packages_path}/bin/python${settings:python_version}'
}

# ...

We added the options python_version and packages_path to our settings section. Then, in the files section, we added our python_path using values from the sections section. We can re-run this script, creating a new dev.ini file.

We will also need to make edits in our read file. If we don’t tell the ConfigParser that there’s string interpolation, it will give us the raw string containing the brackets without substituting the real values. We need to import ExtendedInterpolation and pass it in to the ConfigParser class init method. Once we do that, we can get the python_path option with the correct value.

from configparser import ConfigParser, ExtendedInterpolation

parser = ConfigParser(interpolation=ExtendedInterpolation())
parser.read('dev.ini')

print(parser.get('files', 'python_path'))  # /usr/local/bin/python3

Posted in