How To Use ConfigParser For Configuration Files In Python 3


Python 3 config files
Intermediate

Putting parameters in configuration files can take some extra effort at the start, but then can save you a lot of time and heartache in the future. We are all tempted to simply hardcode parameters directly into our code as we save precious time when we write code, but then doing this properly can take extra effort. Some of us at least create constants or store parameters in a variable, while others store them in a class variable to keep this even cleaner. Arguably the best option is store these in a configuration file. In this article you’ll learn the steps compulsory to use configuration files in python 3. It will be strictly according to the official documentation of python 3.

ConfigParser is the class used to implement configuration files in python 3. The main function of using these files is to write python programs which can easily be modified by end users easily. The main aspect of this article is to know about the complete implementation of configuration files. We will cover the three main aspects in this article which are Setup, File format and Basic API.

Introduction to Python 3 Configuration Files

Configuration files can play a vital role in any program and its management. One of the popular approaches to separate code from configuration is to store these files in YAML, JSON or INI and not in .py format. One reason that .py files are not used is that Python 3 can be slower when it comes to reloading. You would need to restart the whole program if you stored your config in a python .py file. Also, the end user can modify the code at will if it is in .py format. Configuration files make it easier to modify or change the code. The data stored in configuration is to have separation so that the programmer can focus on code development and ensure that is clean as possible and the user only needs to touch the configuration file.

Setup of Python 3 ConfigParser

The class used to create configuration files is ConfigParser. This is a part of the standard python 3 library so no need to do any pip installation. We have to import it: “import configparser” to use it or there is another way of using it, it will work in both python2 and python 3, which is: 

    import configparser

File Format of configuration file

One convention that is used for the file format is to use the extension .ini (short for initial or initiation) but you can use the configuration based on your own or on clients preferences. There are different parts of configuration files. 

  • A configuration file consists of one or more sections. 
  • The section names are written in these delimiters [section name]. 
  • The concept is similar to mapping. It consists of key-value pairs meaning there is a name of the configuration item (“key”) and the other the actual value of the configuration (“value”)
  • Two operators are used to initialize or separate key-value pair assignment operator (=) or colon operator (:).
  • You can even put in a comment using the # or ; prefix.

Example: 

[default]

host = 192.168.1.1
port = 31

username = admin

password = admin

[database]

#database related configuration files
port = 22
forwardx11 = no

name = db_test

In the above configuration file example, we have two sections first is [default]  and second is [database]. Each section has its own key-value pairs/entries like username = admin and name = db_test. So all of the key-value pairs belong to a given section, so it is easier to organise your configuration files. Finally the sentence with a prefix of # is for commenting

Reading the configuration file from python code

Now, we will talk about the method to read from the config file. As mentioned earlier, ConfigParser is the module/class used to create configuration files. First, ConfigParser object has to be initialized: config = configparser.ConfigParser(); The following are functions:

Initialization of ConfigParser

You can can initiate the configuration file with the following syntax. Here the variable “config” will contain all the values

config = configparser.ConfigParser()

Write to a Configuration file with ConfigParser

Although normally you normally edit to a configuration file in a text editor by hand, there are times where you want to programmatically write to a config file. For example, this could be to create a default config file which a user can then use as a basis to change or edit. You may also want to over-ride a config entry (after confirming with the user) that is erroneous.

Once the object is initialised, we can now write in it. There are ways through which we can initialize the section to write in the config file. We are going use the example mentioned above in file format. Let’s initialize the default section using dictionary.

Example: 

config['default'] = {
 "host" : "192.168.1.1",
 "port" : "22",
 "username" : "username",
 "password" : "password"
 }

Here, “default” is the name of the section (the part in the actual configuration file that had the square “[” and “]” brackets) and curly braces denote the start and end of a dictionary. Inside the dictionary are key-value pairs i.e. “host” is the key and “192.168.1.1” is the value separated by colon “:”

Now, let’s initialize the database section using empty dictionary and add the key-value pairs line by line. 

Example:

 config['database'] = {}
 config['database']['port'] = "22"
 config['database']['forwardx11'] = "no"
 config['database']['name'] = "db_test"

Here, “database” is the name of the section and curly braces denote the same start and end of a dictionary. In this case, the dictionary is empty. Key-value pairs i.e. “port” is the key and “22” is the value separated by colon “=.” This method provides a lot more flexibility. 

Here’s the full code so far:

import configparser

config = configparser.ConfigParser()
config['default'] = {
 "host" : "192.168.1.1",
 "port" : "22",
 "username" : "username",
 "password" : "password"
 }

config['database'] = {}
config['database']['port'] = "22"
config['database']['forwardx11'] = "no"
config['database']['name'] = "db_test"

with open('test.ini', 'w') as configfile:
      config.write(configfile);

After initializing the sections in config, you can now write it to a config file:

with open('test.ini', 'w') as configfile:
      config.write(configfile);

Now, you will be able to see the file named test.ini created.

Read config from the config file using ConfigParser

The next step is to read the file which you just have created.

  • The config file can be read by using read() method: config.read(‘test.ini’). This will read the test.ini file which you just created.
  • If you want to print just the sections available in configuration file, method sections() can be used: config.sections().
  • Next is getting the value of any key stored in the section. config[‘database’][‘name’] 

This will give you the value which is “db_test” of the key called “name” stored in data_base section. 

The following code will print out all the values stored against the keys in the default section using a for loop.

for key in config['default']:
    print(config['default'][key])

Code:

Output:

Changing the datatype of the configuration value from ConfigParser

The datatype of the object of ConfigParser is string by default. This is fine for most situations, but then suppose you want to get a true/false value instead, or a number value to do maths operations. For this the string default may not work. We can typecast/covert the datatype of the object of configparser or the datatype of keys of section into any other type such as integer, float etc. In order to change the datatype of object, you have to covert it manually or by using getter methods. The best and the preferred way is to use getter methods.

There are three getter methods:

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

Example: config['default'].getint('port')

getint() will covert the datatype of port key of section “default” into “integer”. If you use the typeof(); method on port then it will show integer type now.

There is another way of doing it:

Example: config.getboolean('data_base', 'forwardx11')

In this way, config file is invoking the getboolean() method and its takin two parameters as argument. The first is the name of the section and the other is the key whole value’s type will be changed.

What to do if a value is not available from a configfile

A fallback result can also be obtained. Fallback is the result obtained when the key or section we want to get isn’t available.

Example: config.get('default', 'database', fallback='not_database')  

In this case, not_database will be returned if the “database” key isn’t available or the section default is not found.

Conclusion

We come to know about the setup i.e. importing the ConfigParser first to create configuration files. Next section was about the file format. There you can check about the basic syntax of creating a configuration file. It consists of sections and key-value pairs.

We played with the data types of keys in default and data_base sections. We can change datatypes using getter methods. Last but not the least, we studied about the basic api like write, read and about fallback.

Using configuration files is not difficult and can save a lot of time. So in your next coding work, take the extra few minutes to create a configuration file instead of hardcoding.

Full Code: ConfigParser Example Code

import configparser

config = configparser.ConfigParser() 

#Set up default item for hosts using dictionary
config['default'] = {"host" : "192.168.1.1",
                     "port" : "22",
                     "username" : "username",
                     "password" : "password" }

#setup config item bytes
config['database'] = {}
config['database']['port'] = "22"
config['database']['forwardx11'] = "no"
config['database']['name'] = "db_test"

#Write default file
with open('test.ini', 'w') as configfile:
	config.write(configfile)

#Open the file again to try to read it
config.read('test.ini')

#Print the sections
print(config.sections())

print( config['database']['name'] )

#Print each key pair
for key in config['default']:
	print(config['default'][key])

#print the type of integer value
print (type (config['default'].getint('port')))

print( config.getboolean('database', 'forwardx11') )

#Print default value
print( config.get('default', 'databaseabc', fallback='not_database') )

Output:

Reference

https://docs.python.org/3/library/configparser.html

Want to see more useful tips?

Get new tips in your inbox automatically. Subscribe to our newsletter!

Charles White

I'm a big believer in the value of learning to code and learning to code is something that everyone should learn these days. Here are a collection of things i've learned over the years..

Leave a Reply

Your email address will not be published. Required fields are marked *

Recent Content