Share This
Π‘Π²ΡΠ·Π°Ρ‚ΡŒΡΡ со ΠΌΠ½ΠΎΠΉ
ΠšΡ€ΡƒΡ‚ΠΈ Π² Π½ΠΈΠ·
Categories
//🐍 ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ ΠΊΠ°ΠΊ инструмСнт управлСния прилоТСниями Π½Π° Python

🐍 ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ ΠΊΠ°ΠΊ инструмСнт управлСния прилоТСниями Π½Π° Python

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

konfiguracionnye fajly kak instrument upravlenija prilozhenijami na python b1a415f - 🐍 Конфигурационные файлы как инструмент управления приложениями на Python

Вводные замечания о форматах конфигурационных файлов

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

К наиболее распространенным форматам конфигурационных файлов, которые находят применение в контексте управления приложениями на Python, можно отнести INI, JSON, TOML и YAML.

  • INI – самый простой формат из рассмотренных. С одной стороны чем проще читать конфигурационный файл, тем лучше, но с другой – файлы *.INI могут оперировать только одномерными структурами, т.е. структурами с простой одноуровневой иерархией. В большинстве прикладных задач, когда приходится иметь дело с моделями объектов, допускающих представление в виде списков, ассоциативных массивов и т.п., возможностей INI оказывается недостаточно.
  • JSON-файл выглядит как обычный словарь Python и может включать сложные иерархические зависимости, однако с точки зрения читаемости проигрывает и YAML, и TOML. Кроме того, JSON не поддерживает комментарии, а они часто могут значительно упростить сопровождение кода.
  • В отличие от предыдущих, формат TOML обладает несоизмеримой гибкостью и широтой арсенала поддерживаемых типов данных. TOML поддерживает простые пары «ключ-значение», массивы, классические и встроенные таблицы, массивы таблиц, булевы значения, а также локальные временные метки и временные метки со смещением.

Для сравнения рассмотрим одну и ту же модель объекта, описанного с помощью TOML и JSON.

Вот TOML-представление модели объекта:

view_obj.toml

         [[fruits]] name = "apple"  [fruits.physical]  # подтаблица color = "red" shape = "round"  [[fruits.varieties]]  # вложенный массив таблиц name = "red delicious"  [[fruits.varieties]] name = "granny smith"  [[fruits]] name = "banana"  [[fruits.varieties]] name = "plantain"     

А вот JSON-представление:

view_obj.json

         {   "fruits": [     {       "name": "apple",       "physical": {         "color": "red",         "shape": "round"       },       "varieties": [         { "name": "red delicious" },         { "name": "granny smith" }       ]     },     {       "name": "banana",       "varieties": [         { "name": "plantain" }       ]     }   ] }     

Синтаксические особенности JSON – избыточные фигурные и квадратные скобки – делают сложноструктурные JSON-файлы «размазанными».

Формат YAML обладает схожими с форматом TOML возможностями (в смысле гибкости представления моделей объектов и разнообразия поддерживаемых типов данных), но на сложных структурах выглядит компактнее.

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

Python-библиотеки для работы с конфигурационными файлами

Из всего многообразия предназначенных для работы с конфигурационными файлами библиотек – ориентированных на какой-то конкретный формат или «всеядных» – можно выделить следующие:

  • configparser: это элемент стандартной библиотеки Python, предназначенный для работы с INI-файлами Microsoft Windows. В распоряжении пользователя есть класс ConfigParser, который реализует базовые возможности библиотеки.
  • PyYAML: элемент не входит в стандартную библиотеку, поэтому его нужно установить с помощью менеджера пакетов pip pip install pyyaml. В Python-сценарии обращение к библиотеке выглядит как import yaml.
  • toml: этот элемент тоже представляет собой стороннее решение для работы с форматом TOML и требует установки с помощью pip install toml.
  • dynaconf: это очень гибкая библиотека, которая 1) позволяет работать со всеми популярными форматами конфигурационных файлов (*.toml, *.yaml, *.json, *.ini, *.py), 2) поддерживает мультипрофили, т.е. конфигурационный файл может содержать несколько заголовков, относящихся к различным стадиям готовности программного продукта (например, default, development, production и т.д.), а нужный набор настроек затем вызывается с указанием соответствующего заголовка, 3) умеет работать с переменными окружения («работает из коробки» с библиотекой dotenv), 4) предлагает утилиту командной строки для выполнения операций общего назначения (init, list, write, validate и т.д.). Устанавливается библиотека с помощью менеджера пакетов pip pip install dynaconf.
  • hydra: это, строго говоря, не просто библиотека, а полноценная платформа, предназначенная для решения широкого круга задач, связанных с конфигурацией сложных приложений. Установить hydra можно либо с помощью менеджера пакетов pip pip install hydra-core --upgrade, либо с помощью менеджера пакетов conda conda install -c conda-forge hydra-core.

В основном, выбор библиотеки определяется следующими аспектами:

  • сложностью задачи и ее особенностями. К примеру, конфигурация маршрута подготовки моделей машинного обучения для развертывания на облачной платформе может быть выполнена и с помощью PyYAML/toml, а вот управление сложным web-проектом скорее всего потребует продвинутых возможностей dynaconf или hydra;
  • требованиями к показателю переиспользования кода. С этой точки зрения преимущества на стороне библиотеки hydra;
  • гибкостью решения и одновременно простотой сопровождения кода. Здесь чаще используются библиотеки PyYAML и toml.

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

Несколько слов о синтаксисе YAML

Синтаксис YAML прост и лаконичен, но есть несколько особенностей. Практически каждый YAML-файл строится на базе списка. Каждый элемент списка это список пар «ключ-значение», который обычно называют словарем. То есть представление модели объекта с помощью YAML сводится к тому, чтобы описать эту модель в терминах списков и словарей.

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

Все элементы списка располагаются на одном и том же уровне и начинаются с - (тире и пробел):

start_end.yaml

         --- # Начало файла # Список фруктов - Apple - Orange - Strawberry - Mango ... # Конец файла     

Словари YAML представляют собой, как в и Python, наборы пар «ключ-значение» (за двоеточием должен следовать пробел):

dict.yaml

         # Запись о сотруднике martin:   name: Martin Johnson   job: Developer   skill: Elite     

YAML поддерживает стандартные типы данных: целочисленный (int), вещественный (float), булев (boolean), строковый (string) и null:

types.yaml

         integer: 25 float: 25.0 exponent: 12.3015e+05 boolean: Yes string: "25" infinity: .inf # бесконечность neginf: -.inf  # минус бесконечность     

При необходимости можно явно указывать тип данных значения с помощью конструкции !![тип данных], например:

  • pi: !!float 3.14159,
  • flag: !!bool false и т.д.

Булевы значения, могут иметь разные варианты записи, но рекомендуется использовать true и false, чтобы YAML-файл был совместим с настройками по умолчанию большинства YAML-линтеров:

supported_bools.yaml

         create_key: yes needs_agent: no knows_oop: True likes_emacs: TRUE uses_cvs: false     

В YAML необязательно заключать строковые константы в кавычки, но в ситуациях, когда требуется явно подчеркнуть строковую природу значения, кавычки не помешают. Допускается использовать как одинарные, так и двойные кавычки. Единственное отличие заключается в том, что двойные кавычки разрешают использовать управляющие коды строковых констант – их еще называют экранированными последовательностями – t (символ горизонтальной табуляции), r (символ возврата каретки), n (символ перехода на новую строку) и т.д.

Для работы с длинными строками используют символы | и >

multilines_and_one_long_line.yaml

         include_newlines: |             это действительно             три отдельные             строки fold_newlines: >             а это на самом деле одна             длинная строка, которая             выглядит как три отдельные     

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

anchor_alias.yaml

         hello: &hi 'hello' # вводится якорь hi greeting:   audience: 'world'   hello: *hi # применение якоря; hello получит строку 'hello'     

Псевдонимы можно задавать и для блоков:

anchor_for_block.yaml

         foo:   bar: &bar # псевдоним для блока     qux: 'quxqux'     baz: 'bazbaz' greeting:   audience: 'world'   bar: *bar # *bar развернется в словарь с ключами qux и baz     

С помощью ключа слияния <<: можно «наследовать» и переопределять разделы:

merge_key.yaml

         bar: &bar # вводится псевдоним блока   qux: 'quxqux'   baz: 'bazbaz' greeting:   audience: 'world'   bar:     <<: *bar # *bar развернется в словарь qux и baz     baz: 'notbaz' # НО baz перезапишется новым значением notbaz     

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

Порог входа высок, но за счет огромного количества плагинов и продуманной концепции редактора эффективность разработки увеличивается многократно. Детали работы с редактором можно узнать, например, из книгиНейла, Дрю «Практическое использование Vim».

Проверка типов управляющих параметров конфигурационного файла

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

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

Проверку типов можно организовать с помощью стандартной библиотеки Python dataclasses и сторонней библиотеки marshmallow_dataclass.

Рассмотрим простой пример использования marshmallow_dataclass, заимствованный со страницы проекта:

simple_example_marshmallow.py

         from dataclasses import dataclass, field from typing import List, Optional  import marshmallow_dataclass import marshmallow.validate   @dataclass class Building:     height: float = field(        metadata = {            "validate": marshmallow.validate.Range(min=0)         }     )     name: str = field(default="anonymous")   @dataclass class City:     name: Optional[str]     buildings: List[Building] = field(default_factory=list)    # создаем экземпляр схемы city_schema = marshmallow_dataclass.class_schema(City)() # city_schema => <City(many=False)> # загружаем словарь city = city_schema.load(     {         "name": "Paris",         "buildings": [{             "name": "Eiffel Tower",             "height": 324         }]     } ) # city => City(         name='Paris',         buildings=[             Building(                 height=324.0,                 name='Eiffel Tower'             )         ]      )  city.buildings # => [Building(height=324.0, name='Eiffel Tower')] city.buildings[0].height # 324.0     

Здесь класс Building содержит всего два атрибута: вещественный height и строковый name. С помощью метода marshmallow.validate выполняется проверка на минимальное значение атрибута height, а с помощью field атрибут name получает значение по умолчанию.

Класс City содержит опциональный атрибут name, который ожидает получить либо объект строкового типа, либо None. Атрибут buildings ожидает принять список объектов типа Building.

Далее создаем экземпляр схемы city_schema на базе объекта класса City, а затем загружаем словарь. Схема ожидает получить строку для атрибута name и список объектов Building, то есть список объектов, которые описываются строковым атрибутом name и вещественными атрибутом height.

Используя точечную нотацию и нотацию списков можно добраться до значений атрибутов.

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

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

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

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

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

konfiguracionnye fajly kak instrument upravlenija prilozhenijami na python 061c205 - 🐍 Конфигурационные файлы как инструмент управления приложениями на Python

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

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

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

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

В этом вопросе могут помочь:

  • DearPyGui: библиотека для разработки настольных приложений с графическим интерфейсом пользователя;
  • Streamlit: мощная библиотека для прототипирования браузерных решений с графическим интерфейсом.

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

Пример связки «конфигурационный YAML-файл + Python-приложение»

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

Для простоты гипотеза о выбросах проверяется с помощью классической стандартизованной Z-оценки и модифицированной робастной Z-оценки (англ.) на медиане. Для моделирования псевдослучайных процессов с гауссовским распределением ординат и корреляционными функциями заданного типа использовались алгоритмы, заимствованные из книги Быкова, В.В. «Цифровое моделирование в статистической радиотехнике».

Полный код примера с пояснениями и деталями реализации доступен в github-репозитории.

Вот его структура:

struct_repo.md

         . configs/   `- gauss_processes_acf.yaml figure_exapmples/   `- gauss_exp_acf.pdf   `- ... figures/   `- *.pdf python_scripts   `- main.py   `- helper_funcs_and_class_schema.py README.md      

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

gauss_proc_acf.yaml

         --- # *** MENU *** # Types of ACF (for `kind_acf`): # 1: exp type, # 2: exp-cos type, # 3: exp-cos-sin type (plus), # 4: exp-cos-sin type (minus)  # *** MAIN CONTROL PARAMETERS *** sigma: !!float 2            # standard deviation w_star: !!float 1.25        # model parameter w0: !!float 2.5             # model parameter alpha: !!float 0.05         # smoothing factor for EWMA window_width: !!int 14     # width of window in MA delta_t: !!float 0.05       # time step N: !!int 1000               # number of counts kind_acf: !!int 1           # ACF type   # *** OTHERS APP SETTINGS *** visibility:   ma_show: !!bool true  colors:   white: !!str &white "#FDFDFD"   grey: !!str &grey "#52616B"   blue_purple: !!str &blue_purple "#8785A2"   terakotta: !!str &terakotta "#E84A5F"   pearl_night: !!str &pearl_night "#112D4E"   krayola_green: !!str &krayola_green "#1CAC78"  figure_settings:   height_main_fig: !!int 7   width_main_fig: !!int 18   left_xlim_acf: !!float 0.   right_xlim_acf: !!float 4.   left_xlim_pdf: !!float -9   right_xlim_pdf: !!float 9 ...     

В figure_examples хранятся демонстрационные примеры работы сценария python_scripts/main.py, а прямые результаты его работы в – каталоге figures.

Управлять типом корреляционной функции процесса можно с помощью параметра kind_acf. Смысл остальных управляющих параметров (w_star, w0, alpha и т.д.) должен быть понятен из комментариев.

Для запуска приложения следует перейти в корневой каталог проекта и выполнить:

start_app.sh

         $ python python_scripts/main.py      --config-path configs/gauss_processes_acf.yaml      --output-fig-path figures/your_output_image_name.pdf      

Функция cmd_line_parser из модуля helper_funcs_and_class_schema.py прочитает значения флагов (--config-path, --output-fig-path), а затем вернет путь до конфигурационного файла и путь до файла с результатами анализа псевдослучайного процесса.

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

Повысить эффективность работы с конфигурационными YAML-файлами можно с помощью различных утилит (например, с помощью легковесной yq), но потоковый редактор sed, как правило, «из коробки» доступен на большинстве операционных систем.

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

sed_example.sh

         $ sed 's/w0: !!float 3.0/w0: !!float 3.15'      configs/gauss_processes_acf.yaml          > configs/gauss_expacf_w0=3.15.yaml     

Здесь sed ищет строку «w0: !!float 3.0», заменяет ее строкой «w0: !!float 3.15» и записывает результат (>) в новый конфигурационный файл.

На рисунках ниже приведены результаты работы Python-приложения с различными комбинациями управляющих параметров.

konfiguracionnye fajly kak instrument upravlenija prilozhenijami na python 5d43e07 - 🐍 Конфигурационные файлы как инструмент управления приложениями на Python

Сводка по анализу выбросов стационарного гауссовского псевдослучайного процесса с корреляционной функцией экспоненциального типа

konfiguracionnye fajly kak instrument upravlenija prilozhenijami na python c541b29 - 🐍 Конфигурационные файлы как инструмент управления приложениями на Python

Сводка по анализу выбросов стационарного гауссовского псевдослучайного процесса с корреляционной функцией экспоненциально-косинусного типа

konfiguracionnye fajly kak instrument upravlenija prilozhenijami na python f38798d - 🐍 Конфигурационные файлы как инструмент управления приложениями на Python

Сводка по анализу выбросов стационарного гауссовского псевдослучайного процесса с корреляционной функцией экспоненциально-косинусно-синусного типа (минус)

konfiguracionnye fajly kak instrument upravlenija prilozhenijami na python a403066 - 🐍 Конфигурационные файлы как инструмент управления приложениями на Python

Сводка по анализу выбросов стационарного гауссовского псевдослучайного процесса с корреляционной функцией экспоненциально-косинусно-синусного типа (плюс)

Заключение

Из руководства вы узнали:

  • какие из существующих форматов конфигурационных файлов могут пригодится в роли текстового интерфейса к Python-приложениям;
  • какие существуют библиотеки для работы с конфигурационными файлами и где проходит граница области применимости каждой из них;
  • как использовать выразительный синтаксис YAML-файлов – якоря, псевдонимы, ключи слияния – для упрощения описания модели объектов;
  • в каких сценариях имеет смысл использовать связку «конфигурационный файл + Python-приложение» и в чем сильная сторона такого подхода;
  • как может выглядеть пример использования текстовых интерфейсов в задаче обнаружения выбросов;
  • а также, как «винтажные» инструменты – Vim и sed – могут повысить эффективность редактирования текстовых файлов.

Полезные источники:

  • From Novice to Expert: How to Write a Configuration file in Python
  • YAML Syntax with Ansible
  • Наглядно о том, как Vim рвёт в щепки Sublime, Atom, PyCharm
  • Кобзарь, А.И. Прикладная математическая статистика, 2012
  • Templating YAML in Kubernetes with real code
  • Github-репозиторий с кодом рассмотренного примера о выбросах случайного гауссовского процесса

Связные материалы с платформы Proglib:

  • Все, что нужно знать о декораторах
  • Преобразования Фурье для обработки сигналов с помощью Python

  • 37 views
  • 0 Comment

Leave a Reply

Π’Π°Ρˆ адрСс email Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½. ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ поля ΠΏΠΎΠΌΠ΅Ρ‡Π΅Π½Ρ‹ *

Π­Ρ‚ΠΎΡ‚ сайт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Akismet для Π±ΠΎΡ€ΡŒΠ±Ρ‹ со спамом. Π£Π·Π½Π°ΠΉΡ‚Π΅, ΠΊΠ°ΠΊ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ΡΡ ваши Π΄Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠ΅Π².

Categories 05.

Π‘Π²ΡΠ·Π°Ρ‚ΡŒΡΡ со ΠΌΠ½ΠΎΠΉ
Close