Instalación de la dependencia
Primero, es necesario intsalar la biblioteca ruamel.yaml mediante pip:
pip install ruamel.yaml
Implementación del método personalizado
El mecanismo principal consiste en sobrescribir el método represent_none del volizador (Dumper). A continuación se presenta una implementación completa:
import ruamel.yaml
# Datos de ejemplo con diversos tipos, incluyendo valores nulos
configuracion = {
"titulo": "Aplicación Demo",
"descripcion": None,
"activo": True,
"etiquetas": ["dev", None, "python"],
"parametros": {
"timeout": None,
"max_conexiones": 100
}
}
# Crear una instancia personalizada del Dumper
class DumperPersonalizado(yaml.Dumper):
pass
# Definir cómo representar valores None
DumperPersonalizado.add_representer(
type(None),
lambda dumper, value: dumper.represent_scalar('tag:yaml.org,2002:null', '')
)
# Volcar los datos al archivo YAML
with open('configuracion.yaml', 'w', encoding='utf-8') as archivo:
yaml.dump(configuracion, archivo, Dumper=DumperPersonalizado, allow_unicode=True)
Alternativa usando represent_none directamente
Otra aproximación más directa consiste en modificar la instancia del Dumper después de crearla:
import ruamel.yaml
datos_ejemplo = {
"usuario": "admin",
"email": None,
"roles": [None, "editor", None]
}
# Instanciar el Dumper con opciones personalizadas
volizador = yaml.Dumper(width=120)
volizador.represent_none = lambda self, data: self.represent_scalar(
'tag:yaml.org,2002:null',
''
)
# Generar la salida YAML como cadena
resultado = yaml.dump(datos_ejemplo, Dumper=volizador)
print(resultado)
Resultado esperado
Al ejecutar el código anterior, el archivo YAML generado presentará el siguiente formato:
titulo: Aplicación Demo
descripcion: ''
activo: true
etiquetas:
- dev
- ''
- python
parametros:
timeout: ''
max_conexiones: 100
Verificación mediante pruebas
Para validar el comportamiento correcto, se puede implementar una prueba unitaria:
import ruamel.yaml
import pytest
class DumperPruebas(yaml.Dumper):
pass
DumperPruebas.add_representer(
type(None),
lambda d, v: d.represent_scalar('tag:yaml.org,2002:null', '')
)
def verificar_yaml_vacio():
datos = {
"nombre": "Prueba",
"valor": None,
"habilitado": False,
"elementos": [1, None, 3]
}
salida = yaml.dump(datos, Dumper=DumperPruebas)
assert "valor: ''" in salida, "El valor nulo no se representó correctamente"
assert "- ''" in salida, "El valor nulo en lista no se representó correctamente"
print("Todas las verificaciones pasaron exitosamente")
if __name__ == "__main__":
verificar_yaml_vacio()
Casos de uso en proycetos reales
Esta técnica resulta particularmente útil en escenarios donde se requiere mantener una distinción clara entre valores nulos y valores ausentes. Por ejemplo, en archivos de configuración de aplicaciones, en definiciones de esquemas de API, o cuando se procesan datos para modelos de machine learning donde los valores nulos tienen un significado específico distinto de los valores por defecto.