Как я могу разобрать YAML в несколько compose.yaml на основе значения ключа с Python - PullRequest
1 голос
/ 01 апреля 2019

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

Это часть моего проекта, мне нужно разобрать и разделить на несколько разных файлов yaml, основываясь на значении ключа в файле yaml, который я получаю.

файл yaml, который я получаю, выглядит следующим образом

testname: testname
testall:
    test1:
        name: name1
        location: 0
    test2: 
        name: name2
        location: 2
    test3: 
        name: name3
        location: 0
    test4: 
        name: name4
        location: 2
    ...
locations:
    - 0
    - 2
    - ...  

Я хочу разобрать его и разбить по устройству следующим образом:

# location0.yaml
testname:test
tests:
    test1:
        name:test1
        location:0
    test3: 
        name: test3
        location: 0
# location2.yaml
testname:test
tests:
    test2:
        name:test2
        location:0
    test4: 
        name: test4
        location: 0

Как разобрать как выше форму?

1 Ответ

0 голосов
/ 01 апреля 2019

Хотя вы можете сделать это с PyYAML, вам придется ограничить себя в YAML 1.1. Для этого типа чтения-изменения-записи вы должны используйте ruamel.yaml (отказ от ответственности: я являюсь автором этого пакета). Не поддерживает только YAML 1.2, сохраняет комментарии, теги и якорные имена в случае, если они встречаются в вашем источнике и могут сохранить кавычки вокруг скаляров, буквального и сложенного стиля и т. д., если вам это нужно.

Также обратите внимание, что ваш вывод неверен YAML, вы не можете иметь многострочный (то есть без кавычек) скалярный ключ (стиль блока) отображение. Вам нужно написать:

"testname:test
tests":

но я предполагаю, что вы имели в виду два ключа для сопоставления корневого уровня:

testname: test
tests:

Предполагая, что ваш ввод в input.yaml:

testname: testname
testall:
    test1:
        name: name1    # this is just the first name
        location: 0
    test2: 
        name: "name2"  # quotes added for demo purposes
        location: 2
    test3: 
        name: name3    # as this has the same location as name1 
        location: 0    # these should be together
    test4: 
        name: name4    # and this one goes with name2
        location: 2
locations:
    - 0
    - 2

Вы можете сделать:

import sys
from pathlib import Path
import ruamel.yaml

in_file = Path('input.yaml')


yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=6, offset=4)  # this matches your input
yaml.preserve_quotes = True
data = yaml.load(in_file)

for loc in data['locations']:
    out_name = f'location{loc}.yaml'
    tests = {}
    d = ruamel.yaml.comments.CommentedMap(dict(testname="test", tests=tests))
    d.yaml_set_start_comment(out_name)
    testall = data['testall']
    for test in testall:
        if loc == testall[test]['location']:
           tests[test] = testall[test]
           tests[test]['location'] = 0
    # since you set location to zero and this affects data, make sure to remove 
    # the items. This will prevent things from going wrong in case the
    # locations sequence does have zero, but not as its first number
    for key in tests:
         del testall[key]
    yaml.dump(d, Path(out_name))

, что дает location0.yaml:

# location0.yaml
testname: test
tests:
    test1:
        name: name1    # this is just the first name
        location: 0
    test3:
        name: name3    # as this has the same location as name1 
        location: 0    # these should be together

и location2.yaml:

# location2.yaml
testname: test
tests:
    test2:
        name: "name2"  # quotes added for demo purposes
        location: 0
    test4:
        name: name4    # and this one goes with name2
        location: 0
...