Python: замена строки в файле YAML - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть пример файла YAML:

---
test:
  name: "Tom"
  age: "5"
  version: "1.0"

Как мне заменить этот файл YAML на:


test:
  name: "Max"
  age: "10"
  version: "2.2"

Вот как я открываю файл:

import yaml

with open("config.yml", 'r') as stream:
        print(yaml.load(stream))

Но я понятия не имею, как редактировать файл YAML сейчас.

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Если вы прочитаете документацию PyYAML, вы увидите, что она говорит вам, что использование функции load() потенциально опасно, поэтому первое, что нужно сделать (так как вам и почти всем остальным это не нужно),не использует это, но вместо этого использует safe_load().

Вы также должны изменить свой входной файл на config.yaml, рекомендуемое расширение для файлов YAML было .yaml с 2006 года.

Зная это, способ изменить файл config.yaml с помощью PyYAML:

import yaml

with open('config.yaml') as stream:
   data = yaml.safe_load(stream)

test = data['test']
test.update(dict(name="Tom", age="10", version="2.2"))

with open('output.yaml', 'wb') as stream:
   yaml.safe_dump(data, stream, default_flow_style=False, 
                  explicit_start=True, allow_unicode=True, encoding='utf-8')

Это даст вам output.yaml, который выглядит следующим образом:

---
test:
  age: '10'
  name: Tom
  version: '2.2'

Параметр default_flow_style необходим, чтобы не получить JSON-подобную структуру для отображения вашего конечного узла.explicit_start, чтобы получить индикатор окончания ведущих директив (---), и я рекомендую всегда использовать allow_unicode=True, encoding='utf-8' (и открывать файл как двоичный файл), чтобы избежать неожиданностей или проблем при изменении name наBjörk Guðmundsdóttir.

Теперь, как вы заметите, это не генерирует желаемый результат (хотя семантически тот же):

  • одинарные кавычки вместо двойных кавычек вокругстроки, которые можно интерпретировать как числа
  • без двойных кавычек вокруг Tom
  • сортировка ключей вашего сопоставления

Если у вас есть какие-либо комментарии в YAMLфайл, они были бы потеряны.

Лучшим способом обновления YAML-файлов является использование ruamel.yaml (отказ от ответственности: я являюсь автором этого пакета), который имеет несколько более значительных значений по умолчанию, чем PyYAML, обрабатывает YAML 1.2 и не пропускает комментарии (есливы должны иметь их в своем файле):

import ruamel.yaml


yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.explicit_start = True

with open('config.yaml') as stream:
   data = yaml.load(stream)

test = data['test']
test.update(dict(name="Tom", age="10", version="2.2"))

with open('output.yaml', 'wb') as stream:
    yaml.dump(data, stream)

с этим ваш выходной файл будет:

---
test:
  name: "Tom"
  age: "10"
  version: "2.2"

, что именно то, что вы хотели.

0 голосов
/ 21 февраля 2019

Учитывая тот факт, что вы используете PyYaml, подходящий способ сделать это выглядит так:

#!/usr/bin/env python

import yaml

with open("testfile.yaml", 'r') as stream:
    try:
        loaded = yaml.load(stream)
    except yaml.YAMLError as exc:
        print(exc)

# Modify the fields from the dict
loaded['test']['name'] = "Max"
loaded['test']['age'] = "10"
loaded['test']['version'] = "2.2"

# Save it again
with open("modified.yaml", 'w') as stream:
    try:
        yaml.dump(loaded, stream, default_flow_style=False)
    except yaml.YAMLError as exc:
        print(exc)

Таким образом, вы просто загружаете yaml в dict с именем loaded, вы изменяетеЗначения, которые вам нужны, затем сохраните его (перезаписать исходный файл или нет, ваш вызов).Для вложенного ввода у вас будет вложенный запрос, который вы должны будете изменить.Параметр default_flow_style=False необходим для создания необходимого формата (стиль потока), в противном случае для вложенных коллекций он создает стиль блока:

A: a
B: {C: c, D: d, E: e}

Cheers!

Позднее редактирование :

Как указал Антон, в моем ответе есть некоторые недостатки.

  • Лучше использовать safe_load вместо load, так как последнее потенциально опасно.

  • Для выхода требуется указатель конца директивы (эти три черточки в начале).Чтобы добавить их, мы используем explicit_start=True в методе dump (который на самом деле должен быть safe_dump).

  • Используйте возможно ruamel.yaml вместо yaml, если выхотите получить лучший вывод (хотя они семантически одинаковы)

См. ответ Энтона для получения более подробной информации, так как он является автором пакета.

...