3 formas de leer archivos de configuración y secretos en Python

Guardar y leer la configuración y secretos de nuestra aplicación Python es muy importante. Podemos hacerlo en un archivo ini, json, XML, YAML y en variables de entorno.

3 formas de leer archivos de configuración y secretos en Python

Cuando desarrollamos una aplicación, lo normal es que utilice una base de datos, un servidor de caché o que incluso tenga integraciones con servicios de terceros como Stripe que requieren de un API key. Las variables de configuración y secretos de una aplicación nunca deben guardarse en nuestro repositorio, sino que deben guardarse en archivos de configuración.

¡Imaginad que guardamos nuestra clave de base de datos hardcodeada en el repositorio y lo subiéramos a Github!

En este artículo vamos a ver 4 formas de leer archivos de configuración en Python.

1. Guardar la configuración en el código

¡Cuidado con esto porque es el caso en el que comentaba que podemos subir nuestros secretos a Git y/o compartirlos con más gente! Por ejemplo, podríamos tener el archivo de configuración config.py:

DATABASE_CONFIG = {
   'db_host': 'localhost',
   'db_name': 'my_database_name',
   'db_user': 'database_user',
   'db_password': 'database_password',
   'db_port': 3306
}
database_name = DATABASE_CONFIG['db_name']

El problema de esto es que tenemos las variables de configuración y conexión a nuestra base de datos introducidas directamente en el código, y esto no es una buena práctica. Es cierto que es muy cómodo, pero nada seguro.

Mi recomendación es que no guardéis ningún secreto en el propio código.

2. Guardar los secretos en un archivo de configuración externo

De esta manera guardamos la configuración de nuestra aplicación en un archivo externo que podemos ignorar en Git. Podemos utilizar archivos con extensión .ini o .json gracias a la extensión de Python configparser para Python 3.x o ConfigParser para Python 2.x.

Vamos a ver cómo sería el archivo config.ini:

; config.ini
[DEFAULT]
DB_NAME = db_name_default
DB_USER = db_user_default
DB_PASSWORD = db_password_default
[TESTING]
DB_NAME = db_name_testing
DB_USER = db_user_testing
DB_PASSWORD = db_password_testing
[PRODUCTION]
DB_NAME = db_name_production
DB_USER = db_user_production
DB_PASSWORD = db_password_production

De esta manera, podríamos carga la configuración de nuestra aplicación como en el siguiente ejemplo en Python utilizando el archivo config.ini:

import configparser
config = configparser.ConfigParser()
config.read('config.ini')
database_name = config['DEFAULT']['DB_NAME']
database_password = config['DEFAULT']['DB_PASSWORD']

En caso de utilizar JSON, el archivo config.json podría quedar así:

// config.json
{
   "DEFAULT": {
       "DB_NAME": "db_name_default",
       "DB_USER = db_user_default",
       "DB_PASSWORD = db_password_default"
   },
   "TESTING": {
       "DB_NAME = db_name_testing",
       "DB_USER = db_user_testing",
       "DB_PASSWORD = db_password_testing"
   },
   "PRODUCTION": {
       "DB_NAME = db_name_production",
       "DB_USER = db_user_production",
       "DB_PASSWORD = db_password_production"
   }
}

Para leer el archivo de configuración tendríamos que abrir utilizar la librería json:

import json

with open('config.json', 'r') as file:     config = json.load(file)

database_name = config['DEFAULT']['DB_NAME'] database_password = config['DEFAULT']['DB_PASSWORD']

Con este método, podríamos tener un archivo config.ini.example que contuviese las variables de configuración vacías y que podríamos commitear en Git, y por otra parte tendríamos el archivo config.ini, el cual añadiríamos al .gitignore para ignorarlo.

3. Guardar la configuración en variables de entorno

En este caso no utilizaríamos ningún archivo sino las variables de entorno de nuestro propio sistema operativo. Gracias al paquete os podemos acceder a ellas en Python. Vamos a ver un ejemplo:

import os database_name = os.environ.get('DB_NAME', None)

Lo que hemos hecho aquí es obtener la variable de entorno DB_NAME a través del módulo os y, si no se encuentra disponible, asignarle un None, que sería un valor por defecto.

Conclusiones

Para finalizar el artículo, me gustaría comentar que personalmente prefiero la opción 2 o la opción 3, ya que la 1 me parece algo insegura. Es cierto que si vamos a realizar un script que ni vamos a subir a Github ni vamos a compartir con nadie, podemos guardar las variables de configuración y secretos en nuestro propio código, pero debemos tener mucho cuidado de no subir nuestras contraseñas y secretos a ningún sitio.