5.1 The configparser module
Introduction to the configparser module
Currently, many popular services provide an API that we can use in our applications. Integration with these services requires authentication using data such as a login and password, or simply an access token.
Each service may require different data for authentication, but one thing is certain – we need to store it somewhere in our application. It's not a good idea to hardcode them directly in the code.
A better solution is to use the configuration file, which will be read by the code. In Python, this is possible thanks to a module called configparser
.
The configparser
module is available in the Python standard library. To start using it, we need to import the appropriate module:
import configparser
However, before we start reading the configuration data, we must familiarize ourselves with the structure of the file in which they're stored. Are you curious how this is done?
What does the configuration file look like?
The structure of the configuration file is very similar to Microsoft Windows INI files. It consists of sections that are identified by names enclosed in square brackets. The sections contain items consisting of key value pairs. Each pair is separated by a colon :
or equals sign =
.
What's more, the configuration file may contain comments followed by a semicolon ;
or hash #
:
[DEFAULT] host = localhost # This is a comment. [mariadb] name = hello user = user password = password [redis] port = 6379 db = 0
Our configuration file contains the DEFAULT
, mariadb
and redis
sections.
The DEFAULT
section is slightly different because it contains the default values that can be read in the other sections of the file. In our case, there's a common host for all sections.
The second section called mariadb
stores the data necessary to connect to the MariaDB database. These are the database name, username, and password.
The last section contains Redis
configuration data, consisting of the port and database number. In addition, both in this section and in the mariadb
section, we have access to the host option defined in the DEFAULT
section. In a moment, you'll learn how to read this data using the configparser
module.
NOTE: The whitespace at the beginning and end of keys and values is removed.
Parsing the configuration file
Parsing the configuration file is extremely simple. First, we need to create a ConfigParser
object, which provides many useful methods for parsing data. One of them is the read
method, responsible for reading and parsing the configuration file. In our example, we pass the config.ini
filename to it, but it's also possible to pass a list containing several files.
If all goes well, the read
method returns a list of filenames that have been successfully parsed. Let's look at the code in the editor to see how to parse the data stored in the config.ini
file.
import configparser config = configparser.ConfigParser() print(config.read('config.ini')) print('Sections:', config.sections(),'\n') print('mariadb section:') print('Host:', config['mariadb']['host']) print('Database:', config['mariadb']['name']) print('Username:', config['mariadb']['user']) print('Password:', config['mariadb']['password'], '\n') print('redis section:') print('Host:', config['redis']['host']) print('Port:', int(config['redis']['port'])) print('Database number:', int(config['redis']['db']))
Result:
Sections: ['mariadb', 'redis'] mariadb section: Host: localhost Database: hello Username: user Password: password redis section: Host: localhost Port: 6379 Database number: 0
In the example, we use the sections
method to display the names of sections in the file. Note that the DEFAULT
section doesn't appear in the list of returned sections. This is the default behavior of the sections
method.
Access to the data contained in the configuration file is analogous to how we use dictionaries. To obtain any value, use the appropriate key sequence. It's important to note that the section names are case sensitive, while the keys aren't.
Despite the fact that the DEFAULT
section is omitted as a result of the sections
method, we still have access to its options. Both the mariadb
and redis
sections can read the host
option.
Its also possible to access the values stored in the options by using the get
method. The get
method requires the section name and key to be passed. This is what it looks like in practice:
print('Host:', config.get('mariadb', 'host')) # print('Host:', config['mariadb']['host']
Reading configuration from other sources
The configparser
module enables configurations from various sources to be read. One of them is a dictionary that we can load using the read_dict
. Look at the code in the editor.
import configparser config = configparser.ConfigParser() dict = { 'DEFAULT': { 'host': 'localhost' }, 'mariadb': { 'name': 'hello', 'user': 'root', 'password': 'password' }, 'redis': { 'port': 6379, 'db': 0 } } config.read_dict(dict) print('Sections:', config.sections(),'\n') print('mariadb section:') print('Host:', config['mariadb']['host']) print('Database:', config['mariadb']['name']) print('Username:', config['mariadb']['user']) print('Password:', config['mariadb']['password'], '\n') print('redis section:') print('Host:', config['redis']['host']) print('Port:', int(config['redis']['port'])) print('Database number:', int(config['redis']['db']))
Result:
Sections: ['mariadb', 'redis'] mariadb section: Host: localhost Database: hello Username: root Password: password redis section: Host: localhost Port: 6379 Database number: 0
The read_dict
method accepts any dictionary whose keys are section names, while the values include dictionaries containing keys and values. All values read from the dictionary are converted to strings.
NOTE: The configparse
r module also has read_file
and read_string
methods that allow you to read the configuration from an open file or string. You can find more information about these methods in the documentation.
Creating a configuration file
Creating a configuration file is as easy as parsing it. If you know how to work with dictionaries, it's a piece of cake. Let's look at a simple example of how to create a configuration file that you already know. Take a look at the code in the editor.
import configparser config = configparser.ConfigParser() config['DEFAULT'] = {'host': 'localhost'} config['mariadb'] = {'name': 'hello', 'user': 'root', 'password': 'password'} config['redis'] = {'port': 6379, 'db': 0} with open('config.ini', 'w') as configfile: config.write(configfile)
To create a configuration file, you should treat the ConfigParser
object as a dictionary. Note that the section names are keys, while their options are listed in separate dictionaries. The above configuration is saved using the write
method, which requires an open file to be passed in text mode. For this purpose, the built-in open method is used.
A configuration loaded using the read method can also be modified. To change a single option, simply set the new value to the appropriate key, and then save the file using the write method:
import configparser config = configparser.ConfigParser() config.read('config.ini') config['redis']['db'] = '1' with open('config.ini', 'w') as configfile: config.write(configfile)
Interpolating values
The big advantage of the configuration file is the possibility of using interpolation. It allows you to create expressions consisting of a placeholder under which the appropriate value will be substituted. Take a look at the configuration file below:
[DEFAULT] host = localhost [mariadb] name = hello user = user password = password [redis] port = 6379 db = 0 dsn = redis://%(host)s
The configuration file has been extended with another option called dsn
. Its value contains the placeholder %(host)s
, which needs to be replaced by an appropriate value.
Placing any key between %
and s
informs the parser of the need to interpolate. Of course, all the work is done for us, and we only get the ready results.
For the dsn
option, it'll be the following string: redis:localhost
. Note that the placeholder
%(host)s'' has been replaced by the value stored in the host option.