Используйте Python для анализа файлов конфигурации
Первый шаг — выбор формата конфигурации: INI, JSON, YAML или TOML.
Иногда программе требуется достаточное количество параметров, и помещать их все в качестве аргументов командной строки или переменных среды неприятно и невозможно. В этих случаях вам понадобится использовать файл конфигурации.
Существует несколько популярных форматов файлов конфигурации. Среди них почтенный (хотя иногда и недоопределенный) формат INI
, популярный, но иногда трудный для написания вручную формат JSON
, обширный, но иногда удивляющий в деталях формат YAML
и новейшее дополнение TOML
, о котором многие еще не слышали.
Ваша первая задача — выбрать формат, а затем задокументировать этот выбор. Когда эта простая часть завершена, пришло время проанализировать конфигурацию.
Иногда полезно иметь класс, соответствующий «абстрактным» данным в конфигурации. Поскольку этот код ничего не меняет с конфигурацией, это самый простой способ продемонстрировать логику синтаксического анализа.
Представьте себе конфигурацию файлового процессора: он включает в себя входной каталог, выходной каталог и файлы, которые нужно забрать.
Абстрактное определение класса конфигурации может выглядеть примерно так:
from __future__ import annotations
import attr
@attr.frozen
class Configuration:
@attr.frozen
class Files:
input_dir: str
output_dir: str
files: Files
@attr.frozen
class Parameters:
patterns: List[str]
parameters: Parameters
Чтобы упростить код, специфичный для формата, вы также напишете функцию для анализа этого класса из словарей. Обратите внимание, что это предполагает, что в конфигурации будут использоваться тире, а не подчеркивания. Подобное несоответствие не является редкостью.
def configuration_from_dict(details):
files = Configuration.Files(
input_dir=details["files"]["input-dir"],
output_dir=details["files"]["output-dir"],
)
parameters = Configuration.Paraneters(
patterns=details["parameters"]["patterns"]
)
return Configuration(
files=files,
parameters=parameters,
)
JSON
JSON (нотация объектов JavaScript) — это формат, подобный JavaScript.
Вот пример конфигурации в формате JSON:
json_config = """
{
"files": {
"input-dir": "inputs",
"output-dir": "outputs"
},
"parameters": {
"patterns": [
"*.txt",
"*.md"
]
}
}
"""
Логика синтаксического анализа анализирует JSON во встроенные структуры данных Python (словари, списки, строки) с помощью модуля json
, а затем создает класс из словаря:
import json
def configuration_from_json(data):
parsed = json.loads(data)
return configuration_from_dict(parsed)
ИНИ
Формат INI, первоначально популярный в Windows, стал де-факто стандартом конфигурации.
Вот та же конфигурация, что и INI:
ini_config="""
[files]
input-dir = inputs
output-dir = outputs
[parameters]
patterns = ['*.txt', '*.md']
"""
Python может проанализировать его с помощью встроенного модуля configparser
. Парсер ведет себя как объект, подобный dict
, поэтому его можно передать непосредственно в configuration_from_dict
:
import configparser
def configuration_from_ini(data):
parser = configparser.ConfigParser()
parser.read_string(data)
return configuration_from_dict(parser)
ЯМЛ
YAML (еще один язык разметки) — это расширение JSON, которое упрощает написание вручную. Частично это достигается за счет длинной спецификации.
Вот та же конфигурация в YAML:
yaml_config = """
files:
input-dir: inputs
output-dir: outputs
parameters:
patterns:
- '*.txt'
- '*.md'
"""
Чтобы Python мог это проанализировать, вам необходимо установить сторонний модуль. Самый популярный — PyYAML
(pip install pyyaml
). Анализатор YAML также возвращает встроенные типы данных Python, которые можно передать в configuration_from_dict
. Однако анализатор YAML ожидает поток, поэтому вам необходимо преобразовать строку в поток.
import io
import yaml
def configuration_from_yaml(data):
fp = io.StringIO(data)
parsed = yaml.safe_load(fp)
return configuration_from_dict(parsed)
ТОМЛ
TOML (собственный язык разметки Тома) создан как облегченная альтернатива YAML. Спецификация короче, и в некоторых местах она уже популярна (например, менеджер пакетов Rust Cargo использует ее для настройки пакетов).
Вот та же конфигурация, что и TOML:
toml_config = """
[files]
input-dir = "inputs"
output-dir = "outputs"
[parameters]
patterns = [ "*.txt", "*.md",]
"""
Для того, чтобы разобрать TOML, вам необходимо установить сторонний пакет. Самый популярный из них называется просто toml
. Подобно YAML и JSON, он возвращает базовые типы данных Python.
import toml
def configuration_from_toml(data):
parsed = toml.loads(data)
return configuration_from_dict(parsed)
Краткое содержание
Выбор формата конфигурации — это тонкий компромисс. Однако, как только вы примете решение, Python сможет анализировать большинство популярных форматов, используя несколько строк кода.