Файлы, которые содержат один или несколько документов YAML (короче: файл YAML, который, начиная с сентября 2006 года, рекомендуется иметь расширение .yaml
), являются текстовыми файлами и могут быть объединены из частей как таковые.Единственное требование состоит в том, чтобы в конце концов у вас был текстовый файл, который является действительным файлом YAML.
Самым простым является, конечно, иметь верхний и нижний колонтитулы в отдельных файлах для этого, но, как вы говорите о несколькихФайлы YAML это скоро становится громоздким.Однако всегда можно выполнить базовый анализ содержимого файла.
Поскольку ваша рабочая часть начинается с Resource:
, и вы указываете 3 списка или словаря (у вас не может быть трех строк в корне YAMLдокумент).Структура данных корневого уровня вашего документа YAML должна быть либо mapping , а все остальное, кроме ключей для этого отображения, должно иметь отступ (теоретически, нужно только больше отступать, нона практике это почти всегда означает, что ключи не имеют отступов), например (m.yaml
):
# header
a: 1
b:
- 2
- c: 3 # end of header
Resource:
# footer
c:
d: "the end" # really
или корневой уровень должен быть последовательностью (s.yaml
):
# header
- a: 1
b:
- 2
- c: 3
- 42 # end of header
- Resource:
# footer
- c:
d: "the end" # really
оба могут быть легко разделены без загрузки YAML, вот пример кода для этого для файла с отображением корневого уровня:
from pathlib import Path
from ruamel.yaml import YAML
inf = Path('m.yaml')
header = [] # list of lines
resource = []
footer = []
for line in inf.open():
if not resource:
if line.startswith('Resource:'): # check if we are at end of the header
resource.append(line)
continue
header.append(line)
continue
elif not footer:
if not line or line[0] == ' ': # still in the resource part
resource.append(line)
continue
footer.append(line)
# you now have lists of lines for the header and the footer
# define the new data structure for the resource this is going to be a single key/value dict
upd_resource = dict(Resource=['some text', 'for the resource spec', {'a': 1, 'b': 2}])
# write the header lines, dump the resource lines, write the footer lines
outf = Path('out.yaml')
with outf.open('w') as out:
out.write(''.join(header))
yaml = YAML()
yaml.indent(mapping=2, sequence=2, offset=0) # the default values
yaml.dump(upd_resource, out)
out.write(''.join(footer))
print(outf.read_text())
это дает:
# header
a: 1
b:
- 2
- c: 3 # end of header
Resource:
- some text
- for the resource spec
- a: 1
b: 2
# footer
c:
d: "the end" # really
То же самое при разборе файла YAML не сложнее.Следующее автоматически обрабатывает оба случая (независимо от того, является ли корневой уровень отображением или последовательностью):
from pathlib import Path
from ruamel.yaml import YAML
inf = Path('s.yaml')
upd_resource_val = ['some text', 'for the resource spec', {'a': 1, 'b': 2}]
outf = Path('out.yaml')
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=2, sequence=2, offset=0)
yaml.preserve_quotes = True
data = yaml.load(inf)
if isinstance(data, dict):
data['Resource'] = upd_resource_val
else: # assume a list,
for item in data: # search for the item which has as value a dict with key Resource
try:
if 'Resource' in item:
item['Resource'] = upd_resource_val
break
except TypeError:
pass
yaml.dump(data, outf)
Это создает следующее out.yaml
:
# header
- a: 1
b:
- 2
- c: 3
- 42 # end of header
- Resource:
- some text
- for the resource spec
- a: 1
b: 2
# footer
- c:
d: "the end" # really
Если m.yaml
файл был входным, выходной был бы точно таким же, как и в текстовом примере кода «конкатенации».