Лайфхаки

Маленькие, полезные хитрости

Конфигурационные файлы в python. Шаблон применения конфигурационных файлов, как инструмента управления Python-приложениями

22.05.2023 в 06:00

Конфигурационные файлы в python. Шаблон применения конфигурационных файлов, как инструмента управления Python-приложениями

Разобравшись с основными понятиями и концепциями, перейдем к рассмотрению связки «конфигурационный файл + Python-приложение».

В самом простом случае связка состоит из одного конфигурационного файла и одного модуля Python. В общем случае для управления Python-приложением может использоваться несколько файлов конфигурации (различных форматов), а базовая логика приложения опирается на наборов модулей и пакетов.

Сильная сторона такого представления задачи заключается в возможности явным образом декомпозировать приложение на:

  • изменяющийся блок управляющих параметров, или другими словами на динамическую часть инфраструктуры кода, с которой разработчик будет взаимодействовать в будущем,
  • неизменяющийся блок базовой логики – статичную часть кода, которая не требует внесения изменений в программный код напрямую.

Конфигурационные файлы в python. Шаблон применения конфигурационных файлов, как инструмента управления Python-приложениями

Высокоуровневая схема взаимодействия конфигурационного файла с Python-приложением

Упрощенно, шаблон использования конфигурационных файлов как текстового интерфейса к Python-приложению выглядит так: управляющие параметры выносятся в конфигурационный файл, а базовая логика описывается в Python-модуле.

Этот шаблон распространяется на приложения произвольной сложности, но у него есть естественные ограничения.

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

Python configparser. configparser — Configuration file parser ¶

This module provides theclass which implements a basic configuration language which provides a structure similar to what’s found in Microsoft Windows INI files. You can use this to write Python programs which can be customized by end users easily.

Note

This library does not interpret or write the value-type prefixes used in the Windows Registry extended version of INI syntax.

See also

Module
Support for a creating Unix shell-like mini-languages which can be used as an alternate format for application configuration files.
Module
The json module implements a subset of JavaScript syntax which can also be used for this purpose.

14.2.1. Quick Start

Let’s take a very basic configuration file that looks like this:

The structure of INI files is described. Essentially, the file consists of sections, each of which contains keys with values.classes can read and write such files. Let’s start by creating the above configuration file programatically.

As you can see, we can treat a config parser much like a dictionary. There are differences,, but the behavior is very close to what you would expect from a dictionary.

Now that we have created and saved a configuration file, let’s read it back and explore the data it holds.

>>> import configparser >>> config = configparser . ConfigParser () >>> config . sections () >>> config . read ( 'example.ini' ) >>> config . sections () >>> 'bitbucket.org' in config True >>> 'bytebong.com'

As we can see above, the API is pretty straightforward. The only bit of magic involves the DEFAULT section which provides default values for all other sections. Note also that keys in sections are case-insensitive and stored in lowercase.

Конфигурационные файлы это. Краткое содержание


Мощность ОС Linux кроется в возможности гибко настраивать систему под наши потребности. Большинство дистрибутивов содержат продвинутые пользовательские интерфейсы для конфигурации системы, однако, по сути, они лишь редактируют текстовые файлы в различных системных папках. Понимая, как работают конфигурационные файлы, мы можем отказаться от этих интерфейсов и повысить свой уровень владения Linux.Из этого руководства вы узнаете, где файлы конфигурации расположены и каковы их функции. Благодаря(Filesystem Hierarchy Standard) папки и файлы, которые мы рассмотрим, сохраняют своё расположение даже в разных дистрибутивах. Прим. переводчика: Прежде чем двигаться дальше, следует разобраться, как устроена файловая система согласно стандарту FHS.Все файлы и каталоги располагаются в корневой директории«/». Даже если эти данные находятся на различных носителях, какие-то из этих каталогов присутствуют, а какие-то могут отсутствовать. В качестве примера можно привести каталоги, связанные с подсистемой X Window, когда каталогов может и не быть, если графическая подсистема не установлена. Однако, большинство каталогов присутствует на всех UNIX-подобных операционных системах и используется аналогичным образом.
РазделКорневая директория, содержащая всю файловую иерархию
/bin/Утилиты, которые доступны всем пользователям, такие как cat, ls, cp и др.
/boot/Загрузочные файлы (файлы загрузчика, ядро, initrd, System.map). Как правило, выносится на отдельный раздел.
/dev/Файлы устройств. Файлы в данном каталоге обычно создаются драйверами (например, /dev/null, /dev/zero, /dev/sda1).
/etc/Основной каталог конфигурационных файлов системы.
/home/Домашние директории с пользовательскими данными. Могут быть на отдельном разделе либо монтироваться по nfs.
/lib/Основные библиотеки, необходимые для работы программ из /bin/ и /sbin/.
/media/Точки монтирования для сменных носителей, таких как CD-ROM, DVD-ROM, флеш-карты.
/mnt/Используется для монтирования временных файловых систем.
/opt/Дополнительное программное обеспечение. Сюда обычно устанавливаются различные компиляторы и пользовательское ПО, которое не требует соответствия FSHS
/proc/Виртуальная файловая система, представляющая состояние ядра операционной системы и запущенных процессов в виде файлов.
/root/Домашняя директория пользователя root.
/sbin/Основные системные программы для администрирования и настройки системы (например, init, iptables, ifconfig).
/srv/Данные, специфичные для окружения системы.
/tmp/Временные файлы.
/usr /Вторичная иерархия для данных пользователя, содержит большинство пользовательских приложений и утилит.
/usr/bin/Дополнительные программы для всех пользователей, не являющиеся необходимыми в однопользовательском режиме. При различных решениях может монтироваться отдельно.
/usr/include/Стандартные заголовочные файлы.
/usr/lib/Библиотеки для программ, находящихся в /usr/bin/ и /usr/sbin/.
/usr/sbin/Дополнительные системные программы (такие как демоны различных сетевых сервисов).
/usr/share/Архитектурно-независимые общие данные.
/usr/src/Исходные коды ядра.
/usr/local/Третичная иерархия для данных, специфичных для данного хоста. Обычно содержит такие поддиректории, как bin/, lib/, share/.
/var/Изменяемые файлы, такие как файлы регистрации (log-файлы), временные почтовые файлы, файлы спулеров.
/var/lock/Лок-файлы, указывающие на занятость некоторого ресурса.
/var/log/Различные log-файлы.
/var/mail/Почтовые ящики пользователей.
/var/run/Информация о запущенных программах (в основном о демонах).
/var/spool/Задачи, ожидающие обработки (например, очереди печати, непрочитанные или неотправленные письма).

Python ini. Basic configparser usage

These are some examples on using ConfigParser , assuming the following INI file…

>>> import ConfigParser >>> Config = ConfigParser.ConfigParser() >>> Config >>> Config.read("c:\\tomorrow.ini") >>> Config.sections() >>>

Explanation: We first import the configparser, tell it to read the file, and get a listing of the sections. Sections are listed in square brackets .

Next, we are going to get some settings, after defining a helper function.

def ConfigSectionMap(section): dict1 = {} options = Config.options(section) for option in options: try: dict1

Now the code:

>>> Name = ConfigSectionMap("SectionOne") >>> Age = ConfigSectionMap("SectionOne") >>> print "Hello %s. You are %s years old." % (Name, Age) Hello Derek. You are 30 years old.

This works great most of the time, but what about the "Value: Yes" and "Single: True" values? Those are booleans. They can be either True or False, Yes or No, 1 or 0, on or off. To read a boolean value, you use: Config.getboolean(section, option) Example, continuing from above:

>>> single = Config.getboolean("SectionOne", "single") >>> single True

You can also usegetint(section, option)to get a number as an int. This may be easier to use thanint(Config.get(section, option))There is alsogetfloatwhich is used the same as getint, but, as you guessed, returns a float instead of an int.

Notes on reading an INI file

lines beginning with a semicolon ';' a pound sign '#' or the letters 'REM' (uppercase or lowercase) will be ignored. You may use these for comments if you want. You cannot put a comment on an option line. It will only be treated as a comment if it is at the beginning of the line!

Writing an INI file

When you write to an INI file, you will wipe out all comments.

Модуль config python.

Source code: Lib/configparser.py

Этот модуль предоставляет класс, который реализует базовый язык конфигурации, предоставляющий структуру, подобную той, что находится в INI-файлах Microsoft Windows. Вы можете использовать это для написания программ Python, которые могут быть легко настроены конечными пользователями.

Note

Эта библиотека не интерпретирует и не записывает префиксы типов значений, используемые в расширенной версии синтаксиса INI реестра Windows.

See also

Module

TOML-это хорошо специфицированный формат для файлов конфигурации приложений.Он специально разработан как улучшенная версия INI.

Module

Поддержка создания Unix shell-подобных мини-языков,которые также могут быть использованы для конфигурационных файлов приложений.

Module

Модульjsonреализует подмножество синтаксиса JavaScript, который иногда используется для настройки, но не поддерживает комментарии.

Quick Start

Возьмем очень простой конфигурационный файл,который выглядит следующим образом:

Структура файлов INI описана. По сути, файл состоит из разделов, каждый из которых содержит ключи со значениями.могут читать и записывать такие файлы. Начнем с создания вышеуказанного файла конфигурации программно.

>>> import configparser >>> config = configparser.ConfigParser() >>> … 'Compression' : 'yes' , … 'CompressionLevel' : '9' } >>> config = {} >>> config = 'hg' >>> config = {} >>> topsecret = config >>> topsecret = '50022' # изменяет парсер >>> topsecret = 'no' # то же самое >>> config = 'yes' >>> … config.write(configfile) …

Как видите, мы можем рассматривать парсер конфигурации как словарь. Есть различия,, но поведение очень близко к тому, что вы ожидаете от словаря.

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

>>> config = configparser.ConfigParser() >>> config.sections() >>> config.read( 'example.ini' ) >>> config.sections() >>> 'bitbucket.org' in config True >>> 'bytebong.com' in config False >>> config 'hg' >>> config 'yes' >>> topsecret = config >>> topsecret 'no' >>> topsecret '50022' >>> for key in config: … print (key) user compressionlevel serveraliveinterval compression forwardx11 >>> config 'yes'

Как мы видим выше, API довольно прост. Единственная магия связана с разделомDEFAULT, который предоставляет значения по умолчанию для всех остальных разделов. Также обратите внимание, что ключи в разделах нечувствительны к регистру и сохраняются в нижнем регистре.

Можно прочитать несколько конфигураций в один, где самая последняя добавленная конфигурация имеет наивысший приоритет. Любые конфликтующие ключи берутся из более новой конфигурации, а ранее существовавшие ключи сохраняются.

>>> another_config = configparser.ConfigParser() >>> another_config.read( 'example.ini' ) >>> another_config '50022' >>> another_config.read_string( "\nPort=48484" ) >>> another_config '48484' >>> >>> another_config '21212' >>> another_config 'no'

Это поведение эквивалентнос несколькими файлами, переданными в параметр имен файлов .

Config python это. Когда необходим файл конфигурации приложения?

Перед разработкой конфигурационного файла сначала необходимо спросить себя, нужен ли вообще какой-либо внешний файл с данными? Разве мы не можем просто поместить их в виде константных значений прямо в исходном коде? Собственно, достаточно известная концепция The Twelve-Factor App давно отвечает на этот вопрос:

Лакмусовой бумажкой для проверки правильности решения о выделении config всей конфигурационной информации приложения из кода, является рассмотрение возможности о публикации в любой момент кодовой базы вашего приложения, то есть можно ли сделать его исходный код открытым, без нарушения конфиденциальности чьих-либо учетных данных.

Обратите внимание, что это определение config не включает внутреннюю конфигурацию приложения, такую как, например, какconfig/routes.rbв Rails , или способ подключения модулей в Spring . Перечисленные выше примеры способов конфигурации не меняются в зависимости от среды развертывания, и поэтому это лучше всего реализовать их в коде.

Подходы рекомендованные этой концепцией предписывают, чтобы любые параметры, зависящие от среды, такие как учетные данные базы данных, находились во внешнем файле. В противном случае их реализуют просто обычными константами в коде. Другой вариант использования, который я часто вижу, – это хранение динамических переменных (данных) во внешнем файле (базе данных), например, черный blacklist или белый whitelist список пользователей. Ими могут быть числа в заданном диапазоне (например, длительность тайм-аута) или любые текстовые файлы с произвольным содержимым. Отметим, что эти динамические переменные (данные) остаются неизменными вне зависимости от особенностей исполняемой среды.

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

Библиотека config python. Basic usage

This package provides a CLI for scaffolding configuration setup. Assuming you have a Python package calledmy_packagegiven the next directory structure:

\-- project +-- my_package │ \-- __init__.py | \-- main.py

If you are inprojectdirectory, in order to generate a configuration formy_package, run:

config_py -p my_package

The command above will generate aconfigpackage inside ofmy_package, so that directory structure looks like this after:

\-- project +-- my_package │ \-- __init__.py | \-- main.py | +-- config | \-- __init__.py | \-- config_dev.py

Let's put sample configuration value in newly createdconfig_dev.py:

TEST='TEST'

Now, if you import configuration inmain.py:

and you runmain.py, the constantTESTis going to be imported fromconfig_dev.py(devis default environment):

python -m my_package.main # prints TEST value imported from config_dev.py

Adding new environment

If you want something more than defaultdevyou should create new config file inside package'sconfigdirectory:

touch {your_module}/config/config_prod.py

Then put the sameTESTvariable there:

TEST = 'NOPE'

If you run your module withWSGI_EVNset toprodmodule will pick up values from this file.

Loading a configuration for a different environment

In order to load a new configuration for a different environment, let's name itstageenvironment, you have to create a fileconfig/config_stage.py, and provideWSGI_ENVenv variable like this:

WSGI_ENV=stage python -m my_package.main # prints TEST value imported from config_stage.py

As you can see, we imported a configuration for config/config_stage.pyfor that environment and without making any changes to the calling code.

Import config python. Импорт конфигурационных файлов

Конфигурацию можно хранить в различном виде:xml,yaml,iniи так далее.

Один из способов - записывать ее в виде обычного питоновского файла, при исполнении которого должен получиться объект со свойствами-параметрами.

Этот вариант имеет как достоинства, так и недостатки. Сейчас речь не о том. Рассмотрим, как именно подгружается конфигурация на примере.

import imp d = imp.new_module('config') d.__file__ = filename try: execfile(filename, d.__dict__) except IOError, e: if silent and e.errno in (errno.ENOENT, errno.EISDIR): return False e.strerror = 'Unable to load configuration file (%s)' % e.strerror raise

Создается объект модуля с именем'config', в нем прописывается путь к файлу конфигурации__file__(каждый модуль лежащий в файловой системе должен иметь этот атрибут - помогает при поиске неисправностей).

Затем следует вызовexecfileв контексте модуля конфигурации. Между прочим,execfileможно заменить на более длинную конструкцию:

with open(filename) as f: source = f.read() code = compile(source, filename, 'exec') exec code in d.__dict__

Как видим, тоже ничего слишком сложного: читаем содержимое файла конфигурации, компилируем его в режиме'exec'и запускаем на словаре нашего модуля.

Почти так же работает обычный импорт модуля.

Так почему же нельзя сделать

d = imp.load_source('mod_name', filename)

сократив весь код до одной строки?

Дело в первую очередь в том, что конфигурация - это не модуль в полном смысле этого слова. Хотя технически создается полноценный объект типа "модуль" с именем'config', этот модуль не регистрируется в общем словаре модулейsys.modules.

Соответственно его нельзя получить написав import config

И, значит, конфигурация не будет путаться под ногами, закрывая собой (возможно) честный модуль с таким же именем, лежащий в python import path .

Более того, конфигурация имеет смысл только для этого самого фреймворка Flask, остальной код ее просто-напросто не должен видеть - что мы и получили.

Если хотите, модуль конфигурации - анонимный (по аналогии с анонимными функциями).

Вызов жеload_sourceработает немного иначе. Объект модуля будет создан как:

d = sys.modules.setdefault(mod_name, imp.new_module(mod_name))

Т.е. будет взят модуль с именемmod_nameизsys.modules, если не существует - будет создан новый модуль и опять же зарегистрирован в общем каталоге. Обратите внимание,load_sourceработает еще и какreload, если модуль с этим именем уже был загружен.

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

Flask написан очень грамотно, Armin Ronacher на такие грабли не наступает. Чего и вам желаю.