Как обновить файл yaml с помощью python

У меня есть файл some.yaml с содержимым ниже.

    init_config: {}
    instances:
        - host: <IP>
          username: <username>
          password: <password>

Файл yaml должен быть проанализирован и обновлен, как показано ниже.

    init_config: {}
    instances:
        - host: 1.2.3.4
          username: Username
          password: Password

Как я могу проанализировать значения и соответствующим образом обновить их?

Ответ 1

Пакет ruamel.yaml был специально улучшен (мной, начиная с PyYAML), для выполнения такого рода циклического, программного обновления и обновления.

Если вы начинаете с (обратите внимание, я удалил лишние начальные пробелы):

init_config: {}
instances:
    - host: <IP>              # update with IP
      username: <username>    # update with user name
      password: <password>    # update with password

и запустить:

import ruamel.yaml

file_name = 'input.yaml'
config, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(open(file_name))

instances = config['instances']
instances[0]['host'] = '1.2.3.4'
instances[0]['username'] = 'Username'
instances[0]['password'] = 'Password'

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

Выход будет:

init_config: {}
instances:
    - host: 1.2.3.4           # update with IP
      username: Username      # update with user name
      password: Password      # update with password

Порядок ключей сопоставления (host, username и password), стиль и комментарии сохраняются без каких-либо дополнительных действий.

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

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=6, sequence=4)
with open(file_name) as fp:
    config = yaml.load(fp)

Если вы посмотрите историю этого ответа, вы увидите, как это сделать с помощью более ограниченного, похожего на PyYAML, API.

Ответ 2

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

import yaml

fname = "some.yaml"

stream = open(fname, 'r')
data = yaml.load(stream)

data['instances'][0]['host'] = '1.2.3.4'
data['instances'][0]['username'] = 'Username'
data['instances'][0]['password'] = 'Password'

with open(fname, 'w') as yaml_file:
    yaml_file.write( yaml.dump(data, default_flow_style=False))

Ответ 3

Я не знаю, нужен ли вам YAML. Помимо использования тега YAML, кажется, что вы не заинтересованы в документе YAML. Так почему бы не использовать Jinja2 или какой-либо язык шаблонов?

from jinja2 import Template

tmpl = Template(u'''\
    init_config: {}
    instances:
         - host: {{ IP }}
           username: {{ username }}
           password: {{ password }}
''')

print tmpl.render(
     IP=u"1.2.3.4",
     username=u"Username",
     password=u"Password"
)

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


Бонус: Случай использования

Я работал с очень сложными документами YAML, для которых есть неизвестные теги

...
  propertiesIDs: { 1, 2, 3, 4 }
  globalID: !myapplication.InterfaceID &primitiveID

replication: !myapplication.replication
  beginDate: 2012-09-10T20:00:03
  endDate: 2020-09-10T20:00:04
  replicant_uuid:
    ? 17169504-B6AB-11E4-8437-36E258BB2172
    ? 206B5842-B6AB-11E4-AAC3-36E258BB2172
...

Выполнение правильного анализа этого документа является сложным и трудоемким. Мне нужно только заполнить некоторые значения, а YAML отправляется стороннему приложению. Поэтому вместо анализа YAML или попытки создать действительный документ напрямую с помощью pyyaml ​​проще (более экономично, менее подвержено ошибкам), чтобы сгенерировать его непосредственно через шаблоны. Кроме того, языки шаблонов могут быть легко использованы с циклами для заполнения полей с динамическим размером.

Ответ 4

Вот как я создаю шаблоны док-кранов для dev, production, stage и т.д.

  • mkdir crane_templates
  • touch crane_templates/ init.py
  • Добавить содержимое шаблона с помощью nano crane_templates/some.yaml
  • Nano crane_gen.py

--- crane_gen.py ---

#!/usr/bin/env python
from jinja2 import Environment, PackageLoader

env = Environment(loader=PackageLoader('crane_templates', './'))
tmpl = env.get_template('crane.yaml.tmpl')

result = tmpl.render(
     IP=u"1.2.3.4",
     username=u"Username",
     password=u"Password"
)

5. python crane_gen.py > result.yaml

Ответ, вдохновленный @MariusSiuram

Ответ 5

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

import yaml

s = """
    init_config: {}
    instances:
        - host: <IP>
          username: <username>
          password: <password>
"""

dict_obj = yaml.load(s) # loads string in internal data structure - dict
dict_obj['instances'][0]['host'] = 'localhost' # change values
print yaml.dump(dict_obj) # dumps dict to yaml format back