Рубрики
Без рубрики

Файлы конфигурации Правильный путь

Файлы конфигурации анализа – это то, что мы делаем программисты каждый день. Но вы уверены, что делаете это правильно?. Tagged с Python.

Впервые опубликовано на мой блог

Файлы конфигурации анализа – это то, что мы делаем программисты каждый день. Но вы уверены, что делаете это правильно?

Давай выясним!

В остальной части этой статьи мы предположим, что хотим проанализировать файл конфигурации, содержащий токен доступа GitHub в программе командной строки под названием фрук .

Вы можете написать что -то вроде этого:

/* in config.json */
{
  "auth":
  {
    "github":
    {
      "token": "ab642ef9zf"
    }
  }
}
/* in frob.js */
const config = require('./config');
const token = config.auth.github.token;
...

Ну, это предполагает, что мы используем Узел Анкет Сделать эту работу в браузере или в любом другом контексте JavaScript остается в качестве упражнения для читателя:)

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

Во -первых, используя Json Для файлов конфигурации может быть не такой хорошей идеей. Итак, мы собираемся использовать YAML. Вот несколько причин, почему:

  • Как и JSON, мы можем отображать непосредственно с типами питонов «простых старых данных» (списки, словари, целые числа, поплавки, струны и логические)

  • Синтаксис четко определен, и все реализации ведут себя одинаково. (Это не Дело для JSON, см. Парирование JSON – это минное поле для деталей)

  • Мы можем иметь комментарии в файле конфигурации.

  • Файл легче читать для людей. Сравнивать:

{
  "auth":
  {
    "github":
    {
      "token": "ab642ef9zf"
    }
  }
}
auth:
  github:
    token:  "ab642ef9zf"
  • Элементы могут быть произвольными вложенными. ( .ini Есть несколько способов выразить одни и те же данные, поэтому мы можем выбрать то, что более читабельно:

shopping_list:
 - eggs
 - bacon
 - tomatoes
 - beans

tags: ["python", "testing"]
  • Пробел является значительным, поэтому файл имеет быть должным образом отступа.

Второй , config.json Файл жестко кодируется, чтобы находиться рядом с исходным кодом.

Это означает, что возможно, что он будет добавлен и подтолкнут к системе управления версиями, если мы не будем осторожны.

Поэтому вместо этого мы постараемся быть совместимым с Стандарты Freedesktop Анкет

В основном это означает, что мы должны:

  • Ищите файл конфигурации в $ Xdg_config_home/frob.yml Если установлена переменная среды xdg_config_home.
  • Если нет, ищите это в ~/.config/frob.yml
  • И если не найдено в доме, ищите по умолчанию в /etc/xdg/frob.yml

Это поможет нам следовать за Принцип наименьшего удивления Потому что, поскольку многие программы следуют этим правилам сегодня, пользователи нашей реализации будут Ожидайте нам сделать то же самое.

К счастью, нам не нужно реализовать все это, мы можем использовать pyxdg библиотека:

import xdg.BaseDirectory

cfg_path = xdg.BaseDirectory.load_first_config("frob.yml")
if cfg_path:
   ...

Иногда файл вообще не существует, поэтому мы захотим сообщить об этом нашему пользователю:

cfg_path = xdg.BaseDirectory.load_first_config("frob.yml")

if not cfg_path:
    raise InvalidConfig("frob.yml not found")

Иногда файл будет существовать, но read_text () По какой -то причине потерпит неудачу (например, проблема с разрешением):

import pathlib

try:
   config_file = pathlib.Path(cfg_path)
   contents = config_file.read_text()
except OSError as read_error:
    raise InvalidConfig(f"Could not read file {cfg_path}: {read_error}")

Иногда файл будет существовать, но будет содержать недействительный YAML:

import ruamel.yaml

contents = config_file.read_text()
try:
    parsed = ruamel.yaml.safe_load(contents)
except ruamel.yaml.error.YAMLError as yaml_error:
    details = format_error(yaml_error.context_mark.line, yaml_error.context_mark.column)
    message = f"{cfg_path}: YAML error: {details}"
    raise InvalidConfig(message)

Вот где все становится сложно. Что если файл существует, читабелен, содержит действительный код YAML, но пользователь сделал опечатку при его написании?

Вот несколько случаев, которые мы должны справиться:

# empty config: no error

# `auth` section is here but does not contain
# a `github` entry: no error
auth:
  gitlab:
    ...

# `auth.github` section is here but does not
# contain `token`, this is an error:
auth:
  github:
    tken: "ab642ef9zf"

Наивный способ справиться с этим – написать код таким образом:

parsed = ruamel.yaml.safe_load(contents)
auth = parsed.get("auth")
if auth:
    github = auth.get("github")
    token = github.get("token")
    if not token:
        raise InvalidConfig("Expecting a key named 'token' in the
                            'github' section of 'auth' config")

Это становится утомительным очень быстро. Лучший способ – использовать схема библиотека:

import schema
auth_schema = schema.Schema(
  {
    schema.Optional("auth"):
    {
      schema.Optional("github") :
      {
        "token": str,
      }
    }
  }
)

try:
    auth_schema.validate(parsed)
except schema.SchemaError as schema_error:
    raise InvalidConfig(file_path, schema_error)

И последнее, но не менее важное: иногда мы захотим автоматически сохранить файл конфигурации.

В этом случае важно, чтобы сохраненный файл конфигурации все еще напоминал исходный.

С ruamel.yaml , это делается с помощью Загрузчик

def save_token(token):
    contents = config_file.read_text()
    config = ruamel.yaml.load(contents, ruamel.yaml.RoundTripLoader)
    config["auth"]["github"]["token"] = token
    dumped = ruamel.yaml.dump(config, Dumper=ruamel.yaml.RoundTripDumper)
    config_file.write_text(dumped)

Профь! Это была большая работа для, казалось бы, простой задачи. Но я верю, что стоит пройти через все эти проблемы: мы рассмотрели много краевых случаев и убедились, что у нас всегда были очень четкие сообщения об ошибках. Пользователи кода, написанные так, будут очень благодарны, когда дела пойдут на юг. Ваше здоровье!

Спасибо, что прочитали это далеко:)

Я хотел бы услышать, что вы скажете, поэтому, пожалуйста, оставьте комментарий ниже или прочитайте Страница обратной связи Для большего количества способов связаться со мной.

Оригинал: “https://dev.to/dmerejkowsky/parsing-config-files-the-right-way”