Найти в Дзене
С любовью о Python

Работа с YAML-файлами с использованием библиотеки PyYAML

Оглавление

YAML - кто ты такой?

YAML (YAML Ain't Markup Language) - популярный формат для хранения данных, в особенности, конфигов. К примеру, конфигов для gitlab CI, для хуков линтеров в pre-commit описываются в YAML.

Формат легко читается, для восприятия легче, чем JSON, особенно когда структура сложная. Кроме того, YAML легко преобразуется в dict и с ним удобно работать через код.

Расширение файла может выглядеть и как ”.yml” и как “.yaml”, разницы нет.

Синтаксис и структура

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

-2

Итак, разберем детально что тут происходит:

  • строки. Можно писать как с кавычками ("integration") так и без (admin, localhost)
  • словари. Можно в одну строку: data: { ”key”: “value” }

можно блоками:

-3
  • списки. Можно в одну строку: ["slow", not bad"]

Можно указать каждый элемент на новой строке через дефис:

-4
  • якоря. Уникальная штука в YAML, которая позволяет избежать дублирования и дает возможность переиспользовать данные.

Для начала, якорь надо определить:

-5

а потом ссылаться на него в других местах конфига:

-6

и вместо этой ссылки будет подставлено значение host: localhost .

Чтение и запись YAML-файлов с помощью библиотеки PyYaml

PyYaml

Очень популярная библиотека для работы с YAML. Она не встроенная, потому нам надо ее установить:

pip install pyyaml

Чтение YAML-файлов

Чтобы распарсить YAML-файл в словарь Python, в PyYaml присутствует функция safe_load() . Есть еще функция load(), но ее не рекомендуется использовать с данными из непроверенных источников, т.к. она может вызывать любой код на Python.

Давайте создадим файл config.yml и сохраним туда наш конфиг.

Также создадим файл yaml_parser.py, где и будем реализовывать логику работы с YAML.

Напишем функцию для чтения конфига:

-7

Что здесь происходит:

  • С помощью библиотеки pathlib определяем текущую директорию (CWD) и путь до конфига (CONFIG_PATH)
  • Внутри функции def open_config() проверяем, что объект по указанному в аргументе config_path пути существует и является файлом. Если какое-то из этих условий не выполняется, вызываем исключение raise FileNotFoundError , страхуя себя от лишних ошибок
  • Далее открываем файл с помощью контекстного менеджера в режиме чтения, преобразуем наш конфиг в словарь и возвращаем его.

Посмотрим, что получится при вызове этой функции:

-8

Итак, все работает! Теперь наш конфиг преобразован в словарь и с ним можно работать в коде.

Согласитесь, если описывать конфиги именно в таком формате, то читать их будет посложнее, чем YAML.

Запись YAML-файлов

Ну и финальное. Попробуем обратную процедуру, преобразуем и запишем словарь в YAML-файл.

Попробуем обратно преобразовать тот же конфиг из dict в YAML, затем сравним файлы и убедимся, что данные идентичны. Поехали!

Напишем функцию для записи словаря в YAML-файл:

-9

Что здесь происходит:

  • Функция принимает имя нового файла, включая расширение (filename) и словарь, который будем преобразовывать и сохранять (data)
  • С помощью контекстного менеджера открываем (и создаем, если файла нет) файл в режиме записи
  • с помощью функции safe_dump() преобразовываем и сохраняем данные без сортировки по ключам

Вызовем функцию и посмотрим, что происходит:

-10

После выполнения кода, в той же директории рядом с исходным файлом будет создан файл new_config.yml с таким содержимым:

-11

Структура и данные абсолютно идентичны, мы справились с задачей!

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

Давайте убедимся, что наши файлы идентичны на все 100%. Откроем оба сохраненных конфига и проверим их на равенство с помощью assert :

-12

В случае неравенства будет вызвано исключение AssertionError с указанным текстом ошибки.

Этого не произошло, т.к. наши данные идентичны.

***

Присоединяйтесь ко мне в Telegram: https://t.me/python3_with_love. Там есть все, и читать код намного удобнее.