Создание пользовательского блока
Описание
Создание пользовательского блока — это процесс создания нового блока в Puzzle RPA, который позволяет пользователям создавать свои собственные блоки для использования в процессах.
Перечень действий для создания пользовательского блока
- Требуется создать папку с именем блока (например
hello_my_block). - Внутри папки создать структуру файлов (см. ниже).
- Наполнить файлы
block.json,values.xml,code.value.py(илиcode.py),meta.json,libs.py.json,typeToName.json. - Добавить код в
src/__init__.py. - (Опционально) Указать зависимости в
requirements.txtи поместить готовые wheels вwheels/. - Импортировать папку в Puzzle RPA через Настройки → Расширения.
- Перезагрузить Puzzle RPA и проверить блок в тулбоксе.
Структура папки блока
hello_my_block/ # имя папки - обычно совпадает с type блока├─ block.json├─ code.value.py # или code.py├─ meta.json├─ libs.py.json├─ values.xml├─ typeToName.json├─ requirements.txt # опционально├─ wheels/ # опционально, *.wls файлы└─ src/ # папка для python - скриптов и вспомогательных файлов └─ __init__.pyНазначение файлов
block.json- JSON-описание внешнего вида блока;code.value.py/code.py- строка/код, который будет встраиваться в сгенерируемый Python (вызов функции изcode-storage-py);libs.py.json- список импортируемых модулей изcode-storage-py;meta.json- режим, флаги логирования и поведение генерации;values.xml- XML-описание разъёмов/тулбокса (shadow/начальные блоки);typeToName.json- отображаемое название блока для логов/информации;requirements.txt- файл описывающий дополнительные python библиотеки и их версии которые используются блоком;wheels/- папка с wheel-пакетами которые используются блоком;src/- папка для python - скриптов и вспомогательных файлов;src/__init__.py- реализация функций, вызываемых блоком (c декораторами логгера).
Создание файла block.json
type- уникальное имя блока; должно совпадать с именем папки и с<block type="...">вvalues.xml.message0- текст блока; параметры (разъёмы блока) указываются как%1,%2и т.д. Например, “Умножить %1 на 2”.args0: массив описаний разъёмов/полей.inputsInline:true/false— располагает ли разъёмы в одну строку.output- ключ со значениемnullдля блока возвращающего значение.previousStatement- ключ со значениемnullдля блока который может иметь предыдущее соединение сверху (обозначенное выемкой).nextStatement- ключ со значениемnullдля блока который следующее соединение снизу (обозначенное вкладкой).colour: цвет блока в HEX.tooltip- текст подсказки который будет отображаться при наведении на блок.helpUrl- URL справки по блоку.
Пример block.json для блока, который умножает число на 2:
{ "type": "hello_double", "message0": "Умножить %1 на 2 %2", "args0": [ { "type": "input_value", "name": "VALUE1" }, { "type": "input_dummy" } ], "inputsInline": true, "output": null, "colour": "#4A90E2", "tooltip": "Умножает число на 2", "helpUrl": ""}Примечания и типичные параметры args0
input_dummy- пустая строка/видимый текст в блоке (используется для описаний).
{ "type": "input_dummy"}input_value- поле для подсоединения блока со значением (value).
{ "type": "input_value", "name": "VALUE1"}input_statement- для вложенных блоков (statement/тело).
{ "type": "input_statement", "name": "DO"}field_dropdown- выпадающий список (нужны опции вoptions).
{ "type": "field_dropdown", "name": "MODE", "options": [ [ "Опция A", "A" ], [ "Опция B", "B" ] ]}field_checkbox- чекбокс (логическое значение).
{ "type": "field_checkbox", "name": "ENABLED", "checked": true}field_number- числовое поле.
{ "type": "field_number", "name": "NUM", "value": 10, "min": 0, "max": 100, "precision": 1}field_text- текстовое поле.
{ "type": "field_text", "name": "TEXT", "text": "Пример"}field_variable- поле переменных.
{ "type": "field_variable", "name": "VAR", "variable": "item"}field_code_editor- поле для редактирования кода.
{ "type": "field_code_editor", "name": "CODE"}field_image- поле для отображения изображения (Требуется base64 строка изображения, width и height в пикселях, alt - текст изображения когда блок свернут).
{ "type": "field_image", "src": "data:image/png+xml;base64,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", "width": 25, "height": 25, "alt": "SQL"}Создание файла code.value.py / code.py
- Если блок возвращает значение — используем
code.value.py. - Если блок не возвращает значение — используем
code.py.
Синтаксис (строка, которая будет вставлена в сгенерированный код)
${vc('VALUE1')}- метка для кодогенерации: значение из разъёмов типа input_value.${fv('FIELD1')}- метка для кодогенерации: значение из полей типа field_text, field_number, field_variable, field_dropdown, field_checkbox.${sc('DO')}- метка для кодогенерации: код из блока типа input_statement (для вложенных блоков).#isInternalLog- специальный маркер для передачи параметра логирования (обычно последний аргумент).
Пример code.value.py (вызов функции из модуля hello_double):
hello_double.double_value(${vc('VALUE1')},#isInternalLog)Примечания:
- Если нужно передать несколько аргументов — перечислить:
${vc('VALUE1')}, ${vc('VALUE2')}. - Если требуется обернуть значения полей типа fv в кавычки, то используйте
'${fv('FIELDVALUE1')}'
Создание файла libs.py.json
- Формат: JSON-массив путей модулей, которые нужно импортировать в сгенерированный код (модули из
code-storage-py). - Префикс
$/означает путь внутри code-storage (пример используемой практики).
Пример:
[ "$/hello_double"]Примечания:
- Откуда брать имена? — соответствуют именам модулей в
code-storage-py.
Создание файла meta.json
Описание ключей:
_modeсо значением"value"— блок возвращает значение (используетсяcode.value.py)._isInternalLogсо значениемtrue/false— включить внутреннее логирование для блока._isDontUseLoggerсо значениемtrue— блок не должен писать лог (подавляет логирование)._onIfUseFuncсо значениемfalse— устаревший флаг (требуется всегда указыватьfalse).
Пример:
{ "_mode": "value", "_isInternalLog": true, "_onIfUseFunc": false,}Условия использования ключей:
| Задача | Рекомендация |
|---|---|
| Блок возвращает значение | _mode: "value" |
| Блок просто выполняет действие | не указывать _mode |
| Нельзя логировать | _isDontUseLogger: true |
| Лог нужен | _isInternalLog: true |
Создание файла typeToName.json
- Служит для записи читаемого названия блока в логах.
- Формат:
{"type_name": "Читаемое название"}.
Пример:
{ "hello_double": "Умножить число на 2"}Создание файла values.xml
- Описывает как блок выглядит в тулбоксе, какие теневые блоки (
shadow) или обычные блоки (block) подставлять в разъёмы блока.
Пример описания блока hello_double в values.xml:
<block type="hello_double"> <value name="VALUE1"> <shadow type="math_number"> <field name="NUM">2</field> </shadow> </value></block>Примеры разных типов полей в values.xml
<!-- Текстовое поле --><shadow type="text"> <field name="TEXT"></field></shadow>
<!-- Числовое поле --><shadow type="math_number"> <field name="NUM">10</field></shadow>
<!-- Переменная --><block type="variables_get"> <field name="VAR">myVar</field></block>Создание файла requirements.txt и wheels/
- Если блок использует библиотеки, отсутствующие в окружении Puzzle RPA, укажите их в файле
requirements.txt. - В папке
wheels/размещаются собранные.whlфайлы совместимых с версией Python (3.11) и операционной системой.
Рекомендации:
- Минимизируйте внешние зависимости.
- Если библиотека уже присутствует в Puzzle RPA — не добавляйте её в файл
requirements.txt, чтобы не вызвать конфликты. - В документации/репозитории проекта храните актуальный список предустановленных библиотек.
Пример содержимого файла requirements.txt:
pandas==2.2.3numpy==1.24.3Создание файла src/__init__.py — реализация функций
- Внутри находятся функции, которые вызываются из файлов
code.value.py/code.py. - Для логирования используются декораторы из модуля
puzzle_logger.
Пример реализации:
from puzzle_logger import log_decorator, window_logger
@window_logger@log_decoratordef double_value(value, puzzle_logger_path=None, block_text=None, block_id=None, window_log=False, **kwargs): if isinstance(value, (int, float)): return value * 2
if isinstance(value, str): try: return float(value) * 2 except ValueError: raise ValueError(f"Некорректный аргумент: '{value}' не является числом")
raise TypeError(f"Тип '{type(value).__name__}' не поддерживается")Примечания:
- Всегда ставьте параметры
puzzle_logger_path=None, block_text=None, block_id=None, window_log=Falseпосле основных параметров, если хотите корректный лог. - Логирование и обработка ошибок важны для поддержки и диагностики блока.
Типичные ошибки и как их избежать
- Не совпадают имена:
typeвblock.json, имя вtypeToName.jsonи<block type>вvalues.xmlдолжны совпадать — иначе блок не подключится или не будет логироваться. Имя папки с файлами расширения должно соответствоватьtypeвblock.json. - Неправильный формат JSON — синтаксис JSON, пути к модулям должны быть корректны.
- Запутанные зависимости — разные версии библиотек в
requirements.txtмогут конфликтовать с системными. Тестируйте на отдельном стенде. - Отсутствуют ключи описания полей или функции не экспортируются — убедитесь, что функция и ключи описания полей существуют и их имена совпадают с вызовом в
code.value.py/code.py. - Блок не появляется в тулбоксе — в чём причина? Часто: ошибки в
values.xml, несовпадениеtype, синтаксическая ошибка вblock.json.
Минимальный шаблон (готовые файлы) — папка hello_double
- Скачать пример блока — hello_double.zip — и распаковать архив в папку блока (например
hello_double). Либо создать папку и файлы вручную по этой инструкции. - Импортировать папку в Puzzle RPA: “Настройки → Расширения”.
Файл: block.json
{ "type": "hello_double", "message0": "Умножить %1 на 2 %2", "args0": [ { "type": "input_value", "name": "VALUE1" }, { "type": "input_dummy" } ], "inputsInline": true, "output": null, "colour": "#4A90E2", "tooltip": "Умножает число на 2", "helpUrl": ""}Файл: values.xml
<block type="hello_double"> <value name="VALUE1"> <shadow type="math_number"> <field name="NUM">2</field> </shadow> </value></block>Файл: code.value.py
hello_double.double_value(${vc('VALUE1')},#isInternalLog)Файл: libs.py.json
[ "$/hello_double"]Файл: meta.json
{ "_mode": "value", "_isInternalLog": true, "_onIfUseFunc": false,}Файл: typeToName.json
{ "hello_double": "Умножить на 2"}Файл: __init__.py
from puzzle_logger import log_decorator, window_logger
@window_logger@log_decoratordef double_value(value, puzzle_logger_path=None, block_text=None, block_id=None, window_log=False, **kwargs): if isinstance(value, (int, float)): return value * 2
if isinstance(value, str): try: return float(value) * 2 except ValueError: raise ValueError(f"Некорректный аргумент: '{value}' не является числом")
raise TypeError(f"Тип '{type(value).__name__}' не поддерживается")