Неверный формат (без символов новой строки) при загрузке YAML со встроенным JSON

Я пытаюсь разобрать ввод YAML из файла:

root: {
   children : { key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}
}

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

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 4096
yaml.indent(sequence=4, offset=2)

with open(yml_file, 'r') as file:
   print("Modifying file: '%s'..." % str(file))
   data = yaml.load(file)

data['root'][new_project_name.lower()] = {'key': "%s" % new_project_name.lower(),
                                                          'test_version': "{{ %s_version | default(\'1.0.0-SNAPSHOT\') }}"
                                                                     % new_project_name.lower()}

 with open(yml_file, 'w') as file:
       yaml.dump(data, file)

Дело в том, что когда файл пишется с новой записью, у меня все получается в одной строке, поэтому вроде не сохраняет новые строки (CR LF), (кажется загружает и без них) а у вас знаете, есть ли способ их сохранить?

вывод (все в одной строке):

root: {children : { key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}}

person galegofer    schedule 18.09.2018    source источник
comment
Проверьте вопрос stackoverflow.com/questions/24418449/pretty-output-with -пьямл. В ответах представлены возможные решения с pyyaml и ruamel.yaml   -  person Poolka    schedule 18.09.2018
comment
Ваш вывод является подделкой, он не может быть сгенерирован ни с одной из известных мне версий ruamel.yaml. В коде нет части, которая генерирует пробел между индикатором сопоставления и ключом, и, конечно же, нет кода, который иногда делает это (до key:), а иногда нет (до children:). Всегда предоставляйте рабочий код, чтобы мы могли видеть, что вы на самом деле делаете (неправильно), не хватает всего нескольких строк, чтобы можно было вырезать и вставить, зачем делать что-то неполным?   -  person Anthon    schedule 18.09.2018
comment
Вы правы, мне нужно было отредактировать вывод, чтобы показать вам концепцию, поэтому, вероятно, я сделал ошибку, к сожалению, я не могу использовать исходный код. В любом случае, вывод такой же без пробелов, как вы хорошо сказали.   -  person galegofer    schedule 19.09.2018


Ответы (1)


ruamel.yaml не сохраняет комментарии и не сохраняет интервалы внутри стиля. Если вы заботитесь о макете, чтобы ваш YAML было легче читать людям, вы должны использовать стиль потока максимально для листовых узлов, если вообще. Это стиль дампа по умолчанию при использовании YAML(typ='fast').

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

Установка уровня отступа влияет только на конструкции блочного стиля.

Вы должны изменить ввод только на стиль потока листового узла для лучшей читабельности:

root: 
   children: {key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}

Это загружает ту же структуру данных, что и ваш ввод.

Теперь вы можете сделать:

import sys
import ruamel.yaml

yml_file = 'input.yaml'
new_project_name = 'NPN'


yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 4096

with open(yml_file, 'r') as file:
   print("Modifying file: '%s'..." % str(file))
   data = yaml.load(file)

npn_lower = new_project_name.lower()

data['root'][npn_lower] = m = ruamel.yaml.comments.CommentedMap([
    ('key',  "%s" % npn_lower),
    ('test_version', "{{ %s_version | default(\'1.0.0-SNAPSHOT\') }}" % npn_lower)
])
m.fa.set_flow_style()

with open('output.yaml', 'w') as fp:
    yaml.dump(data, fp)

который печатает:

Modifying file: '<_io.TextIOWrapper name='input.yaml' mode='r' encoding='UTF-8'>'...

и имеет как output.yaml:

root:
  children: {key: "test-key", version: "{{ test_version | default( '1.0.0-SNAPSHOT' ) }}"}
  npn: {key: npn, test_version: "{{ npn_version | default('1.0.0-SNAPSHOT') }}"}

Что следует отметить:

  • добавьте CommentedMap, так как в обычном словаре вы не можете индивидуально установить стиль потока, и вам нужно это сделать, так как это больше не вложенный стиль потока. Элементы добавляются в виде списка кортежей, так как в более старых версиях Python порядок ключей не обязательно будет таким же, как в вашем вводе. Вы также создаете пустой CommentedMap() и добавляете пары ключ/значение по одной.

  • во время опробования (и с кодом, представленным здесь) всегда так же плохо менять входной файл, как и для каждого тестового прогона ваш ввод должен быть отменен.

person Anthon    schedule 18.09.2018