Добавить несколько документов в файл 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.