Generating Data From INI Configuration Files in Python

Icons made by Prosymbols from www.flaticon.com

Python provides a number of methods to generate data. These range from for loop, list comprehension, and range to NumPy sequences such as arange, linspace, logspace, and geomspace. Each of these have specific input parameters but they differ in the output. In this article, I’ll discuss a method to generate data under a single function with parameters read from an INI configuration file.

Using ConfigParser to Read from INI Files

The library to read from configuration files is ConfigParser. The usage is quite simple. We simply instantiate an object and then provide the filename to the read method.

import from configparser import ConfigParser
config = ConfigParser()
config.read(filename)

Once it’s provided, we can access keys within a section of the INI file using the get method.

value = config.get(section, key)

The plain get method will return strings. If the values are numbers, getint will return an integer and getfloat will return a float.

Defining Data Generation Mode and Data Type

The two modes we’ll cover are discrete and step. These two modes directly translate to a simple discrete sequence of values and also a sequence of step values. We can use the internal range function for step values but this doesn’t allow for floating point numbers. An alternative is to use np.arange() but if you need to loop over the points rather than have them in memory, it’s better to create a generator function.

The method I’ve selected is to define a frange() function to generate a range of floating-point numbers in both positive and negative directions.

For a more thorough explanation of the differences between range and np.arange visit https://realpython.com/how-to-use-numpy-arange/#comparison-of-range-and-nparange.

def frange(start, stop=None, step=None):
    """This provides a floating point range function is both positive and negative directions"""
    if stop is None:
        stop = start
        start = 0
    if step is None:
        step = 1
    i = start
    while True:
        if step > 0 and i >= stop:
            break
        elif step < 0 and i <= stop:
            break
        yield i
        i = round(i + step, 14) # round off floating point error

In addition to the mode, we’ll need to define the data type to ensure that the proper data type is returned. We use a dtype key for this and allow types int, float, and string.

mode = config.get(section, "mode", fallback="discrete")
dtype = config.get(section, "dtype", fallback="string")

We use the fallback parameters here to default to discrete strings. You could choose somethings different. With discrete strings as default, the letters section of the INI doesn’t need either mode or dtype keys.

If the mode is discrete, we’ll need to read the values and convert to the required data type. Since the individual values are provided in a comma separated format, we’ll need to split the string and the convert.

if mode == "discrete":
    if dtype == "int":
        values = map(int, config.get(name, "values").split(","))
    elif dtype == "float":
        values = map(float, config.get(name, "values").split(","))
    else:
        values = map(str, config.get(name, "values").split(","))

If the mode is step, we’ll need to read the start, stop, and step values, convert to required data type, and then call frange().

elif mode == "step":
    if dtype == "int":
        start = config.getint(name, "start")
        stop = config.getint(name, "stop")
        step = config.getint(name, "step")
    elif dtype == "float":
        start = config.getfloat(name, "start")
        stop = config.getfloat(name, "stop")
        step = config.getfloat(name, "step")

stop = round(stop + step, 14)  # increment stop for inclusive range and round off floating point error
values = frange(start, stop, step)

Finally, we return the values either as a list or generator object.

return values

Example INI File

Final Python Function

Leave a Reply