Я использую ruamel.yaml для редактирования файлов YAML и их дампа. Мне нужна помощь в том, как сохранить структуру исходного файла,
У меня есть файл YAML с содержимым ниже, однако это содержимое не изменяется, но когда я загружаю и выгружаю его после редактирования, структура этого содержимого меняется
parameters: {
"provision_pipeline": "provision-integrations",
"enable_sfcd_ds_argo_operator": "false",
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"
}
Однако после того, как я выгружу, структура этого изменится на следующий формат:
parameters: {"provision_pipeline": "provision-integrations", "enable_sfcd_ds_argo_operator": "false",
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"}
Код:
def addTargetToBaseIntegFileAndUpdate(deploymentTarget, fi, env, samvmf_repo, folder, pipelineversionintegration, basefile):
yamldata = OrderedDict()
ryaml = rumel.yaml.YAML()
ryaml.preserve_quotes = True
ryaml.default_flow_style = False
ryaml.indent(mapping=2)
with open(basefile, "r") as file:
yamldata = ryaml.load(file)
deploymentTargets = yamldata["targets"]["stagger_groups"]
target = ""
doesFIExist = False
fi_index = 0
for index, sg in enumerate(deploymentTargets):
if sg["name"] == env.lower():
target = deploymentTargets[index]
for i, fi_item in enumerate(target["falcon_instances"]):
if fi_item["name"] == fi.lower():
fi_index = i
doesFIExist = True
break
if doesFIExist:
yamldata["targets"]["stagger_groups"][index]["f_instances"][fi_index]["f_domains"].append(deploymentTarget["f_instances"][0]["f_domains"][0])
else:
yamldata["targets"]["stagger_groups"][index]["f_instances"].append(deploymentTarget["f_instances"][0])
break
with open(basefile, "w") as fileobj:
ryaml.dump(yamldata, fileobj)
У вас есть два сопоставления в вашем YAML, одно с одним ключом (parameters
) и одно с тремя ключами (provision_pipeline
) и т. д. Первое сопоставление — это блочный стиль, второе — стиль потока. Какая программа заставляет вас сохранять это несоответствие?
Как указал Ник Бейли в комментариях, это стилистическое изменение, а не структурное. То есть данные одни и те же, просто представлены по-разному.
Теперь, что касается этого стиля, YAML имеет два стиля представления структур данных:
Стиль блока: Каждый ключ/значение начинается с новой строки, а списки и словари (сопоставления) запускаются и останавливаются с помощью отступа. Обычно это предпочтительный стиль, так как он более удобочитаем.
Стиль потока: списки/сопоставления начинаются и заканчиваются квадратными скобками, а несколько ключей/значений разделяются запятыми, как в JSON. Разрывы строк не требуются между парами ключ/значение, но также не запрещены. Этот формат чаще используется для небольших и простых структур данных, особенно в одной строке, поскольку он может сэкономить место.
Исходный YAML, который вы показали, представляет собой одну пару ключ/значение в более крупном отображении блочного стиля, но само значение имеет блочный стиль не; это просто стиль потока с добавлением дополнительных разрывов строк. Я думаю, вы, вероятно, захотите этого, полностью в блочном стиле:
test:
parameters:
"provision_pipeline": "provision-integrations"
"enable_sfcd_ds_argo_operator": "false"
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"
ruamel.yaml в режиме по умолчанию (туда и обратно) сохраняет стиль потока или блока, в зависимости от того, что вы ему зададите, но я не знаю, как заставить его запоминать определенные разрывы строк, которые вы добавили в разделе потока. Посмотрите это сравнение:
import sys
from ruamel.yaml import YAML
yaml_string_1 = """\
test:
parameters: {
"provision_pipeline": "provision-integrations",
"enable_sfcd_ds_argo_operator": "false",
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"
}
"""
yaml_string_2 = """\
test:
parameters:
"provision_pipeline": "provision-integrations"
"enable_sfcd_ds_argo_operator": "false"
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"
"""
yaml = YAML()
for yaml_string in [yaml_string_1, yaml_string_2]:
output = yaml.load(yaml_string)
yaml.dump(output, sys.stdout)
print()
Выход:
test:
parameters: {provision_pipeline: provision-integrations, enable_sfcd_ds_argo_operator: 'false',
clustermanagement_helm_values_path: sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml}
test:
parameters:
provision_pipeline: provision-integrations
enable_sfcd_ds_argo_operator: 'false'
clustermanagement_helm_values_path: sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml
Вы также можете, конечно, добавить preserve_quotes
и любые другие опции, которые вам нужны.
Оригинальный YAML не является потоковым. Это блочный стиль для сопоставления корневого уровня (с одним ключом parameters
) и стиль потока для сопоставления, которое является значением этого ключа.
Спасибо, что указали на мою двусмысленность, уточню.
Я не хотел быть педантичным. Но это кажется значительным, так как я понимаю проблему, если OP обрабатывает данные дальше, например. анализатор JSON, который понимает только полный стиль потока. Но это наполовину, так что на самом деле нет четкой причины, почему бы не сделать его полностью блочным, как вы предлагаете.
ruamel.yaml
не сохраняет новые строки между элементами сопоставления стилей потока. Единственное
на них влияет yaml.width
, поэтому вы получаете перенос строк, которые становятся слишком длинными.
Например. с вашим вводом, если вы установите ширину на 40, вы получите:
parameters: {"provision_pipeline": "provision-integrations",
"enable_sfcd_ds_argo_operator": "false",
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"}
Но нет элемента управления, который даст вам первую пару ключ-значение на новой строке или закрытие. фигурная скобка на отдельной строке.
Ваше добавление ryaml.default_flow_style = False
влияет только на совершенно новые диктовки и списки, которые вы добавляете в
структура данных.
Вам следует подумать о переходе на блочный стиль и отбросить все несущественные кавычки, что делает YAML и менее подробный, и более читаемый. Для программы, которая загружает данные, это не имеет значения, и преобразование легко выполняется путем загрузки в обычном безопасном режиме (который не устанавливает информацию о блочном/потоковом стиле). на загруженных данных):
import sys
import pathlib
import ruamel.yaml
basefile = pathlib.Path('input.yaml')
data = ruamel.yaml.YAML(typ='safe').load(basefile)
yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)
который дает:
parameters:
provision_pipeline: provision-integrations
enable_sfcd_ds_argo_operator: 'false'
clustermanagement_helm_values_path: sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml
Строковый скаляр 'false'
должен быть заключен в кавычки, чтобы его не путали с логическим значением false
.
Если вышеуказанное улучшение неприемлемо, т.е. если дальнейшая обработка выполняется с чем-то кроме полного синтаксического анализатора YAML, вы можете выполнить постобработку вывода:
import sys
import pathlib
import ruamel.yaml
basefile = pathlib.Path('input.yaml')
def splitflowmap(s):
res = []
for line in s.splitlines():
if ': {' in line and line[-1] == '}':
start, rest = line.split(': {', 1)
start = start + ': {'
indent = ' ' # two spaces more than the start
for idx, ch in enumerate(start):
if ch != ' ':
break
indent += ' '
res.append(start)
rest = rest[:-1] # cut of }\n
for x in rest.split(', '): # if you always have quotes it is safer to split on '", "'
res.append(f'{indent}{x},')
res[-1] = res[-1][:-1] # delete trailing comma
res.append(f'{indent[2:]}}}') # re-add the cut of }\n on a line of its own
continue
res.append(line)
return '\n'.join(res) + '\n'
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 2**16
data = yaml.load(basefile)
yaml.dump(data, sys.stdout, transform=splitflowmap)
который дает:
parameters: {
"provision_pipeline": "provision-integrations",
"enable_sfcd_ds_argo_operator": "false",
"clustermanagement_helm_values_path": "sam/sam-helm-charts/kube-node-recycler-0.0.4-273/values.nodepool.yaml"
}
Это не структурное изменение, это просто изменение форматирования. Я не знаком с тем, какие параметры форматирования предлагает ruamel.yaml, но вам нужно изучить это, чтобы контролировать форматирование выходных пробелов.