Python ConfigParser: Configuration Files Made Easy

ConfigParser is a prerequisite if you want to build Python projects that are robust to updates and easy to manage.

At the end of this tutorial, you will know how to read and write configuration files for your applications using the configparser module.

Let’s learn how to use configparser!

What Is the Python ConfigParser Module?

Configuration files, commonly known as config files, are frequently used to configure the parameters, options, and settings of operating systems and applications.

Config files store key-value pairs that are read by your application at startup and used as part of its logic.

ConfigParser is a Python module that allows to create configuration files in a simple way. With ConfigParser you can also read or update the content of a configuration file. The structure of configuration files created using ConfigParser is similar to the structure of Microsoft Windows INI files.

Separating configuration from code will save you the hassle of compiling and redeploying your code from scratch just to make a configuration change.

How Do You Know If the ConfigParser Module is Installed?

Open the Python shell and import the configparser module.

If you don’t see any error like in the example below it means the configparser module is installed.

$ python
Python 3.8.5 (default, Sep  4 2020, 02:22:02) 
[Clang 10.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import configparser
>>>

And here is the exception you will see (ModuleNotFoundError) if configparser is not installed:

>>> import configparser
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'configparser'

How to Write an INI Configuration File with Python ConfigParser

Let’s consider a simple configuration file as follows. Save it on your machine in a file called sample_config.ini.

[DEFAULT]
serverthreads = 45
content_type = text/html
content_length = 1024
autoscaling = no

[website_name.org]
username = your_name
login_mail = your_mail

[private.data.com]
password = secret_password
autoscaling = yes

In config files, you will see the name of a section within square brackets. Sections are the foundation of configuration files.

Under each section, key-value pairs are separated with the assignment symbol ‘=’. Each key value must be unique under each section. 

Let’s now check how we can create this config file with configparser: 

import configparser

config = configparser.ConfigParser()

# define sections much like a dictionary
config['DEFAULT'] = { 'serverthreads' : 45, 'content_type' : 'text/html', 'content_length' : 1024 }

# we can define the key-value pairs later on as well
config['DEFAULT']['autoscaling'] = 'no'

config['website_name.org'] = dict()
config['website_name.org']['Username'] = 'your_name' 
config['website_name.org']['login_mail'] = 'your_mail'

config['private.data.com'] = {}
private = config['private.data.com']
private['Password'] = 'secret_password'
private['autoscaling'] = 'yes'

# finally, write the config object to an INI file
with open('generated_config.ini', 'w') as configfile:
    config.write(configfile)

Notice that we are using the Python with open statement to create a configuration file called generated_config.ini.

Execute the Python program on your machine and confirm that the file it generates has the same properties as the original configuration file we created at the beginning of this tutorial.

How Python Handles Configuration Files

As you can see from the example in the previous section, you can handle a configuration file in a similar way to a dictionary.

However, it is important to notice a difference…

All keys under a config section are case-insensitive: you can easily confirm this by verifying that the following expressions both return the boolean value True.

You can add the following code at the end of the previous Python code that generates the config file.

print('ServerThreads' in config['DEFAULT'])
print('serverthreads' in config['DEFAULT'])

[output]
True
True

Later in this tutorial, I will show you how to read the INI file after creating it.

Another aspect to consider is that the DEFAULT section provides default values for all the other sections.

Let’s test this by printing the value of a property defined in the DEFAULT section but not defined in the second section of our configuration file:

print(config['website_name.org']['content_type'])

[output]
text/html

It works!

Another important thing to keep in mind is that you cannot remove the DEFAULT section, trying to do so will raise a ValueError exception:

config.pop('DEFAULT')

[output]
Traceback (most recent call last):
  File "configparser_test.py", line 26, in <module>
    config.pop('DEFAULT')
  File "/opt/anaconda3/lib/python3.8/_collections_abc.py", line 801, in pop
    del self[key]
  File "/opt/anaconda3/lib/python3.8/configparser.py", line 978, in __delitem__
    raise ValueError("Cannot remove the default section.")
ValueError: Cannot remove the default section.

How to Read an INI Configuration File with Python ConfigParser

Now that we know how to create a configuration file it’s time to learn how to read a configuration file too.

In this part of the tutorial, we will use the Python shell that helps us test different expressions easily.

You can simply start by initializing the configuration parser. Notice that without reading any config file, the config object returns an empty sections list.

>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.sections()
[]
>>>

Now use the read method of the config object to read the content of the configuration file we created:

>>> config.read('generated_config.ini')
['generated_config.ini']

You can then get the section names as follows although the DEFAULT section will not show up in the list:

>>> config.sections()
['website_name.org', 'private.data.com']

Let’s execute a few statement against the configuration file after reading it from the INI file:

>>> 'unknown_property' in config
False
>>>
>>> 'your_name' in config['website_name.org']['username']
True
>>>
>>> config['private.data.com']['password']
'secret_password'
>>>
>>> for key in config['DEFAULT']:
...     print(key)
... 
serverthreads
content_type
content_length
autoscaling

You might have already noticed that…

Config parser uses the string datatype for values in our configuration file.

The type() function below shows that the value we are retrieving from the configuration file is a string:

>>> config['DEFAULT']['serverthreads']
'45'
>>> type(config['DEFAULT']['serverthreads'])
<class 'str'>

If you want to use a different datatype, you could do it manually:

>>> int(config['DEFAULT']['serverthreads'])
45

However, configparser has a very handy method called getboolean which can distinguish boolean values in the form of ‘yes’/’no’, ‘on’/’off’, ‘true’/’false’ and ‘1’/’0′:

>>> config['private.data.com'].getboolean('autoscaling')
True

How to Get Values From a Configuration File Using ConfigParser

Similarly to a dictionary, you can use the get() method to retrieve the value corresponding to a key.

>>> website = config['website_name.org']
>>> website.get('login_mail')
'your_mail'

Moreover, the get() method also allows a fallback value, which is a value to be returned if the requested key is not found under the section:

>>> website.get('login_date', fallback='No login_date found')
'No login_date found'

It is crucial to note that the DEFAULT section has a hierarchical superiority compared to other sections and the value corresponding to a key in the DEFAULT section will take precedence over a fallback value:

>>> website.get('content_type', fallback='No login_date found')
'text/html'

Updating Values in a Config File Using Python ConfigParser

Needlessly to say, it is also possible to update key names inside a config file with configparser:

>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read('generated_config.ini')
['generated_config.ini']
>>> config['private.data.com']['password'] = 'new_password'
>>> config['website_name.org']['login_date'] = 'new_date'
>>> config['new_section'] = {'user_port': 4098, 'user_request': 'yes'}
>>> 
>>> with open('generated_config.ini', 'w') as configfile:
...     config.write(configfile)
... 
>>>

Confirm that the content of the configuration file has been updated as you can see below:

[DEFAULT]
serverthreads = 45
content_type = text/html
content_length = 1024
autoscaling = no

[website_name.org]
username = your_name
login_mail = your_mail
login_date = new_date

[private.data.com]
password = new_password
autoscaling = yes

[new_section]
user_port = 4098
user_request = yes

Makes sense?

Conclusion

In this tutorial, you have learned:

  • What a configuration file is.
  • How the Python configparser module allows you to read, write and update config files.

With configparser, you now know how to simplify the way you manage the configuration of your applications.

Bonus read: learn more about the Python with open statement that we have used a few times in this tutorial.

Leave a Comment