Как прочитать компонент в файле YAML, чтобы я мог редактировать его значение ключа, используя ruamel.yaml? - PullRequest
0 голосов
/ 23 декабря 2018

Это мой файл YAML (input.yaml):

team_member:
  name: Max
  hobbies:
    - Reading

team_leader:
  name: Stuart
  hobbies:
    - dancing

Я хочу отредактировать этот файл YAML, чтобы добавить дополнительные значения в ключевые «хобби», например:

team_member:
  name: Max
  hobbies:
    - Reading
    - Painting

team_leader:
  name: Stuart
  hobbies:
    - Dancing
    - Fishing

Я пытался реализовать код Anthon , чтобы соответствовать моей ситуации, но это не помогло вообще, потому что уровень отступа этого файла YAML отличается от моего.
Пример:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()
# yaml.preserve_quotes = True
with open('input.yaml') as fp:
    data = yaml.load(fp)
for elem in data:
    if elem['name'] == 'Stuart':
         elem['hobbies'] = ['Fishing']
         break  # no need to iterate further
yaml.dump(data, sys.stdout)

Я получаю ошибку "TypeError ('строковые индексы должны быть целыми числами',)", я знаю, что этот код может быть полностью неверным, но я новичок в ruamel.yaml.

Как это кодировать?

Ответы [ 2 ]

0 голосов
/ 23 декабря 2018

Спасибо, Антон, твой код сработал, я должен отредактировать этот код следующим образом:

import sys
import ruamel.yaml
from pathlib import Path

yaml = ruamel.yaml.YAML()
path = Path('input.yaml')
yaml.indent(sequence=4, offset=2)  # for the non-default indentation of sequences
with open(path) as fp:
    data = yaml.load(fp)
for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         if len(value['hobbies']) == 1:
             value['hobbies'][0] = value['hobbies'][0].capitalize()
         value['hobbies'].append('Fishing')
    elif value['name'] == 'Max':
         last_item_index = len(value['hobbies']) - 1
         value['hobbies'].append('Painting')
         comments = value['hobbies'].ca
         if not comments.items[last_item_index][0].value.strip():
             # move empty comment lines from previous last item to new last item
             comments.items[last_item_index + 1] = comments.items.pop(last_item_index)
yaml.dump(data, path)
0 голосов
/ 23 декабря 2018

В отображаемом сообщении об ошибке отсутствует номер строки (я предполагаю, что это 9).Это указывает на строку

    if elem['name'] == 'Stuart':

И если это не дает вам подсказки, подход, который я рекомендую в таких случаях, начинает добавлять некоторые print функции, чтобы вы знали, что выработа над.Цикл for выглядит следующим образом:

for elem in data:
    print('elem', elem)
    if elem['name'] == 'Stuart':
         print('elem->hobbies', elem['hobbies'])
         elem['hobbies'] = ['Fishing']

это печатает

 elem team_member

до того, как будет сгенерировано исключение, и я надеюсь, что вы поймете, что вы не выполняете итерации по elem ents (элементы) списка, но поверх ключа s dict (созданного из сопоставления корневого уровня в вашем YAML).И значение , связанное с ключом, является объектом, имеющим ключ name и ключ hobbies.

. Поэтому измените переменную elem на key, чтобы выяснить, чтовы обрабатываете, а затем приступаете к работе с value, значением, связанным с этим ключом вместо elem в этом цикле¹:

for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         print('value->hobbies', value['hobbies'])
         value['hobbies'] = ['Fishing']

Это дает:

value->hobbies ['dancing']
team_member:
  name: Max
  hobbies:
  - Reading

team_leader:
  name: Stuart
  hobbies:
  - Fishing

Таким образом, мы избавились от исключения, но результат не совсем то, что вы хотите.Элемент dancing для ключа 'хобби' пропал, потому что вы назначаете этому ключу новое (список) значение, в то время как вам нужно добавить один элемент в список.Теперь мы также можем избавиться от функции печати:

for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         value['hobbies'].append('Fishing')

Это даст вам два элемента в последней последовательности в файле.Есть еще несколько вещей для решения:

  • заглавная буква dancing неверна.Чтобы исправить это, добавьте строку, обрабатывающую список, если есть только один элемент
  • , необходимо добавить код для имени Max (и именно поэтому вам нужно избавиться от breakв вашем коде)
  • пустая строка, считается комментарием к последнему элементу первой последовательности, этот комментарий необходимо переместить
  • Ваш отступ последовательностей не по умолчанию

Окончательный код будет выглядеть так:

from pathlib import Path
import ruamel.yaml

path = Path('input.yaml')
yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)  # for the non-default indentation of sequences

data = yaml.load(path)
for key in data:
    value = data[key]
    if value['name'] == 'Stuart':
         if len(value['hobbies']) == 1:
             value['hobbies'][0] = value['hobbies'][0].capitalize()
         value['hobbies'].append('Fishing')
    elif value['name'] == 'Max':
         last_item_index = len(value['hobbies']) - 1
         value['hobbies'].append('Painting')
         comments = value['hobbies'].ca
         if not comments.items[last_item_index][0].value.strip():
             # move empty comment lines from previous last item to new last item
             comments.items[last_item_index + 1] = comments.items.pop(last_item_index)

yaml.dump(data, path)

Что дает что-то очень близкое к тому, что вы хотели получить

team_member:
  name: Max
  hobbies:
    - Reading
    - Painting

team_leader:
  name: Stuart
  hobbies:
    - Dancing
    - Fishing

¹ Альтернативадля первых двух строк: for key, value in data.items()

...