Добавить несколько документов в файл yaml | PyYAML

Я работаю над объектом, где первый питон читает YAML, вносит некоторые изменения и затем записывает их обратно в файл. Часть загрузки и обновления значений работает нормально, но когда я пишу файл, он создает списки, а не отдельные документы.

testing.yaml

apiVersion: v1
data:
  databag1: try this
  databag2: then try this
kind: ConfigMap
metadata:
  name: data bag info
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: data-bag-service
  name: data-bag-tagging

Блок кода

import yaml
with open("./testing.yaml", "r") as stream:
    deployment_dict= list(yaml.safe_load_all(stream))

print(deployment_dict)
with open("./testing.yaml", "w") as service_config:
    yaml.dump(
        deployment_dict,
        service_config,
        default_flow_style=False
    )

Преображение я получаю: testing.yaml

- apiVersion: v1
  data:
    databag1: try this
    databag2: then try this
  kind: ConfigMap
  metadata:
    name: data bag info
- apiVersion: extensions/v1beta1
  kind: Deployment
  metadata:
    labels:
      app: data-bag-service
    name: data-bag-tagging

Как я могу достичь исходного состояния с --- индикаторы конца директивы?

2 ответа

Согласно документам:

Если вам нужно выгрузить несколько документов YAML в один поток, используйте функцию yaml.dump_all, yaml.dump_all принимает список или генератор, производящий

yaml.dump_all(
    deployment_dict,
    service_config,
    default_flow_style=False
)

Тебе еще нужно default_flow_style=False чтобы получить вывод стиля блока.

Пример кода:

import yaml


with open("./testing.yaml", "r") as stream:
    d = list(yaml.safe_load_all(stream))

d.append(d[-1])

with open("./testing2.yaml", "w") as stream:
    yaml.dump_all(
        d,
        stream,
        default_flow_style=False
    )

testing2.yaml

apiVersion: v1
data:
  databag1: try this
  databag2: then try this
kind: ConfigMap
metadata:
  name: data bag info
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: data-bag-service
  name: data-bag-tagging
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: data-bag-service
  name: data-bag-tagging

PyYAML на самом деле не предназначен для выполнения таких двусторонних обновлений, он отбрасывает любые ваши комментарии и не обязательно сохраняет порядок ключей сопоставлений.

Я рекомендую вам взглянуть на ruamel.yaml (заявление об отказе: я являюсь автором этого пакета) по нескольким причинам, включая, но не ограничиваясь:

  • поддержка YAML 1.2 (но может писать / читать YAML 1.1 при необходимости)
  • сохранение комментариев, порядка ключей, имен якорей / псевдонимов, форматов с плавающей запятой / целых чисел
  • более точный контроль над отступами отображений и списков
  • не нужно загружать все документы, обрабатывать их и сбрасывать за один раз
  • необязательное сохранение кавычек и / или скаляров блочного стиля
  • безопасная загрузка по умолчанию и предупреждение при использовании небезопасных load в обратно совместимом API
  • много исправлений ошибок


from pathlib import Path
from ruamel.yaml import YAML

path = Path('testing.yaml')
tmp_path = path.with_suffix('.yaml.tmp')


with YAML(output=tmp_path) as yaml:
    # yaml.indent(mapping=4, sequence=4, offset=2)
    # yaml.preserve_quotes = True
    for data in yaml.load_all(path):
        # update data
        yaml.dump(data)

path.unlink()
tmp_path.rename(path)

print(path.read_text(), end='')

который дает:

apiVersion: v1
data:
  databag1: try this
  databag2: then try this
kind: ConfigMap
metadata:
  name: data bag info
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: data-bag-service
  name: data-bag-tagging

Обратите внимание, что вы не можете писать и читать из того же файла, который вы обрабатываете одновременно. Отсюда временный файл, который имеет дополнительное преимущество: если при обновлении этого последнего документа возникает ошибка и ваша программа падает, у вас не останется наполовину записанный поток YAML.

Другие вопросы по тегам