Общая информация
«Модули Python» — функциональная возможность, предназначенная для обработки и загрузки данных в систему из произвольных источников, с помощью скриптов Python.
Запуск и обработка результатов работы «Модуля Python» осуществляется с помощью «Агента ETL», подробнее см. раздел «».
Требования к окружению
Для корректной работы Модуля Python, требуется:
| Наименование |
Версии |
Дополнительная информация |
| Операционная система Microsoft Windows |
7 - 10 |
Подробные технические требования приведены в разделе «». |
| Операционная система семейства Linux |
- Ubuntu 16.x – 18.x
- RedHat 7.x или другой Linux
|
| Агент ETL |
1.34.21 и выше |
Подробные технические требования приведены в разделе
«». |
| Python |
3 и выше |
Виртуальное окружение Python конфигурируется самостоятельно!
До выбора окружения необходимо подготовить само окружение. Это необходимо сделать на сервере с Агентом ETL.
Порядок установки:
- После установки Агента ETL будет создан файл настроек агента
settings.json и каталоги модулей Python: extract-modules и machine-learning.
- Для Windows:
- они будут созданы в каталоге Агента ETL.
- Для Linux:
settings.json – по пути /etc/agentetl/;
- каталог
/opt/agentetl/python/machine-learning/;
- каталог
/opt/agentetl/python/extract-modules/.
- Создать 2 виртуальных окружения: в каталогах
machine-learning и extract-modules и установить в них зависимости согласно файлу requirements.txt.
- Перейти в каталог
machine-learning:
cd /opt/agentetl/python/machine-learning/ Для Windows это будет каталог, куда был установлен Агент ETL.
- Создать виртуальное окружение:
Python –m venv venv (алиас Python может различаться в зависимости от того, что указано в системе, например Python3 или py).
- Активировать виртуальное окружение:
- Windows:
venv\Scripts\activate;
- Linux:
source venv/bin/activate.
- Установить зависимости согласно файлу
requirements.txt:
- Если необходимо установить дополнительные зависимости, их нужно добавить в файл
requirements.txt перед выполнением команды установки. Обратите внимание! openpyxl - приведено как пример установки зависимости:
openpyxl== 3.1.3 - если нужна конкретная версия;
openpyxl – если подходит текущая последняя версия;
openpyxl>= 3.1.3 – если нужна версия больше указанной.
- Команда установки зависимостей из файла
requirements.txt:pip install -r requirements.txt. В случае необходимости доустановить зависимости, добавляем зависимость в requirements.txt и выполняем команду заново.
- Перейти в каталог
extract-modules:
cd /opt/agentetl/python/extract-modules/.
- Выполнить пункты 2.2 – 2.4 для каталога
extract-modules.
- Заполнить
settings.json.
Файл представляет из себя json-файл:
{
"Addr": ":8000",
"AddrForCallBack": "",
"TLSCertFile": "",
"TLSKeyfile": "",
"Login": "user",
"Password": "123",
"LogFile": "log.txt",
"SaveStatsToFile": "",
"Servers": [],
"ETLLogURL": "",
"ETLLogInterval": 30,
"ETLSuccessURL": "",
"Capacity": 200000,
"Workers": 50,
"Bulksize": 0,
"WorkingDir": "",
"MLPython": "venv\\Scripts\\python3.exe",
"ExtractPython": "",
"Databases": {
"Vertica" : {
"InMemoryResultRowlomit": 200000,
"CopyBlockSize": 65536
}
}
}
Подробное описание назначения параметров, см. в разделе «» подраздел «Настройка параметров Агента ETL».
Строки настроек для работы Python:
- "
MLPython": "Путь до исполняемого файла python виртуального окружения каталога machine-learning";
- "
ExtractPython": "Путь до исполняемого файла python виртуального окружения каталога extract-modules".
Пример заполнения данных настроек для Linux:
- "
WorkingDir": "/opt/agentetl";
- "
MLPython": "venv\\Scripts\\python3.exe";
- "
ExtractPython": "venv\\Scripts\\python3.exe".
Обратите внимание! Если параметр "WorkingDir" заполнен, тогда параметры "MLPython" и "ExtractPython" заполняются относительно пути "WorkingDir".
|
Настройка справочника «Модули Python»
Для работы с модулем Python нажмите в верхнем меню «Главное», выберите выпадающий список «Настройки» и перейдите в раздел «Модули Python».

В отобразившемся разделе создайте новый модуль при помощи кнопки «Создать» (1) или «Создать новый элемент копированием текущего» (2).

В отобразившейся форме создания заполнение поле «Наименование». Если необходимо использовать отдельное виртуальное окружение, то нужно заполнить поле «Окружение», подробнее см. подраздел «Создание виртуальных окружений Python».

При нажатии на «Показать все» у поля «Окружение» отобразится форма выбора окружения. При необходимости создания нового окружения нажмите на кнопку «Создать».

В отобразившейся форме заполните поле «Наименование», а в поле «Исполняемый файл python» укажите путь до интерпретатора Python на сервере с «Агентом ETL».

Заполните и закройте форму, выберите окружение.
На вкладке «Скрипт» введите код.

Шаблоны скриптов
В окружении устанавливаются разные библиотеки. Окружение создается на сервере с установленным «Агентом ETL» и путь до него задается с учетом этого. Одновременно может быть развернуто несколько виртуальных окружений Python, каждое из которых содержит свою версию Python и свой набор пакетов.
Примечание — для корректной работы шаблонов кода в справочнике «Модули Python» требуются установить следующие библиотеки в каталог extract-modules, подробнее см. «Создание виртуальных окружений Python»:
В качестве примеров скриптов можно использовать шаблоны. Для этого нажмите на кнопку «Заполнить из шаблона» и выберите необходимый вариант, отобразится скрипт:

Скрипт шаблона базы данных
from typing import Dict, Union
from sqlalchemy import create_engine, text
from api import (
ParametersClass, ParameterClass, ParameterItemsClass, ColumnsClass, TrivialType,
ColumnClass, DataSourceClass, TableDataClass, TypeDescription, Source
)
def get_params() -> ParametersClass:
# Создаем несколько параметров для пользователя
td_str = TypeDescription(precision=0, length=100, contain_time=False, data_type=TrivialType.ttString )
td_number = TypeDescription(precision=10, length=100, contain_time=False, data_type=TrivialType.ttNumber )
td_integer = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttInteger )
td_date = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttDate )
td_datetime = TypeDescription(precision=0, length=0, contain_time=True, data_type=TrivialType.ttDatetime )
variables = [
ParameterClass(index=0, name="is_active", type_desc=td_integer, value=1),
]
# Оборачиваем в VariableItemsClass
items = ParameterItemsClass(variables)
return ParametersClass(items=items)
def get_structure_table(params: ParametersClass) -> DataSourceClass:
is_active = params[0].Value # Получаем значение для поля "is_active"
# Базовые колонки
td = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttInteger )
td_str = TypeDescription(precision=0, length=100, contain_time=False, data_type=TrivialType.ttString )
columns = [
ColumnClass(index=0, name="Age", type_desc=td),
ColumnClass(index=1, name="Name", type_desc=td_str),
]
# Создаем объект таблицы
columns_class = ColumnsClass(columns)
table = DataSourceClass(columns=columns_class)
# Возвращаем созданную таблицу
return table
def get_data(
params: ParametersClass,
table_structure: DataSourceClass,
source: Source,
context: Dict[str, Union[int, float, bool, str]],
) -> TableDataClass:
query_params = {param.Name: param.Value for param in params.Items}
engine = create_engine(f"postgresql+psycopg2://{source.Login}:{source.Password}@{source.Address}/{source.Database}")
table = TableDataClass(table_structure)
with engine.connect() as engine.connection:
query = text("SELECT Name, Age FROM table_test")
result = engine.connection.execute(query, query_params)
rows = result.mappings().all()
for row in rows:
data = []
for column in table.iter_columns():
data.append(row.get(column.Name))
table.AddRow(data)
return table
Скрипт шаблона веб-сервиса
from typing import Dict, Union
import requests
from api import (
ParametersClass, ParameterClass, ParameterItemsClass, ColumnsClass, TrivialType,
ColumnClass, DataSourceClass, TableDataClass, TypeDescription, Source
)
def get_params() -> ParametersClass:
# Создаем несколько переменных для пользователя
td_str = TypeDescription(precision=0, length=100, contain_time=False, data_type=TrivialType.ttString )
td_number = TypeDescription(precision=10, length=100, contain_time=False, data_type=TrivialType.ttNumber )
td_integer = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttInteger )
td_date = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttDate )
td_datetime = TypeDescription(precision=0, length=0, contain_time=True, data_type=TrivialType.ttDatetime )
variables = [
ParameterClass(index=0, name="test_param", type_desc=td_integer, value=1),
]
# Оборачиваем в VariableItemsClass
items = ParameterItemsClass(variables)
return ParametersClass(items=items)
def get_structure_table(params: ParametersClass) -> DataSourceClass:
# Базовые колонки
td = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttInteger)
td_str = TypeDescription(precision=0, length=200, contain_time=False, data_type=TrivialType.ttString)
columns = [
ColumnClass(index=0, name="ID", type_desc=td_str),
ColumnClass(index=1, name="Name", type_desc=td_str),
ColumnClass(index=2, name="Photo", type_desc=td_str),
ColumnClass(index=3, name="Status", type_desc=td_str),
]
# Создаем объект таблицы
columns_class = ColumnsClass(columns)
table = DataSourceClass(columns=columns_class)
# Возвращаем созданную таблицу
return table
def get_data(
params: ParametersClass,
table_structure: DataSourceClass,
source: Source,
context: Dict[str, Union[int, float, bool, str]],
) -> TableDataClass:
table = TableDataClass(table_structure)
response = requests.get(source.Address)
# https://petstore.swagger.io/v2/pet/findByStatus?status=available
data = response.json()
for pet in data[:10]:
table.AddRow([
pet['id'],
pet['name'],
pet['photoUrls'][0] if pet['photoUrls'] else '',
pet['status'],
])
return table
Скрипт шаблона файла
from typing import Dict, Union
import re
from api import (
ParametersClass, ParameterClass, ParameterItemsClass, ColumnsClass, TrivialType,
ColumnClass, DataSourceClass, TableDataClass, TypeDescription, Source
)
def get_params() -> ParametersClass:
# Создаем несколько параметров для пользователя
td_str = TypeDescription(precision=0, length=100, contain_time=False, data_type=TrivialType.ttString )
td_number = TypeDescription(precision=10, length=100, contain_time=False, data_type=TrivialType.ttNumber )
td_integer = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttInteger )
td_date = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttDate )
td_datetime = TypeDescription(precision=0, length=0, contain_time=True, data_type=TrivialType.ttDatetime )
variables = [
ParameterClass(index=0, name="test_param", type_desc=td_str, value="some string"),
]
# Оборачиваем в VariableItemsClass
items = ParameterItemsClass(variables)
return ParametersClass(items=items)
def get_structure_table(params: ParametersClass) -> DataSourceClass:
# Базовые колонки
td = TypeDescription(precision=0, length=0, contain_time=False, data_type=TrivialType.ttInteger)
td_str = TypeDescription(precision=0, length=100, contain_time=False, data_type=TrivialType.ttString)
columns = [
ColumnClass(index=0, name="Name", type_desc=td_str),
ColumnClass(index=1, name="INN", type_desc=td_str),
ColumnClass(index=2, name="Phone", type_desc=td_str),
]
# Создаем объект таблицы
columns_class = ColumnsClass(columns)
table = DataSourceClass(columns=columns_class)
# Возвращаем созданную таблицу
return table
def get_data(params: ParametersClass, table_structure: DataSourceClass, source: Source, context: Dict[str, Union[int, float, bool, str]]) -> TableDataClass:
table = TableDataClass(table_structure)
with open(source.Address, 'r', encoding='utf-8') as f:
text = f.read()
table.AddRow([
re.search('Наименование: (.*)', text).group(0),
re.search('ИНН: (.*)', text).group(0),
re.search('Телефон: (.*)', text).group(0),
])
return table
Контракт шаблона
Шаблоны дают представление о том, как должен выглядеть файл Python. В нем подготавливаются 3 функции:
get_params;
get_structure_table;
get_data.
Функции get_params, get_structure_table, get_data
Предоставляет «Modus ETL» список параметров для доступа к данным и их дефолтные значения.
В функции заданы основные типы данных (td_str, td_number, td_integer...) в качестве примера, на их основе можно конструировать свои типы, указывая нужные величины length (длина строки/числа) и precision (точность для дробного числа).
Сами параметры мы помещаем в список variables, каждое значение представляет собой инициализированный класс ParameterClass. Все аргументы инициализации - обязательные.
variables = [
ParameterClass(index=0, name="is_active", type_desc=td_integer, value=1),
]
Если нам не нужны параметры, то список variables оставляем пустым.
Предоставляет пользователю «Modus ETL»перечень колонок результирующей таблицы.
Список типов задается так же, как и в функции get_params.
Поля помещаем в список columns.
В функции заполняется таблица с данными. Здесь должна находится основная логика по работе с данными. Итогом выполнения функции должна стать возвращаемая таблица - экземпляр класса TableDataClass.
Входящие параметры get_data:
params: ParametersClass — параметры сбора данных;
table_structure: DataSourceClass — структура результирующей таблицы;
-
Length: Optional[int] — длина значения;
-
Precision: Optional[int] — точность значения;
-
ContainTime: bool — содержит время (deprecated):
Data: List[List[Union[bool, int, str, float, datetime.datetime, None]]]
Get(row: int, col: Union[int, str]) -> Union[bool, int, str, float, datetime.datetime, None] - Возвращает значение ячейки по строке и колонке
GetColumn(col: Union[int, str]) -> ColumnClass - Возвращает колонку по индексу или имени
IsNull(row: int, col: Union[int, str]) -> bool - Проверяет, является ли ячейка пустой
-
source: Source — параметры источника данных:
-
Address: str — адрес БД, файла, веб-сервиса, и.т.п.;
-
Database: str — база данных;
-
Login: str — логин к БД;
-
Password: str — пароль к БД;
-
Timeout: int — таймаут вызова БД/сервиса;
-
SecureMode: str — параметр подключения;
-
SkipVerify: bool — параметр подключения;
-
MaxConns: int — максимальное число соединений;
-
DefSchema: str — схема подключения;
-
Protocol: str — протокол подключения;
-
AdditionalProperties: Dict[str, str] — дополнительные параметры подключения;
-
FileName: str — имя файла;
-
Kind: str — тип файла;
-
DataId: str — id данных файла во временном хранилище сессии.
-
context: Dict[str, Union[int, float, bool, str]] — произвольные переменные контекста.
При замене уже имеющегося скрипта отобразиться форма с подтверждением замены скрипта шаблоном. Подтвердите замену нажатием на кнопку «Да» либо нажмите на кнопку «Нет» для отмены.

На вкладке «Описание» возможно написать комментарий с описанием модуля.

Нажмите на кнопку «Записать и закрыть» — модуль создан.
Далее при установке правил выгрузки вы сможете установить вид правила «Модуль Python», как описано в разделе «».