Во встроенном файле YAML json - замените только значения json с помощью Python

У меня есть файл 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. YAMl требует, чтобы } был с большим отступом, чем окружающий уровень, на котором существует annotations:. Вы не можете создать этот вывод с соответствующей реализацией YAML. Я знаю, что некоторые реализации YAML принимают это в качестве входных данных, но я совершенно уверен, что ни одна из них не создаст его.

flyx 06.05.2022 18:58
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
2
1
25
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

То, что у вас есть, это не 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

Другие вопросы по теме