Como posso analisar um arquivo YAML em Python

611

Como posso analisar um arquivo YAML no Python?

Szymon Lipiński
fonte

Respostas:

806

O método mais fácil e puro, sem depender dos cabeçalhos C, é o PyYaml ( documentação ), que pode ser instalado 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)

E é isso. Uma yaml.load()função simples também existe, mas yaml.safe_load()sempre deve ser preferida, a menos que você precise explicitamente da serialização / desserialização arbitrária de objetos fornecida para evitar a introdução da possibilidade de execução arbitrária de código.

Observe que o projeto PyYaml suporta versões através da especificação YAML 1.1 . Se o suporte à especificação YAML 1.2 for necessário, consulte ruamel.yaml, conforme observado nesta resposta .

Jon
fonte
96
Eu acrescentaria que, a menos que você deseje serializar / desserializar objetos arbitrários, é melhor usá- yaml.safe_loadlo, pois ele não pode executar código arbitrário do arquivo YAML.
precisa saber é o seguinte
4
Yaml yaml = novo Yaml (); Objeto obj = yaml.load ("a: 1 \ nb: 2 \ nc: \ n - aaa \ n - bbb");
MayTheSchwartzBeWithYou
2
Eu gosto do artigo de moose: martin-thoma.com/configuration-files-in-python
SaurabhM
4
Você pode precisar instalar o pacote PyYAML primeiro pip install pyyaml, consulte esta publicação para obter mais opções stackoverflow.com/questions/14261614/…
Romain
7
Qual é o ponto de capturar a exceção neste exemplo? Ele será impresso de qualquer maneira, e isso apenas tornará o exemplo mais complicado.
naught101 22/01/19
116

Ler e gravar arquivos YAML com Python 2 + 3 (e 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)

Arquivo YAML criado

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

Finais de arquivos comuns

.yml e .yaml

Alternativas

Para seu aplicativo, o seguinte pode ser importante:

  • Suporte por outras linguagens de programação
  • Desempenho de leitura / escrita
  • Compacidade (tamanho do arquivo)

Consulte também: Comparação de formatos de serialização de dados

Caso você esteja procurando uma maneira de criar arquivos de configuração, leia meu pequeno artigo Arquivos de configuração em Python

Martin Thoma
fonte
Minha saída do Windows é €. Alguém sabe o motivo?
Cloud Cho
Que codificação possui o arquivo? Tem certeza de que está codificado em utf-8?
Martin Thoma
1
Obrigado pela sugestão. Meu arquivo tem codificação utf-8. Eu tive que mudar sua linha de código io.open(doc_name, 'r', encoding='utf8')para ler o caractere especial. YAML versão 0.1.7
Cloud Cho
Huh, interessante. Vou tentar reproduzir isso amanhã e, se puder, ajustarei a pergunta. Obrigado!
Martin Thoma
1
Você pode usar o built-in open(doc_name, ..., encodung='utf8')para leitura e gravação, sem importar io.
Dexteritas
62

Se você possui o YAML que está em conformidade com a especificação YAML 1.2 (lançada em 2009), use ruamel.yaml (isenção de responsabilidade: sou o autor desse pacote). É essencialmente um superconjunto do PyYAML, que suporta a maior parte do YAML 1.1 (de 2005).

Se você quiser preservar seus comentários ao percorrer o caminho, certamente deve usar o ruamel.yaml.

A atualização do exemplo de Jon é 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)

Use a safe_load()menos que você realmente tenha controle total sobre a entrada, precise dela (raramente é o caso) e saiba o que está fazendo.

Se você estiver usando o pathlib Pathpara manipular arquivos, é melhor usar a nova API que o ruamel.yaml fornece:

from ruamel.yaml import YAML
from pathlib import Path

path = Path('example.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)
Anthon
fonte
Olá @Anthon. Eu estava usando o ruamel's, mas tive um problema com documentos que não são compatíveis com ascii ( UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 926: ordinal not in range(128)). Eu tentei definir yaml.encoding como utf-8, mas não funcionou, pois o método de carregamento no YAML ainda usa o ascii_decode. Isso é um inseto?
SnwBr
27

Primeiro instale o pyyaml ​​usando o pip3.

Em seguida, importe o módulo yaml e carregue o arquivo em um dicionário chamado 'my_dict':

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

É tudo o que você precisa. Agora, o arquivo yaml inteiro está no dicionário 'my_dict'.

Amigo
fonte
6
Isso fecha o arquivo?
precisa saber é o seguinte
2
Se o seu arquivo contiver a linha "- olá mundo", é inapropriado chamar a variável my_dict, pois ela conterá uma lista. Se esse arquivo contiver tags específicas (começando com !!python), também poderá ser inseguro (como no disco rígido completo limpo) yaml.load(). Como isso está claramente documentado, você deve repetir esse aviso aqui (em quase todos os casos yaml.safe_load()podem ser usados).
Anthon
4
Você usa import yaml, mas esse não é um módulo interno e não especifica qual pacote é. A execução import yamlem uma nova instalação do Python3 resulta emModuleNotFoundError: No module named 'yaml'
cowlinator 19/11/19
11

Exemplo:


defaults.yaml

url: https://www.google.com

environment.py

from ruamel import yaml

data = yaml.safe_load(open('defaults.yaml'))
data['url']
Prashanth Sams
fonte
é salvar para não fechar o fluxo?
qrtLs
3

Eu uso ruamel.yaml . Detalhes e debate aqui .

from ruamel import yaml

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

O uso do ruamel.yaml é compatível (com alguns problemas simples solucionáveis) com os usos antigos do PyYAML e, conforme indicado no link fornecido, use

from ruamel import yaml

ao invés de

import yaml

e corrigirá a maioria dos seus problemas.

EDIT : PyYAML não está morto como se vê, apenas é mantido em um lugar diferente.

Oleksandr Zelentsov
fonte
@Oleksander: PyYaml foi confirmado nos últimos 7 meses, e a edição encerrada mais recente foi há 12 dias. Você pode definir "morto há muito tempo"?
abalter 20/03/19
@abalter Peço desculpas, parece que eu tenho a informação de seu site oficial ou o post aqui stackoverflow.com/a/36760452/5510526
Oleksandr Zelentsov
@OleksandrZelentsov Eu posso ver a confusão. Houve um longo período em que estava morto. github.com/yaml/pyyaml/graphs/contributors . No entanto, seu site está no ar e mostra lançamentos publicados APÓS o post SO, referente ao desaparecimento do PyYaml. Portanto, é justo dizer que, neste momento, ele ainda está vivo, embora sua direção em relação ao ruamel seja claramente incerta. Além disso, houve uma longa discussão aqui com posts recentes. Eu adicionei um comentário, e agora o meu é o único. Acho que não entendo como as questões fechadas funcionam. github.com/yaml/pyyaml/issues/145
abalter
@abalter FWIW, quando essa resposta foi postada, havia um total de 9 confirmações no passado ... pouco menos de 7 anos. Uma delas era uma "correção" automatizada de gramática ruim. Dois envolveram o lançamento de uma nova versão mal alterada. O resto foram pequenos ajustes, feitos principalmente cinco anos antes da resposta. Todos, exceto a correção automatizada, foram feitos por uma pessoa. Eu não julgaria essa resposta severamente por chamar o PyYAML de "morto há muito tempo".
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
fonte
1
Na verdade, esse código não faz nada. Você quis comentar o código?
cowlinator