Comment puis-je analyser un fichier YAML en Python

611

Comment analyser un fichier YAML en Python?

Szymon Lipiński
la source

Réponses:

806

La méthode la plus simple et la plus pure sans compter sur les en-têtes C est PyYaml ( documentation ), qui peut être installée via 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)

Et c'est tout. Une yaml.load()fonction simple existe également, mais yaml.safe_load()devrait toujours être préférée, sauf si vous avez explicitement besoin de la sérialisation / désérialisation arbitraire d'objet fournie afin d'éviter d'introduire la possibilité d'exécution de code arbitraire.

Notez que le projet PyYaml prend en charge les versions jusqu'à la spécification YAML 1.1 . Si la prise en charge de la spécification YAML 1.2 est nécessaire, voir ruamel.yaml comme indiqué dans cette réponse .

Jon
la source
96
J'ajouterais qu'à moins que vous ne souhaitiez sérialiser / désérialiser des objets arbitraires, il est préférable de l'utiliser yaml.safe_loadcar il ne peut pas exécuter de code arbitraire à partir du fichier YAML.
ternaryOperator
4
Yaml yaml = nouveau Yaml (); Objet obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou
2
J'aime l'article de moose: martin-thoma.com/configuration-files-in-python
SaurabhM
4
Vous devrez peut-être d'abord installer le package PyYAML pip install pyyaml, consultez cet article pour plus d'options stackoverflow.com/questions/14261614/…
Romain
7
Quel est l'intérêt de capturer l'exception dans cet exemple? Cela va s'imprimer de toute façon, et cela rend l'exemple plus compliqué ..
naught101
116

Lire et écrire des fichiers YAML avec Python 2 + 3 (et 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)

Fichier YAML créé

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

Terminaisons de fichiers communes

.yml et .yaml

Alternatives

Pour votre application, les éléments suivants peuvent être importants:

  • Prise en charge par d'autres langages de programmation
  • Lecture / écriture
  • Compacité (taille du fichier)

Voir aussi: Comparaison des formats de sérialisation des données

Dans le cas où vous cherchez plutôt un moyen de créer des fichiers de configuration, vous voudrez peut-être lire mon court article Fichiers de configuration en Python

Martin Thoma
la source
Ma sortie de sur Windows est €. Quelqu'un connaît la raison?
Cloud Cho
Quel encodage le fichier a-t-il? Vous êtes sûr qu'il est encodé en utf-8?
Martin Thoma
1
Merci pour la suggestion. Mon fichier a un encodage utf-8. J'ai dû changer votre ligne de code io.open(doc_name, 'r', encoding='utf8')pour lire le caractère spécial. YAML version 0.1.7
Cloud Cho
Huh, intéressant. J'essaierai de reproduire cela demain et ajusterai la question si je peux. Je vous remercie!
Martin Thoma
1
Vous pouvez utiliser le intégré open(doc_name, ..., encodung='utf8')pour lire et écrire, sans importer io.
dexteritas
62

Si vous avez YAML conforme à la spécification YAML 1.2 (publiée en 2009), vous devez utiliser ruamel.yaml (avertissement: je suis l'auteur de ce package). Il s'agit essentiellement d'un sur-ensemble de PyYAML, qui prend en charge la plupart de YAML 1.1 (à partir de 2005).

Si vous voulez pouvoir conserver vos commentaires lors d'un aller-retour, vous devez certainement utiliser ruamel.yaml.

La mise à niveau de l'exemple de @ Jon est simple:

import ruamel.yaml as yaml

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

À utiliser safe_load()sauf si vous avez vraiment un contrôle total sur l'entrée, en avez besoin (rarement le cas) et savez ce que vous faites.

Si vous utilisez pathlib Pathpour manipuler des fichiers, il vaut mieux utiliser la nouvelle API ruamel.yaml fournit:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)
Anthon
la source
Bonjour @Anthon. J'utilisais Ruamel's mais j'ai eu un problème avec des documents qui ne sont pas conformes à ASCII ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). J'ai essayé de définir yaml.encoding sur utf-8 mais je n'ai pas fonctionné car la méthode de chargement dans YAML utilise toujours l'ascii_decode. Est-ce un bug?
SnwBr
27

Installez d'abord pyyaml ​​à l'aide de pip3.

Importez ensuite le module yaml et chargez le fichier dans un dictionnaire appelé 'my_dict':

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

C'est tout ce dont vous avez besoin. Maintenant, le fichier yaml entier est dans le dictionnaire 'my_dict'.

Copain
la source
6
Est-ce que cela ferme le descripteur de fichier?
yangmillstheory
2
Si votre fichier contient la ligne "- hello world", il est inapproprié d'appeler la variable my_dict, car elle va contenir une liste. Si ce fichier contient des balises spécifiques (en commençant par !!python), il peut également être dangereux (comme dans un disque dur complet nettoyé) à utiliser yaml.load(). Comme cela est clairement documenté, vous devriez avoir répété cet avertissement ici (dans presque tous les cas, vous yaml.safe_load()pouvez l'utiliser).
Anthon
4
Vous utilisez import yaml, mais ce n'est pas un module intégré, et vous ne spécifiez pas de quel package il s'agit. L'exécution import yamld'une nouvelle installation de Python3 se traduit parModuleNotFoundError: No module named 'yaml'
cowlinator
11

Exemple:


defaults.yaml

url: https://www.google.com

environment.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']
Prashanth Sams
la source
est-il possible de ne pas fermer le flux?
qrtLs
3

J'utilise ruamel.yaml . Détails et débat ici .

from ruamel import yaml

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

L'utilisation de ruamel.yaml est compatible (avec quelques problèmes simples résolubles) avec les anciennes utilisations de PyYAML et comme il est indiqué dans le lien que j'ai fourni, utilisez

from ruamel import yaml

au lieu de

import yaml

et cela résoudra la plupart de vos problèmes.

EDIT : PyYAML n'est pas mort comme il se trouve, il est juste maintenu dans un endroit différent.

Oleksandr Zelentsov
la source
@Oleksander: PyYaml a effectué des validations au cours des 7 derniers mois, et le dernier problème clos remonte à 12 jours. Pouvez-vous définir "mort depuis longtemps"?
abalter
@abalter Je m'excuse, il semble que j'ai obtenu les informations de leur site officiel ou du post ici stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov
@OleksandrZelentsov Je peux voir la confusion. Il y a eu une longue période où il était mort. github.com/yaml/pyyaml/graphs/contributors . Cependant, leur site est en place et affiche des versions publiées APRÈS la publication SO faisant référence à la disparition de PyYaml. Il est donc juste de dire qu'à ce stade, il est toujours vivant, bien que sa direction par rapport au ruamel soit clairement incertaine. AUSSI, il y a eu une longue discussion ici avec des articles récents. J'ai ajouté un commentaire, et maintenant le mien est le seul. Je suppose que je ne comprends pas comment fonctionnent les problèmes fermés. github.com/yaml/pyyaml/issues/145
abalter
@abalter FWIW, lorsque cette réponse a été publiée, il y avait eu un total de 9 commits dans le passé ... un peu moins de 7 ans. L'un d'eux était une «correction» automatisée de mauvaise grammaire. Deux impliquaient la publication d'une nouvelle version à peine modifiée. Le reste était des ajustements relativement minuscules, principalement effectués cinq ans avant la réponse. Tous, sauf la correction automatisée, ont été effectués par une seule personne. Je ne jugerais pas durement cette réponse pour avoir qualifié PyYAML de "mort depuis longtemps".
Fund Monica's Lawsuit
-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
la source
1
Ce code ne fait rien. Vouliez-vous commenter le code?
Cowlinator