Uso de ficheros de configuración en Python

A la hora de poner en marcha un desarrollo de software, solemos necesitar de una forma ordenada de incluir nuestros parámetros de configuración como constantes, rutas base de nuestros componentes, datos de acceso a ftp, a base de datos, puertos, etc. Esto lo implementamos normalmente en un fichero de configuración que nos permite ejecutar nuestras aplicaciones en distintos entornos cambiando únicamente los datos contenidos en dicho fichero.

El formato del fichero de configuración puede ser muy variado y según nuestro estilo de programación, o el ecosistema donde se integrará nuestra aplicación nos decantaremos por un formato u otro. Alguna veces preferimos un formato tipo fichero .INI, pero al deber convivir con otros sistema que usen fichero de configuración de tipo .XML, o .YML, nos decantemos por mantener la uniformidad y utilizar también estos formatos.

A continuación veremos como podemos hacer uso de los distintos tipos de ficheros posibles (o al menos lo más habituales) y que librerías necesitaremos para cada una de ellas.

Uso de ficheros de configuración .INI

No puedo negar que mi favorito es el formato .INI y que lo empleo siempre de forma predeterminada, a no ser que el uso de otro formato plantée una ventaja específica para ese caso.

Un ejemplo de fichero config.ini lo tenemos a continuación

[mysql]
host=localhost
user=root
passwd=password
db=name

[paths]
images=/img
download=/download

[other]
available=yes
iteration=500
ratio=2.50
last_execution=2019-08-10

La librería de Python que usaremos es ConfigParser ( https://pypi.org/project/configparser/ ), y si no la tenemos instalada en nuestro entorno podemos incluirla con un sencillo:

pip install configparser

Para usar la librería y acceder a nuestro fichero de configuración, debemos importarla al comienzo de nuestro script de Pyhon, y cargar nuestro fichero config.ini, para su lectura y escritura:

import ConfigParser
import io

configfile_name = "config.ini" 

# Load the configuration file
with open(configfile_name) as f:
    config_file = f.read()
config = ConfigParser.RawConfigParser(allow_no_value=True)
config.readfp(io.BytesIO(config_file))

En este punto disponemos en nuestra variable config el objeto que nos permitirá leer y escribir nuestros parámetros de configuración.

De esta forma nos disponemos a consultar valores concretos de nuestro fichero de configuración. Si ademas el tipo del datos es entero, flotante o binario, podemos consultarlo obtenerlo ya tipado:

 # Read some contents 
print(config.get('paths','download')) # is a string
print(config.getboolean('other', 'available')) # is a boolean
print(config.getint('other', 'iteration')) # is a integer 
print(config.getfloat('other', 'ratio')) # is a float 

Recorrer y mostrar todos los valores

# List all contents
print("List all contents")
for section in config.sections():
    print("Section: %s" % section)
    for options in config.options(section):
        print("x %s:::%s:::%s" % (options,
                                  config.get(section, options),
                                  str(type(options))))

Para escribir en nuestro fichero de configuración necesitamos abrir el fichero con el modo adecuado «w» y al finalizar el proceso, guardar el fichero y cerrarlo.

import os
configfile_name = "config2.ini"

# Check if there is already a configurtion file
if not os.path.isfile(configfile_name):
    # Create the configuration file as it doesn't exist yet
    cfgfile = open(configfile_name, 'w')

    # Add content to the file
    Config = ConfigParser.ConfigParser()
    Config.add_section('mysql')
    Config.set('mysql', 'host', 'localhost')
    Config.set('mysql', 'user', 'root')
    Config.set('mysql', 'passwd', 'my secret password')
    Config.set('mysql', 'db', 'write-math')
    Config.add_section('other')
    Config.set('other',
               'preprocessing_queue',
               ['preprocessing.scale_and_center',
                'preprocessing.dot_reduction',
                'preprocessing.connect_lines'])
    Config.set('other', 'use_anonymous', True)
    Config.write(cfgfile)
    cfgfile.close()

El resultado de guardar el fichero de configuración config2.ini es:

[mysql]
host = localhost
user = root
passwd = my secret password
db = write-math

[other]
preprocessing_queue = ['preprocessing.scale_and_center', 'preprocessing.dot_reduction', 'preprocessing.connect_lines']
use_anonymous = True

Uso de ficheros de configuración .YML

Un formato habitual de fichero de configuración en aplicaciones recientes es YAML del que Wikipedia dice:

YAML es un formato de serialización de datos legible por humanos inspirado en lenguajes como XMLCPythonPerl.

https://es.wikipedia.org/wiki/YAML

Un fichero de configuración .YML debe tener una estructura similar a la siguiente:

mysql:
     host: localhost
     user: root
     passwd: my secret password
     db: write-math 
other:
     preprocessing_queue:
         - preprocessing.scale_and_center
         - preprocessing.dot_reduction
         - preprocessing.connect_lines
     use_anonymous: yes 

La librería de Python que usaremos es PyYaml (https://pyyaml.org/wiki/PyYAML), y si no la tenemos instalada en nuestro entorno podemos incluirla con un sencillo:

pip install pyyaml

Para usar la librería y acceder a nuestro fichero de configuración, debemos importarla al comienzo de nuestro script de Pyhon, y cargar nuestro fichero config.yml, para su lectura y recorrer su estructura:

import yaml 
with open("config.yml", 'r') as ymlfile:     
     cfg = yaml.load(ymlfile) 

for section in cfg:     
     print(section) 

print(cfg['mysql']) 
print(cfg['other']) 

El resultado será el siguiente:

other
mysql
{'passwd': 'my secret password',
 'host': 'localhost',
 'db': 'write-math',
 'user': 'root'}
{'preprocessing_queue': ['preprocessing.scale_and_center',
                         'preprocessing.dot_reduction',
                         'preprocessing.connect_lines'],
 'use_anonymous': True}

Uso de ficheros de configuración .XML

Un formato muy extendido en la generación de ficheros de configuración es XML.

Un ejemplo de fichero config.xml lo tenemos a continuación

<config>
    <mysql>
        <host>localhost</host>
        <user>root</user>
        <passwd>my secret password</passwd>
        <db>write-math</db>
    </mysql>
    <other>
        <preprocessing_queue>
            <li>preprocessing.scale_and_center</li>
            <li>preprocessing.dot_reduction</li>
            <li>preprocessing.connect_lines</li>
        </preprocessing_queue>
        <use_anonymous value="true" />
    </other>
</config>

Para la gestión de ficheros xml en Python es habitual el uso de la librería BeatifulSoup (https://www.crummy.com/software/BeautifulSoup/bs4/doc/). Podemos instalarla en nuestro entorno con un sencillo:

pip install lxml

La lectura del fichero de configuración se realiza de la siguiente forma:

from BeautifulSoup import BeautifulSoup 

with open("config.xml") as f:
     content = f.read()

config = BeautifulSoup(content) 

print(config.mysql.host.contents[0]) 

for tag in config.other.preprocessing_queue:
     print(tag) 

Otros posibles formatos

Podemos usar también el formato json o el más básico de todos que sería un fichero .py donde sencillamente se definan como variables goblales los parámetros que vayamos a utilizar nuestra aplicación.

Fuentes