У меня есть файл YAML следующим образом:
api: v1
hostname: abc
metadata:
name: test
annotations: {
"ip" : "1.1.1.1",
"login" : "fad-login",
"vip" : "1.1.1.1",
"interface" : "port1",
"port" : "443"
}
Я пытаюсь прочитать эти данные из файла, только заменяю значения ip
и vip
и записываю обратно в файл.
Что я пробовал:
open ("test.yaml", w) as f:
yaml.dump(object, f) #this does not help me since it converts the entire file to YAML
также json.dump()
тоже не работает, так как он конвертирует весь файл в JSON. Он должен быть того же формата, но значения должны быть обновлены. Как я могу это сделать?
То, что у вас есть, это не YAML со встроенным JSON, это YAML с некоторым значением для annotations
в стиле потока YAML (который является надмножеством JSON и поэтому очень похож на него).
Это было бы YAML со встроенным JSON:
api: v1
hostname: abc
metadata:
name: test
annotations: |
{
"ip" : "1.1.1.1",
"login" : "fad-login",
"vip" : "1.1.1.1",
"interface" : "port1",
"port" : "443"
}
Здесь значение для annotations
— это строка, которую вы можете передать парсеру JSON.
Вы можете просто загрузить файл, изменить его и сделать дамп. Это изменит макет части в стиле потока, но это не повлияет на следующие парсеры:
import sys
import ruamel.yaml
file_in = Path('input.yaml')
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 1024
data = yaml.load(file_in)
annotations = data['metadata']['annotations']
annotations['ip'] = type(annotations['ip'])('4.3.2.1')
annotations['vip'] = type(annotations['vip'])('1.2.3.4')
yaml.dump(data, sys.stdout)
который дает:
api: v1
hostname: abc
metadata:
name: test
annotations: {"ip": "4.3.2.1", "login": "fad-login", "vip": "1.2.3.4", "interface": "port1", "port": "443"}
type(annotations['vip'])()
устанавливает, что строка замены в выводе имеет тот же
цитаты как оригинал.
ruamel.yaml
в настоящее время не сохраняет новые строки в отображении/последовательности стилей потока.
Если это должно вернуться в какой-то репозиторий с минимальными шансами, вы можете сделать:
import sys
import ruamel.yaml
file_in = Path('input.yaml')
def rewrite_closing_curly_brace(s):
res = []
for line in s.splitlines():
if line and line[-1] == '}':
res.append(line[:-1])
idx = 0
while line[idx] == ' ':
idx += 1
res.append(' ' * (idx - 2) + '}')
continue
res.append(line)
return '\n'.join(res) + '\n'
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.width = 15
data = yaml.load(file_in)
annotations = data['metadata']['annotations']
annotations['ip'] = type(annotations['ip'])('4.3.2.1')
annotations['vip'] = type(annotations['vip'])('1.2.3.4')
yaml.dump(data, sys.stdout, transform=rewrite_closing_curly_brace)
который дает:
api: v1
hostname: abc
metadata:
name: test
annotations: {
"ip": "4.3.2.1",
"login": "fad-login",
"vip": "1.2.3.4",
"interface": "port1",
"port": "443"
}
Здесь 15
для ширины, конечно, сильно зависит от вашего файла и может влиять на другие строки, если они
были длиннее. В этом случае вы можете оставить это и сделать обертку
что rewrite_closing_curly_brace()
разделяет и делает отступ всей части стиля потока.
Обратите внимание, что ваш исходный и преобразованный выходные данные являются недопустимыми YAML,
это принято ruamel.yaml
для обратной совместимости. Согласно ЯМЛ
спецификация, закрывающая фигурная скобка должна иметь отступ больше, чем начало annotation
Это недопустимый YAML. YAMl требует, чтобы
}
был с большим отступом, чем окружающий уровень, на котором существуетannotations:
. Вы не можете создать этот вывод с соответствующей реализацией YAML. Я знаю, что некоторые реализации YAML принимают это в качестве входных данных, но я совершенно уверен, что ни одна из них не создаст его.