Python создать файл настроек
Программа для создания файлов конфигурации. Часто встречается нужда держать конфигурационные файлы в порядке, и консистенции, распределять общие данные по разным типам файлам, у некоторых типов файлов нет возможности читать переменные окружения, или приходиться подстраиваться под каждый формат по отдельности. Для того чтобы не подстраиваться под каждый формат файла, можно использовать всю мощь python и держать все конфигурации в одном файле.
Какой формат файла конфигурации использовать?
С практической точки зрения, на формат файла конфигурации нет никаких технических ограничений, если код приложения может его прочитать и анализировать. Но есть и более рациональные практики для выбора формата файла с настройками. Так наиболее распространенными, стандартизованными форматами являются YAML, JSON, TOML и INI. Самый подходящий формата для файл конфигурации должен соответствовать как минимум трем критериям:
- Быть легко читаемым и редактируемым: файл должен иметь текстовый формат и такую структуру, чтобы его содержимое было легко понятно даже не разработчику.
- Разрешать использование комментариев: файл конфигурации – это то, что могут читать не только разработчики. Поэтому в процессе эксплуатации приложения чрезвычайно важно когда пользователи могут успешно пытаться понять его работу и изменить его поведение. Написание комментариев – это эффективный способ быстро пояснить ключевые особенности настройки приложения и делает конфигурационный файл более выразительным.
- Простота развертывания: файл конфигурации должен понятен для обработки всеми операционными системами и средами. Он также должен легко доставляться на сервер с помощью конвейера pipeline CDaaS.
Возможно вам пока не ясно какой из форматов файла лучше использовать. Но если вы подумаете об этом в контексте программирования на языке Python, то наиболее очевидным ответом будет YAML или INI. Форматы YAML и INI хорошо понятны большинству программ и пакетов Python.
INI файл, вероятно, является наиболее простым решением для сохранения настроек приложения, имеющих только один уровень иерархии (вложенности) параметров. Однако формат INI не поддерживает других типов данных, кроме строк: в нем все данные имеют строковое представление.
Та же конфигурация настроек в YAML выглядит следующим образом.
Как видите, YAML изначально поддерживает использование вложенные структуры (также как и JSON) с помощью отступов. Кроме того, YAML, в отличие от формата INI файлов, поддерживает некоторые другие типы данных такие как целые и с плавающей запятой числа, логические значения, списки, словари и т.д.
Формат файлов JSON по сути очень похож на YAML и тоже чрезвычайно популярен, однако в JSON файлы нельзя добавлять комментарии. JSON, как текстовый формат содержащий структурированные данные, часто используется для хранения внутренней конфигурации внутри программы, но совершенно не предназначен для того, чтобы делиться конфигурацией приложения с другими людьми (в особенности с далекими от вопросов разработки ПО).
Формат TOML, с другой стороны, похож на INI, но поддерживает гораздо больше типов данных, а также специальный синтаксис для хранения вложенных структур. Его часто используют менеджеры пакетов Python такие, например, pip или poetry. Но если в файле конфигурации присутствует слишком много вложенных структур, то YAML в этом отношении, с моей точки зрения, наилучший выбор. Следующий ниже фрагмент файла выглядит как INI, но в отличие от него каждое строковое значение имеет кавычки.
Пока что мы выяснили ЧТО из себя представляют форматы файлов YAML, JSON, TOML и INI, далее мы рассмотрим КАК они могут быть использованы.
Обращение по ключу
Иногда мы хотим быть уверены, что значение принадлежит определенному типу
Преимущество такого подхода в том, что среда разработки сразу узнает тип и будет указывать на ошибки, также это дополнительная валидация самого конфига.
Иногда хочется где-нибудь в самом начале программы или скрипта убедиться, что необходимые переменные заданы, для этого предусмотренна специальная функция
Класс ConfigProvider наследуется от dict , поэтому его можно спокойно передавать в сторонние библиотеки.
Все просто, разве нет?
Самое интересное начинается, когда в проекте появляется несколько источников конфигов. Например статичные настройки лежат в config.yml , токены и пароли в переменных окружения и .env , некоторые записаны в файле env_file , используемом докером, часть значений нужно переопределить из кода, так как они заранее не известны, часть извлечь из аргументов программы.
Это ведет за собой менее красивый код, который обязан учитывать особенности хранения, приходится задумаваться, откуда мы берем очередное значения настроек, появляется несогласованность, ведь в одних местам мы обращаеся к os.environ , в других к глобальному словарю, в третьих, к сторонней библиотеке.
Попытка №1
А что насчёт того чтобы хранить конфигурацию в коде? Ну, а что, вроде удобно, да и новых языков не придётся изучать. Существует множество проектов, в которых данный способ используется, и хочу сказать, вполне успешно.
Типичный конфиг в этом стиле выглядит так:
Выглядит неплохо. Только одно настораживает, почему секьюрные данные хранятся в коде? Как мы это коммитить будем? Загадка. Разве что вносить наш файл в .gitignore , но это, конечно, вообще не решение.
Да и вообще, почему хоть какие-то данные хранятся в коде? Как мне кажется код, он на то и код, что должен выполнять какую-то логику, а не хранить данные.
Данный подход, на самом деле используется много где. В том же Django. Все думают, что раз это самый популярный фреймворк, который используется в самом Инстаграме, то они то уж плохое советовать не будут. Жаль, что это не так.
Валидация
Hydra прекрасно интегрируется с декоратором @dataclass для выполнения основных проверок корректности, таких как проверка типов или значения полей. Однако у нее нет поддержки __post_init__ метода расширенной проверки значений, как это описано в моей предыдущей статье.
Валидация
Одна из наиболее интересных, в частности для меня, возможностей dynaconf – это его настраиваемый валидатор. Как упоминалось ранее, Configureparser недостаточно строго проверяет корректность INI файлов настроек, но это можно легко реализовать в dynaconf. В следующем примере мы проверяем, существуют ли определенные ключи в файле с настройками и имеется ли в нем конкретный ключ с корректным значением. Если вы читаете настройки из файла YAML или TOML, которые как мы говорили ранее, поддерживают несколько типов данных, то вы даже можете проверить, находится ли значение настройки, например, число в заданном диапазоне.
Группа конфигураций
Hydra вводит концепцию под названием config group . Идея которой состоит в том, чтобы сгруппировать файлы конфигурации одного типа (или для выполнения одних задач) и затем выбирать один из них во время выполнения приложения. Например, у вас имеется группа настроек «Базы данных» с одной конфигурацией для Postgres, а другой для MySQL.
Когда конфигурация приложения станет более сложной, то в вашей программе она может иметь следующую структуру (пример из документации Hydra).
Например, вы хотите протестировать свое приложение с различными комбинациями опций db , schema и ui , это можно сделать следующим образом:
Когда необходим файл конфигурации приложения?
Перед разработкой конфигурационного файла сначала необходимо спросить себя, нужен ли вообще какой-либо внешний файл с данными? Разве мы не можем просто поместить их в виде константных значений прямо в исходном коде? Собственно, достаточно известная концепция The Twelve-Factor App давно отвечает на этот вопрос:
Лакмусовой бумажкой для проверки правильности решения о выделении config всей конфигурационной информации приложения из кода, является рассмотрение возможности о публикации в любой момент кодовой базы вашего приложения, то есть можно ли сделать его исходный код открытым, без нарушения конфиденциальности чьих-либо учетных данных.
Обратите внимание, что это определение config не включает внутреннюю конфигурацию приложения, такую как, например, как config/routes.rb в Rails, или способ подключения модулей в Spring. Перечисленные выше примеры способов конфигурации не меняются в зависимости от среды развертывания, и поэтому это лучше всего реализовать их в коде.
Подходы рекомендованные этой концепцией предписывают, чтобы любые параметры, зависящие от среды, такие как учетные данные базы данных, находились во внешнем файле. В противном случае их реализуют просто обычными константами в коде. Другой вариант использования, который я часто вижу, – это хранение динамических переменных (данных) во внешнем файле (базе данных), например, черный blacklist или белый whitelist список пользователей. Ими могут быть числа в заданном диапазоне (например, длительность тайм-аута) или любые текстовые файлы с произвольным содержимым. Отметим, что эти динамические переменные (данные) остаются неизменными вне зависимости от особенностей исполняемой среды.
В свою очередь файл конфигурации делает программное обеспечение более гибким и легким для редактирования его функциональных возможностей. Однако, если он слишком сильно разрастается, рациональнее все таки перенести его в базу данных.
Итоги
Таким образом, мы пришли к выводу, что хранить настройки в исходных кодах — не есть хорошо. Для этого уже придуманы различные форматы. Ну, а вы познакомились с ещё одной полезной (как я считаю :)) библиотекой.
Да, также можно было включить и Pydantic , но я считаю, что он слишком НЕлегковесный для таких задач.
Расскажу о проделанном пути, чтобы найти идеальный, для моих целей, инструмент конфигурирования проекта и о создании легковесной библиотеки bestconfig, впитавшей в себя преимущества изложенных подходов.
В статье речь пойдет только о локальных способах хранения настроек, здесь не разбираются случаи загрузки из сети.
После создания проекта рано или поздно возникает вопрос: куда записывать номер версии, где хранить токены, пароли, настройки, каким форматом файлов конфигурации воспользоваться: .json , .yaml , .env, .cfg , .ini или просто создать config.py и записывать туда переменные?
Для каждого из перечисленных вариантов есть библиотека на python, приведу примеры самых популярных форматов.
Переменные окружения могут передаваться программе напрямую командным интерпретатором: они записаны в .bashrc , выполнена команда export , или просто указаны в интерфейсе хостинга. Для того, чтобы их явно указать, удобно использовать .env файлы в директории проекта. Если прописать .env в . gitignore можно сложить туда все ключи и не боятся их опубликовать, в то время как остальные настройки будут в другом месте для использования в продакшн окружении
Библиотека dotenv отлично справляется с задачей подгрузки таких файлов. Все переменные сразу попадают в os.environ
В последнее время стал популярен формат .yml , как один из самых приятных для чтения человеком
Открываем файл из кода
Формат чаще используется для коммуникации между сервисам, например между фронтом и беком, как компактный, но в то же время понятный человеку. Но задать в нем некоторые настройки тоже можно
В файле с расширением .py объявляем все необходимые переменные. У данного подхода есть преимощество - можно некоторые значения вычислять на ходу: инкриментировать номер сборки, менять хост в зависимости от режима: DEBUG или RELEASE и тд.
Осталось только импортировать этот файл там, где он нужен
Dynaconf — мощный конфигуратор настроек для приложений Python
Dynaconf — это очень мощная система для конфигурации настроек в Python, которая поддерживает следующие форматы файлов: yaml, json, ini, toml и python. Она также позволяет автоматически загружать .env файл и поддерживает настраиваемые правила для валидации данных настроек. Проще говоря, он охватывает практически весь функционал трех предыдущих рассмотренных вариантов и даже выходит за рамки этого. Например, вы можете сохранить зашифрованный пароль и используя специальный загрузчик для его расшифровки. Он прекрасно интегрирован с Flask, Django и Pytest. Я не буду упоминать все его возможности в этой статье, и поэтому для более подробной информации обратитесь к его документации.
Пакет Cofigureparser из состава стандартной библиотеки Python
В этом разделе рассмотрим пакеты, предназначенные непосредственно для управления конфигурацией приложения. И начнем со встроенного в стандартную библиотеку Python пакета: Configureparser.
Configureparser в большинстве случаев используется для чтения и записи INI файлов, и поддерживает чтение входных данных из файла сразу в виде словаря или итерируемого iterable файлоподобного объекта. Как известно, каждый файл INI состоит из нескольких секций, содержащих настройки в виде пар ключ-значение. Ниже приведен простой пример кода для доступа к полям настроек.
Чтение
Этот тип файла конфигурации очень легко использовать. Так если вы решите переопределить существующую (или создать новую) переменную среды, то можете использовать вызов метод load_dotenv() , например, зададим значение параметра override .
Резюме
Библиотека создана чтобы максимально упростить распространенную задачу по обращению к файлам настроки, ее основные фичи и особенности:
Поддержка множества форматов файлов
Интерфейс доступа к данным "на любой вкус" (по ключу, через точку, через get и тд)
Маленький вес (примерно 15 кб)
Чистый, типизированный, расширяемый python код на модульной архитектуре
Открытость к изменениям и дополнениям (pull request-ы приветствуются)
Есть и недостатки:
У проекта появляются лишние зависимости. Например вы не используете yaml, однако библиотека подтягивает pyyaml
Захват лишнего. Вы можете написать Config() и даже не обратить внимание, сколько всего попало в config, одни переменные окружения чего стоят - их может быть очень много. И вывод print(config) становится абсолютно не читаемым
Теперь, при создании нового sandbox проекта или усложении текущего еще одним видом конфигурационных файлов, вы можете выбрать из своего арсенала еще один инструмент!
Относитесь к файлу конфигурации, использующемуся в приложении, как к разрабатываемому вами коду.
Когда мы разрабатываем программное обеспечение, то всегда прикладываем много усилий для написания качественного и производительного кода. Однако зачастую этого недостаточно.
Разработка качественного программного обеспечения, включает заботу о разработке своей экосистемы, например, для организации процессов тестирования, развертывания, сетевого обмена данными и т.д. Одним из наиболее важных аспектов, который необходимо при этом учитывать, является реализация гибкого механизма управления конфигурацией (настройками) программного обеспечения.
Правильная реализация управления конфигурацией по сути должна позволять запускать программное обеспечение в любой среде без внесения изменений в его исходный код. Этот подход обеспечивает эффективное управление проблемными настройками вашего приложения со стороны администраторов Ops, обеспечивает представление информации о том, что может произойти во время его функционирования, а также позволяет изменять его поведение во время выполнения.
Наиболее распространенные конфигурации включают в себя учетные данные для базы данных или внешней службы, имя хоста сервера, а также любые динамические параметры и т.д.
В этой статье я хочу поделиться с вами несколькими зарекомендовавшими себя практиками управления конфигурациями, а также как мы можем реализовать их в приложениях, написанных на Python.
Интеграция с Pytest
Еще одна интересная особенность dynaconf – это возможность его интеграции с pytest. Так настройки для модульного тестирования unit testing обычно существенно отличаются в различных средах. Для этого вы можете использовать параметр FORCE_ENV_FOR_DYNACONF , чтобы ваше приложение могло прочитать значения настроек из внешнего файла, или использовать фикстуру monkeypatch для замены определенных пар ключ и значение в файле настроек.
BestConfig
Блуждая по просторам всемирной паутины, идеального решения я не нашел и создал очень простую и удобную библиотеку, умеющую бороться в вышеперечисленными проблемами.
Поставил целью уменьшить количество кода чтения конфигов почти до нуля, но в тоже время оставить гибкость и возможность подкрутки под более специфичные задачи. Итак, давайе посмотрим, как импортировать например config.yml
И да, это все, что нужно сделать. Глобальный объект config уже будет содержать все необходимое. А теперь по порядку.
Что происходит при создании Config() :
Запускается поиск файлов, похожих на конфиги: любые комбинации имени conf, config, configuration, setting, settings с расширениями yml, yaml, json, ini, cfg, env в текущей директории и в папках выше, вплодь до корня проекта. Также в хранилище добавляются переменные окружения
Исходя из формата файла производится импорт содержимого
Создается класс ConfigProvider , предоставляющий универсальный доступ ко всему содержимому
Посмотрим на примерах, в чем же "универсальность" объекта config
Решение проблемы совместимости
Чтение
Из-за проблем с безопасностью рекомендуется использовать метод yaml.safe_load() вместо yaml.load() , чтобы избежать внедрения вредоносного кода при чтении файла конфигурации.
Попытка №2
Ладно, раз уж мы решили, что хранить данные в коде — не круто, то давайте искать альтернативу. Для конфигурационных файлов изобретено немалое количество различных форматов, в последнее время набирают большую популярность toml .
Но мы начнём с того, что нам предлагает сам Python — .ini . В стандартной библиотеке имеется библиотека configparser .
Наш конфиг, который мы уже писали ранее:
А теперь прочитаем в Python:
Все проблемы решены. Данные хранятся не в коде, доступ прост. Но… а если нам нужно читать другие конфиги, ну там json или yaml например, или все сразу. Конечно, есть json в стандартной библиотеке и pyyaml , но придётся написать кучу (ну, или не совсем) кода для этого.
Установка
Модификация
Помимо словаря метод insert принимает названия файлов (с абсолютным или относильным путем) любого из поддерживаемых расширений
Выше я приводил пример, в котором конфиг переменные объявляются прямо в .py файле. Если в проекте уже используется такой вариант, необязательно всё менять, на этот случай есть метод update_from_locals
В питоне есть встроенная функци locals() , она возвращает словарь локальных переменных, имеено ее и использует данный метод. Там, конечно, рассматриваются добавляемые объекты и лишние отсеиваются (подробнее в документации).
Hydra — упрощаем разработку, динамически создавая иерархическую структуру конфигурации приложения
Рассмотрим последним, в этой статье, способ создания и поддержки конфигурации для вашего приложения, который по сути является гораздо большим, чем просто загрузчик и парсер файлов с настройками.
Hydra – это платформа, разработанная Facebook для гибкой и элегантной настройки самых сложных приложений. Которая помимо чтения, записи и валидации корректности файлов конфигурации, реализовывает свою достаточно рациональную стратегию упрощения управления несколькими конфигурационными файлами, переопределения (перезаписи) их с использованием интерфейса командной строки, создания snapshot снимка состояния приложения перед каждым его запуском (между перезапусками) и т.д.
Сделать копию и скрыть данные
Почти всегда нам нужно иметь в проекте секретные(приватные) данные, которые не должны стать публичными. У нас есть возможность создавать копию конфигурации со скрытыми данными. Для того чтобы указать переменную у которой нужно скрыть значения, напишите в начел её имени _hide_
Пример, нам нужно скрыть данные url для подключения к БД, ключ для шифрования сессии, данные для входа в админ панель, ну или любые другие данные. Для того чтобы сделать копию этой конфигурации, например, для того чтобы сохранить всю логики, но при этом скрыть выше указанные данные, мы указываем в начале имени _hide_ , в итоге мы получим файл conf_pub.py который можно спокойно хранить в открытом доступе, например в GitHab .
configer hideconf conf.py
В итоге мы получим копию, расположенную в ./conf_pub.py . Содержание
YAML/JSON — простое чтение внешнего файла
Как обычно, мы начнем с самого простого, то есть создадим внешний файл с настройками, а затем прочитаем его. Python имеет в своем составе встроенные пакеты для чтения и анализа файлов YAML и JSON. И как видно из приведенного ниже кода, они фактически возвращают один и тот же объект типа dict, поэтому доступ к его атрибутам будет одинаковым для обоих файлов.
Обновляем конфигурацию приложения во время его выполнения
Dynaconf в своем составе содержит метод reload() , который очищает значения настроек и перезапускает все загрузчики вашего приложения. Это полезно, если вы хотите, чтобы приложение перезагружало файл настроек во время выполнения и соответственно в последствие изменяло свое поведение. Например, приложение должно автоматически перезагрузить настройки, если файл конфигурации был открыт и изменен (откорректирован).
Валидация
Валидация данных с Configureparser не так проста, как для пакетов, работающих с форматами YAML и JSON. Во-первых, он не возбуждает исключения FileNotFoundError если файла настроек не существует, а вместо этого вызывает исключение типа KeyError, как при попытке доступа к отсутствующему ключу.
Кроме того, этот пакет «игнорирует» некоторые ошибки форматирования, например, неправильное использование отступа. Так в приведенном ниже примере, в случае если в файле присутствует дополнительная табуляция или пробел перед настройкой DEBUG , то вы получите неправильные значения для обеих настроек ENVIRONMENT и DEBUG .
Тем не менее, Configureparser может возбуждать исключение ParserError при наличии нескольких ошибок (см. пример кода с тестами ниже). И в большинстве случаев этого достаточно для определения проблемных мест в самом файле настроек.
Использование
- Скомпилировать конфигурационные файлы
configer parseconf $ПутьКонфигурациям$.py
- Сделать копию и скрыть данные
configer hideconf $ПутьКонфигурациям$.py
Создание файла конфигураций
Для того чтобы указать какие переменные нужно рассматривать в качестве конфигураций, их нужно поместить в переменную export_var , переменная с конфигурациями должна соответствовать правилам, это должен быть картеж со следующим порядком значений:
Название файла (`str`)
Путь куда поместить файл (`str`)
Значения которые нужно взять из словаря заключите в $$(Ключ)$$
Словарь для замены слов dict[str,str]
Эти значения подставится в класс ConfFile(*args)
configer parseconf conf.py
В итоге мы получим файл, расположенный в ./test/__env.env . Содержание
Чтение
Dynaconf использует .env файл для поиска других конфигурационных файлов и последующего заполнения полей settings объекта с настройками. Так если в двух файлах настроек есть одна и та же переменная, то ее значение будет перезаписано значением из последнего файла настроек.
Как читать, обновлять и удалять опции
Теперь мы готовы к тому, что бы научиться чтению файла config, обновлять его опции и даже удалять их. В нашем случае учиться будет намного проще, если мы попробуем на практике написать какой-нибудь код. Просто добавьте следующую функцию в код, который вы писали ранее.
Этот код сначала проверяет, существует ли файл config в принципе. Если его нет, то он использует созданную нами ранее функцию createConfig, чтобы создать файл. Далее мы создаем объект ConfigParser и указываем путь к файлу config для чтения. Чтобы прочесть опцию в вашем config файле, мы вызываем метод нашего объекта ConfigParser, указываем ему наименование секции и опции.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Telegram Чат & Канал
Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Это вернет значение параметра. Если вы хотите изменить значение опции, вам нужно использовать метод set, в котором вы указываете название секции, опции, и новое значение. Наконец, мы можем использовать метод remove_option, чтобы удалить опцию. В нашем примере мы изменили значение font_size, и задали ему размер 12, затем мы удалили опцию font_style. После этого мы записали наши изменения на диск. Этот пример на на столько хорош, давайте упростим наш код. Для этого мы разделим наш код на на несколько функции:
Этот пример выглядит более организованно, по сравнению с первым. Я зашел так далеко, что назвал функции соответственно стандартам PEP8. Каждая функция должна объяснять сама себя и выполнять лишь одну задачу. Вместо того, чтобы помещать всю логику в одну единственную функцию, мы разделяем её на несколько функций, после чего демонстрируем их функционал в конце оператора if. Теперь вы можете импортировать модуль и использовать по назначению. Обратите внимание на то, что в этом примере есть сложная секция, так что вам, возможно, захочется усовершенствовать этот пример в дальнейшем, чтобы сделать его более универсальным.
Валидация
Тем не менее пакет python-dotenv не проверяет корректность .env файла. Допустим у вас есть некоторый .env файл (его содержимое представлено ниже), и вы хотите получить доступ к значению переменной (параметра настройки) DEBUG , то будет возвращено значение None без возбуждения исключения соответствующего типа.
Попытка №3
А сейчас, я хотел бы показать Вам свою библиотеку, которая призвана решить все эти проблемы (ну, или хотя бы уменьшить ваши страдания :)).
Называется она betterconf и доступна на PyPi.
Установка так же проста, как и любой другой библиотеки:
Изначально, наш конфиг представлен в виде класса с полями:
По умолчанию, библиотека пытается взять значения из переменных окружения, но мы также можем настроить и это:
Из этого примера следует, что мы можем применять различные провайдеры для получения данных. И это действительно иногда бывает удобно, говорю из личного опыта.
Хорошо, а что если у нас в конфигах есть булевые значения, или числа, они же в итоге будут все равно приходить в строках. И для этого есть решение:
Таким образом, все похожие на булевые типы значения (а именно true и false будут преобразованы в питоновский bool . Регистр не учитывается.
Свой кастер написать также легко:
Не перезаписывать файл если он уже существует
Допустим у нас есть ситуация когда нужно создать шаблонный файл, по указанному пути. Но нам не нужно его постоянно перезаписывать при вызове parseconf . Например, нам нужно чтобы был создан файл README.md для проекта, и pyproject.tom для зависимостей проекта. README.md файл может часто вами изменятся и расширятся, pyproject.toml файл тоже может часто изменятся например вы обновили версии зависимостей. Писать весь текст файлами в conf.py неудобно поэтому мы хотим чтобы он был создан единожды и больше не перезаписывался для этого мы передаем последним аргументом "norewrite"
Конфиги. Все хранят их по разному. Кто-то в .yaml , кто-то в .ini , а кто-то вообще в исходном коде, подумав, что "Путь Django" с его settings.py действительно хорош.
В этой статье, я хочу попробовать найти идеальный (вероятнее всего) способ хранения и использования конфигурационных файлов в Python. Ну, а также поделиться своей библиотекой для них :)
Best practices
Обобщу процесс взаимодействия с конфигами с использованием библиотеки bestconfig.
Статичные настройки, не содержащие ключей лежат в файле config.yml в корне проекта
Переменные окружения и ключи задаются в .env и игнорируются системой контроля версий
Файл config.py содержит создает класс Config и выполняет другие настройки (например логгирование, версия проекта, обработка параметров запуска и тд)
В других местах проекта делаем from config import config и используемый нужные данные удобным образом
Дисклеймер
Этот проект является прототипом, я не заставляю вас использовать эту программу для решения своих задач, в большой степени мне хочется узнать мнение общественности о необходимости решения таких задач, и если будет поддержка идеи то уже тогда можно задуматься о создании надежной и конкурентной программы.
Если вас не заинтересовала данная статья, и вам не хотите использовать данные решения, то поставьте дизлайк по причине "В статье нет новой для меня информации" а не по какой-нибудь другой причине.
Если вы решили поставить дизлайк по причине "Низкий технический уровень материала", то просьба аргументировать в комментариях в чем он низкий. Если вы не разбирались в исходном коде программы, и вам просто неопрятен моя манера письма, то поставьте дизлайк по причине "Личная неприязнь к автору или компании", не нужно вводить в заблуждение и панику других пользователей ссылать на неаргументированный низкий технический уровень.
Осуждение того что документация и комментарии в исходном коде написаны на родном для меня Русском языке, а не на Английском. Является проявлением русофобии, и в как-то мери национализмом. Каждый в равно степени может писать и документировать на любом удобном для себя языке. Если вы действительно хотите помочь в мультиязычности проекта, то я(мы) готов(ы) к сотрудничеству.
У меня нет гарантий что этот проект будет поддерживаться. Если он мне не понравиться, и не будет поддержки со стороны общественности, то проекту суждено "кануть в лету". Вы, наверное, удивитесь, но так поступают со многими стартапами по всему миру которые не оправдывают ожидания. Так что вспомните об этом, когда захотите упомянуть, что "этот проект не надежен", что "нет гарантий поддержки этого проекта в длительной перспективе", что "лучше писать костыли к проверенным технологиям чем довериться этой авантюрной идеи". Забвение может произойти с любым сатрапам, но по крайне меры ни кто не вкладывал денег в этот проект.
Если вы знаете аналоги для решения этих задач, то буду рад увидеть их в комментариях.
Создание файла
Создание файла config при помощи configparser невероятно просто. Давайте напишем небольшой код, чтобы посмотреть, как это работает:
Данный код создает файл config с одной секцией, под названием Settings, которая будет содержать наши опции: font, font_size, font_style и font_info. Обратите внимание на то, что в Python 3 нам нужно указать, что мы пишем файл в режиме write-only, или “w”. А в Python 2.7, мы использовали “wb” для написания в бинарном режиме.
Чтение
Рассмотрим основы использования hydra. Так в следующем примере команда +APP.NAME , добавленная в командную строку при запуске скрипта, позволяет добавить новое поле (настройку) в конфигурацию приложения, а также осуществить перезапись значения существующего поля (значения настройки) APP.NAME=hydra1.1 .
Python-dotenv — считываем конфигурацию приложения из переменных среды
Теперь перейдем к сторонним библиотекам, использующимся для управления конфигурацией приложений Python. До сих пор я намеренно пропустил еще один тип файлов конфигурации, а именно .env . Так значения настроек, находящихся в файле .env при запуске терминала (скрипта приложения) будут загружены как переменные среды, и поэтому с помощью библиотеки python-dotenv , а точнее ее метода os.getenv() можно получить доступ к ним из кода приложения.
Файл .env обычно выглядит следующим образом. По умолчанию его местонахождение – корневая папка вашего проекта.
Далее…
Hydra поддерживает использование нескольких наборов параметров конфигурации с опцией --multirun , при этом запускаются параллельно несколько задач с различными файлами конфигурации. Например, для предыдущего примера мы можем запустить скрипт следующим образом:
В этом случае в основном потоке запускаются 6 задач одновременно:
Дисклеймер
Этот проект является прототипом, я не заставляю вас использовать эту программу для решения своих задач, в большой степени мне хочется узнать мнение общественности о необходимости решения таких задач, и если будет поддержка идеи то уже тогда можно задуматься о создании надежной и конкурентной программы.
Если вас не заинтересовала данная статья, и вам не хотите использовать данные решения, то поставьте дизлайк по причине "В статье нет новой для меня информации" а не по какой-нибудь другой причине.
Если вы решили поставить дизлайк по причине "Низкий технический уровень материала", то просьба аргументировать в комментариях в чем он низкий. Если вы не разбирались в исходном коде программы, и вам просто неопрятен моя манера письма, то поставьте дизлайк по причине "Личная неприязнь к автору или компании", не нужно вводить в заблуждение и панику других пользователей ссылать на неаргументированный низкий технический уровень.
Осуждение того что документация и комментарии в исходном коде написаны на родном для меня Русском языке, а не на Английском. Является проявлением русофобии, и в как-то мери национализмом. Каждый в равно степени может писать и документировать на любом удобном для себя языке. Если вы действительно хотите помочь в мультиязычности проекта, то я(мы) готов(ы) к сотрудничеству.
У меня нет гарантий что этот проект будет поддерживаться. Если он мне не понравиться, и не будет поддержки со стороны общественности, то проекту суждено "кануть в лету". Вы, наверное, удивитесь, но так поступают со многими стартапами по всему миру которые не оправдывают ожидания. Так что вспомните об этом, когда захотите упомянуть, что "этот проект не надежен", что "нет гарантий поддержки этого проекта в длительной перспективе", что "лучше писать костыли к проверенным технологиям чем довериться этой авантюрной идеи". Забвение может произойти с любым сатрапам, но по крайне меры ни кто не вкладывал денег в этот проект.
Если вы знаете аналоги для решения этих задач, то буду рад увидеть их в комментариях.
Совместимость с Python 3
Из за нововведений в стандарте PEP 8 модуль ConfigParser в Python 3 был переименован в configparser. Возможные ошибки:
ImportError: no module named ConfigParser
Вывод
В этой статье мы рассмотрели несколько способов управления конфигурацией приложений в Python. Независимо от того какой из них вы выберете, всегда необходимо думать о удобочитаемости файлов конфигурации, дальнейшей их поддержки, а также способах обнаружения ошибок для случаев их некорректного использования. Таким образом, конфигурационный файл – это по сути еще один тип кода.
Надеюсь, вам понравится эта статья, не стесняйтесь оставлять свои комментарии ниже.
Файлы конфигурации используются как пользователями, так и программистами. Как правило, их используют для хранения настроек вашего приложения, или операционной системы. Библиотека в ядре Python включает в себя модуль, под названием configparser, который вы можете использовать для создания и работы с файлами конфигурации. Что ж, давайте выделим несколько минут на то, чтобы узнать, как это работает.
Кастомизация
По умолчанию Config() делает довольно много всего, с целью быть универсальным, но содежит ряд аргументов, регулирующих это поведение.
Чтение
Как видно из примера Configureparser не может «угадать» типы данных, содержащихся в файле конфигурации, так как значение каждой настройки сохраняется в виде строки. Тем не менее, он предоставляет несколько полезных методов для преобразования строк (значений настроек) в нужный тип данных. Наиболее интересным из них является метод преобразующий значения в логический тип, то есть он может распознавать некоторые логические значения, например, yes / no , on / off , true / false и 1 / 0 .
Как уже нами упоминалось ранее, Configureparser может читать данные настроек в следующих видах на выходе: словаря с помощью метода read_dict() , простой строки с использованием read_string() и итерируемого файлоподобного объекта, возвращаемого методом read_file() .
Как использовать интерполяцию
Модуль configparser также подразумевает возможность интерполяции, что значит, что вы можете использовать существующие опции, для создания другой опции. Мы на самом деле это делали с опцией font_info, чьи параметры основаны на опциях font и font_size. Мы можем изменить интерполированное значение при помощи словаря Python. Давайте уделим несколько минут, и взглянем на оба случая.
Валидация
При использовании обоих пакетов при попытке чтения несуществующего файла будет генерироваться исключение типа FileNotFoundError . Использование пакета для чтения файлов YAML позволяет получать разные исключения для следующих случаев: пользователь указал файл не являющимся YAML файлом, а также прочитанный файл YAML является не корректным, то есть содержит синтаксические ошибки. В свою очередь пакет для чтения JSON файлов генерирует единственное исключение типа JSONDecoderError для обоих рассмотренных случаев.
Читайте также: