Как обновить файл 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