¿Cómo puedo analizar un archivo YAML en Python?

611

¿Cómo puedo analizar un archivo YAML en Python?

Szymon Lipiński
fuente

Respuestas:

806

El método más sencillo y puro sin depender de los encabezados C es PyYaml ( documentación ), que se puede instalar a través de pip install pyyaml:

#!/usr/bin/env python

import yaml
import json

with open("example.yaml", 'r') as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Y eso es. yaml.load()También existe una función simple , pero yaml.safe_load()siempre debe preferirse a menos que necesite explícitamente la serialización / deserialización de objetos arbitrarios proporcionada para evitar introducir la posibilidad de ejecución de código arbitrario.

Tenga en cuenta que el proyecto PyYaml admite versiones hasta la especificación YAML 1.1 . Si se necesita compatibilidad con la especificación YAML 1.2 , consulte ruamel.yaml como se indica en esta respuesta .

Jon
fuente
96
Agregaría que a menos que desee serializar / deserializar objetos arbitrarios, es mejor usarlo yaml.safe_loadya que no puede ejecutar código arbitrario desde el archivo YAML.
ternaryOperator
44
Yaml yaml = nuevo Yaml (); Objeto obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou
2
Me gusta el artículo de alce: martin-thoma.com/configuration-files-in-python
SaurabhM
44
Es posible que primero necesite instalar el paquete PyYAML pip install pyyaml, consulte esta publicación para obtener más opciones stackoverflow.com/questions/14261614/…
Romain
77
¿Cuál es el punto de capturar la excepción en este ejemplo? Se va a imprimir todos modos, y sólo hace que el ejemplo más enrevesado ..
naught101
116

Leer y escribir archivos YAML con Python 2 + 3 (y unicode)

# -*- coding: utf-8 -*-
import yaml
import io

# Define data
data = {
    'a list': [
        1, 
        42, 
        3.141, 
        1337, 
        'help', 
        u'€'
    ],
    'a string': 'bla',
    'another dict': {
        'foo': 'bar',
        'key': 'value',
        'the answer': 42
    }
}

# Write YAML file
with io.open('data.yaml', 'w', encoding='utf8') as outfile:
    yaml.dump(data, outfile, default_flow_style=False, allow_unicode=True)

# Read YAML file
with open("data.yaml", 'r') as stream:
    data_loaded = yaml.safe_load(stream)

print(data == data_loaded)

Archivo YAML creado

a list:
- 1
- 42
- 3.141
- 1337
- help
- 
a string: bla
another dict:
  foo: bar
  key: value
  the answer: 42

Finales de archivo comunes

.yml y .yaml

Alternativas

Para su aplicación, lo siguiente puede ser importante:

  • Soporte por otros lenguajes de programación.
  • Rendimiento de lectura / escritura
  • Compacidad (tamaño del archivo)

Ver también: Comparación de formatos de serialización de datos.

En caso de que esté buscando una forma de crear archivos de configuración, puede leer mi breve artículo Archivos de configuración en Python

Martin Thoma
fuente
Mi salida de en Windows es €. Alguien sabe el motivo?
Cloud Cho
¿Qué codificación tiene el archivo? ¿Estás seguro de que está codificado en utf-8?
Martin Thoma
1
Gracias por la sugerencia Mi archivo tiene codificación utf-8. Tuve que cambiar su línea de código io.open(doc_name, 'r', encoding='utf8')para leer el carácter especial. YAML versión 0.1.7
Cloud Cho
Huh, interesante Intentaré reproducir eso mañana y ajustaré la pregunta si puedo. ¡Gracias!
Martin Thoma
1
Puede usar el incorporado open(doc_name, ..., encodung='utf8')para leer y escribir, sin importar io.
dexteritas
62

Si tiene YAML que cumple con la especificación YAML 1.2 (lanzada en 2009), entonces debe usar ruamel.yaml (descargo de responsabilidad: soy el autor de ese paquete). Es esencialmente un superconjunto de PyYAML, que admite la mayor parte de YAML 1.1 (desde 2005).

Si desea poder conservar sus comentarios cuando realiza un viaje de ida y vuelta, debe utilizar ruamel.yaml.

Actualizar el ejemplo de @ Jon es fácil:

import ruamel.yaml as yaml

with open("example.yaml") as stream:
    try:
        print(yaml.safe_load(stream))
    except yaml.YAMLError as exc:
        print(exc)

Úselo a safe_load()menos que realmente tenga control total sobre la entrada, la necesite (rara vez el caso) y sepa lo que está haciendo.

Si está utilizando pathlib Pathpara manipular archivos, es mejor utilizar la nueva API que ruamel.yaml proporciona:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)
Anthon
fuente
Hola @Anthon Estaba usando Ruamel pero tuve un problema con los documentos que no cumplen con ASCII ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Intenté establecer yaml.encoding en utf-8 pero no funcionó ya que el método de carga en YAML todavía usa el código ascii_decode. ¿Es esto un error?
SnwBr
27

Primero instale pyyaml ​​usando pip3.

Luego importe el módulo yaml y cargue el archivo en un diccionario llamado 'my_dict':

import yaml
with open('filename.yaml') as f:
    my_dict = yaml.safe_load(f)

Eso es todo lo que necesitas. Ahora todo el archivo yaml está en el diccionario 'my_dict'.

Camarada
fuente
66
¿Esto cierra el identificador de archivo?
yangmillstheory
2
Si su archivo contiene la línea "- hola mundo", es inapropiado llamar a la variable my_dict, ya que contendrá una lista. Si ese archivo contiene etiquetas específicas (comenzando por !!python), también puede ser inseguro (como en el disco duro completo) yaml.load(). Como eso está claramente documentado, debería haber repetido esa advertencia aquí (en casi todos los casos yaml.safe_load()se puede usar).
Anthon el
44
Usas import yaml, pero ese no es un módulo incorporado, y no especificas qué paquete es. Ejecutando import yamlen una nueva instalación de Python3 resultadosModuleNotFoundError: No module named 'yaml'
cowlinator
11

Ejemplo:


defaults.yaml

url: https://www.google.com

ambiente.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']
Prashanth Sams
fuente
¿Es seguro no cerrar la transmisión?
qrtLs
3

Yo uso ruamel.yaml . Detalles y debate aquí .

from ruamel import yaml

with open(filename, 'r') as fp:
    read_data = yaml.load(fp)

El uso de ruamel.yaml es compatible (con algunos problemas solucionables simples) con los viejos usos de PyYAML y, como se indica en el enlace que proporcioné, use

from ruamel import yaml

en vez de

import yaml

y solucionará la mayoría de tus problemas.

EDITAR : PyYAML no está muerto como resultado, solo se mantiene en un lugar diferente.

Oleksandr Zelentsov
fuente
@Oleksander: PyYaml se ha comprometido en los últimos 7 meses, y el último problema cerrado fue hace 12 días. ¿Puedes por favor definir "muerto hace mucho tiempo"?
abalter
@abalter Pido disculpas, parece que obtuve la información de su sitio oficial o de la publicación aquí stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov
@OleksandrZelentsov Puedo ver la confusión. Hubo un período muuuy largo cuando estuvo muerto. github.com/yaml/pyyaml/graphs/contributors . Sin embargo, su sitio está activo y muestra los comunicados publicados DESPUÉS de la publicación SO que se refiere a la desaparición de PyYaml. Por lo tanto, es justo decir que en este punto todavía está vivo, aunque su dirección con respecto a ruamel es claramente incierta. TAMBIÉN, hubo una larga discusión aquí con publicaciones recientes. Agregué un comentario, y ahora el mío es el único. Supongo que no entiendo cómo funcionan los problemas cerrados. github.com/yaml/pyyaml/issues/145
abalter
@abalter FWIW, cuando se publicó esa respuesta, había habido un total de 9 confirmaciones en el pasado ... poco menos de 7 años. Uno de ellos fue un "arreglo" automatizado de mala gramática. Dos involucraron el lanzamiento de una nueva versión apenas modificada. El resto fueron ajustes relativamente pequeños, en su mayoría hechos cinco años antes de la respuesta. Todos menos la solución automatizada fueron realizados por una persona. No juzgaría duramente esa respuesta por llamar a PyYAML "muerto hace mucho tiempo".
Financia la demanda de Mónica el
-1
#!/usr/bin/env python

import sys
import yaml

def main(argv):

    with open(argv[0]) as stream:
        try:
            #print(yaml.load(stream))
            return 0
        except yaml.YAMLError as exc:
            print(exc)
            return 1

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
Wojciech Sciesinski
fuente
1
Este código en realidad no hace nada. ¿Querías comentar el código?
Cowlinator