diff --git a/core/__init__.py b/core/__init__.py index d10217c..0e9b91a 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,6 +1,8 @@ from .vork_node import VorkNode from .vork_node_registry import VorkNodeRegistry from .vork_node_link import VorkNodeLink +from .vork_node_test import VorkNodeTest +from .link_name_generator import edge_title_generator, edge_title_to_number __version__ = "0.1.0" __author__ = "Your Name" @@ -9,4 +11,7 @@ __all__ = [ "VorkNode", "VorkNodeRegistry", "VorkNodeLink", + "VorkNodeTest", + "edge_title_generator", + "edge_title_to_number", ] diff --git a/core/link_name_generator.py b/core/link_name_generator.py new file mode 100644 index 0000000..c53d10d --- /dev/null +++ b/core/link_name_generator.py @@ -0,0 +1,12 @@ +def edge_title_generator(counter: int) -> str: + chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + num = (counter - 1) // len(chars) + 1 + letter_index = (counter - 1) % len(chars) + return f"{chars[letter_index]}{num}" + +def edge_title_to_number(title: str) -> int: + chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + letter = title[0].upper() + number = int(title[1:]) + letter_index = chars.index(letter) + return letter_index + 1 + (number - 1) * len(chars) diff --git a/core/vork_node_link.py b/core/vork_node_link.py index 063fefc..74bc757 100644 --- a/core/vork_node_link.py +++ b/core/vork_node_link.py @@ -1,20 +1,84 @@ -from typing import Optional, TYPE_CHECKING -from .vork_node import VorkNode +from typing import Dict, Any -if TYPE_CHECKING: - from .vork_node_registry import VorkNodeRegistry +from model_nodes import VorkNodeLinkData, VorkNodeLinkSchema + + +from .link_name_generator import edge_title_generator, edge_title_to_number class VorkNodeLink: - def __init__(self, link_id: str, node_from: Optional[VorkNode] = None, node_to: Optional[VorkNode] = None): - self.id: str = link_id - self.node_from: Optional[VorkNode] = node_from - self.node_to: Optional[VorkNode] = node_to + def __init__(self, data: Dict[str, Any]): + """ + Инициализация связи между узлами + """ + self.data = data or {} - def resolve(self, registry: 'VorkNodeRegistry') -> None: - if not hasattr(self.node_from, 'id') or not hasattr(self.node_to, 'id'): - raise ValueError("Both nodes in link must have 'id' attribute") + def generate_link_name(self, link_name:int) -> str: - def __repr__(self) -> str: - return f"VorkNodeLink(id='{self.id}', from={self.node_from.id}, to={self.node_to.id})" + return edge_title_generator(link_name) + + def get_link_number(self, link_name: str) -> int: + + return edge_title_to_number(link_name) + + # @classmethod + # def form(cls) -> VorkNodeLinkSchema: + # """ + # Возвращает схему связи для UI + + # """ + # return VorkNodeLinkSchema() + + def validate(self) -> VorkNodeLinkSchema: + """ + Валидирует данные связи с помощью Pydantic моделей + + """ + try: + # Валидируем данные + validated_data = self.validate_data() + + # Проверяем бизнес-логику связи + if validated_data.parent_port_number is not None and validated_data.parent_port_number < 0: + raise ValueError("Parent exit number must be non-negative") + + if not validated_data.from_id: + raise ValueError("from_id must be set") + + if not validated_data.to_id: + raise ValueError("to_id must be set") + + # Генерируем имя связи, если оно не указано + if not validated_data.last_link_name: + new_link_name = self.generate_link_name(1) + # Обновляем данные с новым именем + self.data['last_link_name'] = new_link_name + # Перевалидируем данные + validated_data = self.validate_data() + else: + old_link_name = edge_title_to_number(validated_data.last_link_name) + new_link_name = self.generate_link_name(old_link_name + 1) + self.data['last_link_name'] = new_link_name + validated_data = self.validate_data() + + # Создаем схему с валидированными данными + return VorkNodeLinkSchema( + link_name=validated_data.last_link_name, + parent_port_number=validated_data.parent_port_number, + to_id=validated_data.to_id, + from_id=validated_data.from_id, + ) + + except Exception as e: + print(f"Link validation error: {e}") + raise + + def validate_data(self) -> VorkNodeLinkData: + """ + Валидирует данные связи + + Returns: + VorkNodeLinkData: Валидированные данные + """ + return VorkNodeLinkData(**self.data) diff --git a/core/vork_node_registry.py b/core/vork_node_registry.py index 5586f3f..43a27d6 100644 --- a/core/vork_node_registry.py +++ b/core/vork_node_registry.py @@ -1,7 +1,7 @@ import importlib import inspect -import os -from typing import Dict, Type, Optional +import pkgutil +from typing import Dict, Type, Optional, List from .vork_node import VorkNode @@ -9,6 +9,8 @@ class VorkNodeRegistry: def __init__(self): self.registry: Dict[str, Type[VorkNode]] = {} + # Автоматически сканируем пакет 'nodes' при создании + self._auto_discover_nodes() def get_all(self) -> Dict[str, Type[VorkNode]]: return self.registry.copy() @@ -16,27 +18,6 @@ class VorkNodeRegistry: def get(self, node_type: str) -> Optional[Type[VorkNode]]: return self.registry.get(node_type) - def auto_discover_from_directory(self, directory_path: str, package_name: str = None) -> None: - if not os.path.exists(directory_path): - print(f"Директория {directory_path} не существует") - return - - for filename in os.listdir(directory_path): - if filename.endswith('.py') and not filename.startswith('__'): - module_name = filename[:-3] - - if package_name: - full_module_name = f"{package_name}.{module_name}" - else: - full_module_name = module_name - - try: - module = importlib.import_module(full_module_name) - self._discover_in_module(module) - except ImportError as e: - print(f"Ошибка импорта модуля {full_module_name}: {e}") - except Exception as e: - print(f"Ошибка при сканировании модуля {full_module_name}: {e}") def _discover_in_module(self, module) -> None: for name, obj in inspect.getmembers(module): @@ -47,9 +28,45 @@ class VorkNodeRegistry: try: node_id = obj({}, {}).id self.registry[node_id] = obj - print(f"Обнаружен узел: {node_id} -> {obj.__name__}") + # print(f"Обнаружен узел: {node_id} -> {obj.__name__}") except Exception as e: print(f"Ошибка при получении ID для {obj.__name__}: {e}") + def _auto_discover_nodes(self) -> None: + """ + Автоматически обнаруживает все VorkNode классы в пакете 'nodes' + Вызывается автоматически при создании реестра + """ + try: + package = importlib.import_module('nodes') + package_path = getattr(package, '__path__', None) + + if package_path: + # Сканируем все модули в пакете nodes + for importer, modname, ispkg in pkgutil.iter_modules(package_path, "nodes."): + try: + module = importlib.import_module(modname) + self._discover_in_module(module) + except Exception as e: + print(f"Ошибка при сканировании модуля {modname}: {e}") + + except ImportError as e: + print(f"Ошибка импорта пакета 'nodes': {e}") + except Exception as e: + print(f"Ошибка при сканировании пакета 'nodes': {e}") + + def get_available_node_types(self) -> List[str]: + """ + Возвращает список всех доступных типов узлов + + Returns: + List[str]: Список типов узлов + """ + return list(self.registry.keys()) + def clear(self) -> None: + """ + Очищает реестр и повторно сканирует пакет 'nodes' + """ self.registry.clear() + self._auto_discover_nodes() diff --git a/core/vork_node_test.py b/core/vork_node_test.py new file mode 100644 index 0000000..febbb37 --- /dev/null +++ b/core/vork_node_test.py @@ -0,0 +1,49 @@ +from typing import Dict, Any +from .vork_node import VorkNode +from model_nodes.node_test_models import ( + TestNodeData, + TestNodeCoreSchema, + TestNodeCoreSchemaData +) + + +class VorkNodeTest(VorkNode): + + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла test + """ + super().__init__(data, links or {}) + + @property + def id(self) -> str: + return "TEST" + + @classmethod + def form(cls) -> TestNodeCoreSchema: + """ + Возвращает схему узла test для UI + """ + return TestNodeCoreSchema() + + def validate(self) -> TestNodeCoreSchema: + """ + Валидирует данные узла test и возвращает схему + """ + try: + validated_data = self.validate_data() + node_data = TestNodeCoreSchemaData(node_port_number=0) + return TestNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + data=node_data + ) + except Exception as e: + print(f"Test node validation error: {e}") + raise + + def validate_data(self) -> TestNodeData: + return TestNodeData(**self.data) + + def process(self, context): + pass diff --git a/model_nodes/__init__.py b/model_nodes/__init__.py new file mode 100644 index 0000000..fb99513 --- /dev/null +++ b/model_nodes/__init__.py @@ -0,0 +1,165 @@ +# Экспорты для моделей узла listen +from .node_listen_models import ( + ListenNodeData, + ListenNodeLinks, + ListenNodeCoreSchema, + ListenNodeCoreSchemaData +) + +# Экспорты для моделей узла trigger +from .node_trigger_models import ( + TriggerNodeData, + TriggerNodeLinks, + TriggerNodeCoreSchema, + TriggerNodeCoreSchemaData +) + +# Экспорты для моделей узла run +from .node_run_models import ( + RunNodeData, + RunNodeLinks, + RunNodeCoreSchema, + RunNodeCoreSchemaData +) + +# Экспорты для моделей узла callback +from .node_callback_models import ( + CallbackNodeData, + CallbackNodeLinks, + CallbackNodeCoreSchema, + CallbackNodeCoreSchemaData +) + +# Экспорты для моделей узла if +from .node_if_models import ( + IfNodeData, + IfNodeLinks, + IfNodeCoreSchema, + IfNodeCoreSchemaData +) + +# Экспорты для моделей узла test (ранее start) +from .node_test_models import ( + TestNodeData, + TestNodeLinks, + TestNodeCoreSchema, + TestNodeCoreSchemaData +) + +# Экспорты для моделей узла switch +from .node_switch_models import ( + SwitchNodeData, + SwitchNodeLinks, + SwitchNodeCoreSchema, + SwitchNodeCoreSchemaData +) + +# Экспорты для моделей узла set +from .node_set_models import ( + SetNodeData, + SetNodeLinks, + SetNodeCoreSchema, + SetNodeCoreSchemaData +) + +# Экспорты для моделей узла wait +from .node_wait_models import ( + WaitNodeData, + WaitNodeLinks, + WaitNodeCoreSchema, + WaitNodeCoreSchemaData +) + +# Экспорты для моделей узла while +from .node_while_models import ( + WhileNodeData, + WhileNodeLinks, + WhileNodeCoreSchema, + WhileNodeCoreSchemaData +) + +# Экспорты для моделей узла each +from .node_each_models import ( + EachNodeData, + EachNodeLinks, + EachNodeCoreSchema, + EachNodeCoreSchemaData +) + +# Экспорты для моделей связей между узлами +from .node_link_models import ( + VorkNodeLinkData, + VorkNodeLinkSchema +) + +__all__ = [ + # Listen node models + "ListenNodeData", + "ListenNodeLinks", + "ListenNodeCoreSchema", + "ListenNodeCoreSchemaData", + + # Trigger node models + "TriggerNodeData", + "TriggerNodeLinks", + "TriggerNodeCoreSchema", + "TriggerNodeCoreSchemaData", + + # Run node models + "RunNodeData", + "RunNodeLinks", + "RunNodeCoreSchema", + "RunNodeCoreSchemaData", + + # Callback node models + "CallbackNodeData", + "CallbackNodeLinks", + "CallbackNodeCoreSchema", + "CallbackNodeCoreSchemaData", + + # If node models + "IfNodeData", + "IfNodeLinks", + "IfNodeCoreSchema", + "IfNodeCoreSchemaData", + + # Test node models + "TestNodeData", + "TestNodeLinks", + "TestNodeCoreSchema", + "TestNodeCoreSchemaData", + + # Switch node models + "SwitchNodeData", + "SwitchNodeLinks", + "SwitchNodeCoreSchema", + "SwitchNodeCoreSchemaData", + + # Set node models + "SetNodeData", + "SetNodeLinks", + "SetNodeCoreSchema", + "SetNodeCoreSchemaData", + + # Wait node models + "WaitNodeData", + "WaitNodeLinks", + "WaitNodeCoreSchema", + "WaitNodeCoreSchemaData", + + # While node models + "WhileNodeData", + "WhileNodeLinks", + "WhileNodeCoreSchema", + "WhileNodeCoreSchemaData", + + # Each node models + "EachNodeData", + "EachNodeLinks", + "EachNodeCoreSchema", + "EachNodeCoreSchemaData", + + # Node link models + "VorkNodeLinkData", + "VorkNodeLinkSchema" +] diff --git a/model_nodes/form_base_descriptor_models.py b/model_nodes/form_base_descriptor_models.py new file mode 100644 index 0000000..70277df --- /dev/null +++ b/model_nodes/form_base_descriptor_models.py @@ -0,0 +1,75 @@ +from __future__ import annotations +from typing import Optional, Annotated, Literal, List +from pydantic import BaseModel, Field + + +class LinkPort(BaseModel): + id: str + label: str + is_addable: Optional[bool] = None + + +class LineElement(BaseModel): + type: Literal['line'] + name: str + label: str + placeholder: Optional[str] = None + + +class AreaElement(BaseModel): + type: Literal['area'] + name: str + label: str + placeholder: Optional[str] = None + + +class SelectElement(BaseModel): + type: Literal['select'] + name: str + label: str + data: List[str] + default: Optional[str] = None + placeholder: Optional[str] = None + + +class NumberElement(BaseModel): + type: Literal['number'] + name: str + label: str + placeholder: Optional[str] = None + + +class DateElement(BaseModel): + type: Literal['date'] + name: str + label: str + placeholder: Optional[str] = None + + +FieldElement = Annotated[ + LineElement | AreaElement | SelectElement | NumberElement | DateElement, + Field(discriminator='type'), +] + + +class RowElement(BaseModel): + type: Literal['row'] + name: str + label: str + link_port: Optional[LinkPort] = None + elements: Optional[List[FieldElement]] = None + + +class FormDescriptor(BaseModel): + elements: List[RowElement] + + +# Descriptor-suffixed aliases for clarity (backward compatible) +LinkPortDescriptor = LinkPort +LineElementDescriptor = LineElement +AreaElementDescriptor = AreaElement +SelectElementDescriptor = SelectElement +NumberElementDescriptor = NumberElement +DateElementDescriptor = DateElement +RowDescriptor = RowElement +FormDescriptorModel = FormDescriptor diff --git a/model_nodes/node_callback_models.py b/model_nodes/node_callback_models.py new file mode 100644 index 0000000..a0f17c6 --- /dev/null +++ b/model_nodes/node_callback_models.py @@ -0,0 +1,117 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, LineElement, AreaElement, SelectElement, LinkPort + + +class CallbackNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла callback + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class CallbackNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла callback + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class CallbackNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла callback + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + + +class CallbackNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла callback + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[CallbackNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла CALLBACK +CALLBACK_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="uri_row", + type="row", + label="URI", + elements=[ + LineElement( + name="uri", + type="line", + label="URI", + placeholder="Webhook URL", + ) + ], + ), + RowElement( + name="method_row", + type="row", + label="Method", + elements=[ + SelectElement( + name="method", + type="select", + label="Method", + data=["POST", "GET", "PUT", "PATCH", "DELETE"], + default="POST", + ) + ], + ), + RowElement( + name="headers_row", + type="row", + label="Headers", + elements=[ + AreaElement( + name="headers", + type="area", + label="Headers", + placeholder="Normalize and validate headers", + ) + ], + ), + RowElement( + name="body_row", + type="row", + label="Body", + elements=[ + AreaElement( + name="body", + type="area", + label="Data", + placeholder="Normalize values and validate JSON", + ) + ], + ), + RowElement( + name="sync_row", + type="row", + label="Wait for request completion", + elements=[ + SelectElement( + name="sync", + type="select", + label="Wait for request completion", + data=["Yes", "No"], + default="Yes", + ) + ], + ), + RowElement( + name="then_row", + type="row", + label="Then", + link_port=LinkPort(id="then_output", label="Then"), + ), + ] +) diff --git a/model_nodes/node_each_models.py b/model_nodes/node_each_models.py new file mode 100644 index 0000000..76cf954 --- /dev/null +++ b/model_nodes/node_each_models.py @@ -0,0 +1,65 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, LineElement, LinkPort + + +class EachNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла each + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class EachNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла each + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class EachNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла each + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + else_port_number: Optional[int] = Field(default=1, description="Номер порта для перехода по Связи Else (LINK)") + + +class EachNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла each + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[EachNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла EACH +EACH_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="list_row", + type="row", + label="List", + link_port=LinkPort(id="then_output", label="Then"), + elements=[ + LineElement( + name="list", + type="line", + label="List", + placeholder="Validate list and extract next value from list", + ) + ], + ), + RowElement( + name="else_row", + type="row", + label="Alternative path", + link_port=LinkPort(id="else_output", label="Else"), + ), + ] +) diff --git a/model_nodes/node_if_models.py b/model_nodes/node_if_models.py new file mode 100644 index 0000000..c8bd360 --- /dev/null +++ b/model_nodes/node_if_models.py @@ -0,0 +1,65 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, AreaElement, LinkPort + + +class IfNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла if + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class IfNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла if + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class IfNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла if + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + else_port_number: Optional[int] = Field(default=1, description="Номер порта для перехода по Связи Else (LINK)") + + +class IfNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла if + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[IfNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла IF +IF_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="condition_row", + type="row", + label="Condition", + link_port=LinkPort(id="then_output", label="Then"), + elements=[ + AreaElement( + name="condition", + type="area", + label="Condition", + placeholder="Enter condition", + ) + ], + ), + RowElement( + name="else_row", + type="row", + label="Alternative path", + link_port=LinkPort(id="else_output", label="Else"), + ), + ] +) diff --git a/model_nodes/node_link_models.py b/model_nodes/node_link_models.py new file mode 100644 index 0000000..8e498e6 --- /dev/null +++ b/model_nodes/node_link_models.py @@ -0,0 +1,22 @@ +from typing import Optional, Dict, Any +from pydantic import BaseModel, Field + + +class VorkNodeLinkData(BaseModel): + """ + Pydantic модель для валидации данных VorkNodeLink + """ + parent_port_number: Optional[int] = Field(default=None, description="Номер выхода родительского узла") + to_id: Optional[int] = Field(default=None, description="ID целевого узла") + from_id: Optional[int] = Field(default=None, description="ID исходного узла") + last_link_name: Optional[str] = Field(default=None, description="Название последней связи") + + +class VorkNodeLinkSchema(BaseModel): + """ + Pydantic модель для схемы VorkNodeLink + """ + link_name: Optional[str] = Field(default=None, description="Название связи") + parent_port_number: Optional[int] = Field(default=None, description="Номер выхода родительского узла") + to_id: Optional[int] = Field(default=None, description="ID целевого узла") + from_id: Optional[int] = Field(default=None, description="ID исходного узла") diff --git a/model_nodes/node_listen_models.py b/model_nodes/node_listen_models.py new file mode 100644 index 0000000..8eb3ae6 --- /dev/null +++ b/model_nodes/node_listen_models.py @@ -0,0 +1,78 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, LineElement, AreaElement, LinkPort + + +class ListenNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла listen + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + is_start: bool = Field(default=False, description="Является ли узел стартовым") + + +class ListenNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла listen + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class ListenNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла listen + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + is_start: bool = Field(default=False, description="Является ли узел стартовым") + + +class ListenNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла listen + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[ListenNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла LISTEN +LISTEN_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="event_row", + type="row", + label="Event", + elements=[ + LineElement( + name="event_name", + type="line", + label="Event", + placeholder="Event identifier", + ) + ], + ), + RowElement( + name="condition_row", + type="row", + label="Condition", + elements=[ + AreaElement( + name="condition", + type="area", + label="Condition", + placeholder="If P([condition(i), [AND, OR]]) == true", + ) + ], + ), + RowElement( + name="then_row", + type="row", + label="Then", + link_port=LinkPort(id="then_output", label="Then"), + ), + ] +) diff --git a/model_nodes/node_run_models.py b/model_nodes/node_run_models.py new file mode 100644 index 0000000..0738fe7 --- /dev/null +++ b/model_nodes/node_run_models.py @@ -0,0 +1,77 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, AreaElement, SelectElement, LinkPort + + +class RunNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла run + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class RunNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла run + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class RunNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла run + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + + +class RunNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла run + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[RunNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы для узла Run +RUN_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="task_row", + type="row", + label="Task", + elements=[ + SelectElement( + name="task", + type="select", + label="Task", + data=["send_email", "process_data", "generate_report", "validate_input", "transform_data"], + default="send_email", + ) + ], + ), + RowElement( + name="context_row", + type="row", + label="Arguments", + elements=[ + AreaElement( + name="context", + type="area", + label="Arguments", + placeholder="Build request JSON from provided environment variables", + ) + ], + ), + RowElement( + name="then_row", + type="row", + label="Then", + link_port=LinkPort(id="then_output", label="Then"), + ), + ] +) diff --git a/model_nodes/node_set_models.py b/model_nodes/node_set_models.py new file mode 100644 index 0000000..7bd1473 --- /dev/null +++ b/model_nodes/node_set_models.py @@ -0,0 +1,77 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, LineElement, AreaElement, LinkPort + + +class SetNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла set + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class SetNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла set + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class SetNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла set + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи then (LINK)") + + +class SetNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла set + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[SetNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла SET +SET_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="variable_row", + type="row", + label="Parameter name", + elements=[ + LineElement( + name="variable", + type="line", + label="Parameter name", + placeholder="Enter parameter name", + ) + ], + ), + RowElement( + name="value_row", + type="row", + label="Value", + elements=[ + AreaElement( + name="value", + type="area", + label="Value", + placeholder="Enter value", + ) + ], + ), + RowElement( + name="link_row", + type="row", + label="Link", + link_port=LinkPort(id="then_output", label="then"), + elements=[], + ), + ] +) diff --git a/model_nodes/node_switch_models.py b/model_nodes/node_switch_models.py new file mode 100644 index 0000000..7d4e8c2 --- /dev/null +++ b/model_nodes/node_switch_models.py @@ -0,0 +1,65 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, AreaElement, LinkPort + + +class SwitchNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла switch + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class SwitchNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла switch + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class SwitchNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла switch + """ + default_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи default (LINK)") + case_1_port_number: Optional[int] = Field(default=1, description="Номер порта для перехода по Связи case_1 (LINK)") + + +class SwitchNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла switch + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[SwitchNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла SWITCH +SWITCH_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="switch_row", + type="row", + label="Switch condition", + link_port=LinkPort(id="case_1_output", label="case_1", is_addable=True), + elements=[ + AreaElement( + name="switch_value", + type="area", + label="Switch condition", + placeholder="Enter condition", + ) + ], + ), + RowElement( + name="default_row", + type="row", + label="Default", + link_port=LinkPort(id="default_output", label="default"), + ), + ] +) diff --git a/model_nodes/node_test_models.py b/model_nodes/node_test_models.py new file mode 100644 index 0000000..f50b87e --- /dev/null +++ b/model_nodes/node_test_models.py @@ -0,0 +1,33 @@ +from typing import Optional +from pydantic import BaseModel, Field + + +class TestNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла test + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class TestNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла test + """ + # Test узел не имеет родительских связей, только исходящие + + +class TestNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла test + """ + node_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + + +class TestNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла test + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + data: Optional[TestNodeCoreSchemaData] = Field(default=None, description="Данные узла") diff --git a/model_nodes/node_trigger_models.py b/model_nodes/node_trigger_models.py new file mode 100644 index 0000000..7814e1b --- /dev/null +++ b/model_nodes/node_trigger_models.py @@ -0,0 +1,76 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, LineElement, AreaElement, LinkPort + + +class TriggerNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла trigger + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class TriggerNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла trigger + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class TriggerNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла trigger + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + + +class TriggerNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла trigger + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[TriggerNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла TRIGGER +TRIGGER_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="event_row", + type="row", + label="Event", + elements=[ + LineElement( + name="event_name", + type="line", + label="Event", + placeholder="Event identifier", + ) + ], + ), + RowElement( + name="context_row", + type="row", + label="Context", + elements=[ + AreaElement( + name="context", + type="area", + label="Payload", + placeholder="Build request JSON from provided environment variables", + ) + ], + ), + RowElement( + name="then_row", + type="row", + label="Then", + link_port=LinkPort(id="then_output", label="Then"), + ), + ] +) diff --git a/model_nodes/node_wait_models.py b/model_nodes/node_wait_models.py new file mode 100644 index 0000000..352f5c7 --- /dev/null +++ b/model_nodes/node_wait_models.py @@ -0,0 +1,90 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, SelectElement, NumberElement, DateElement, LinkPort + + +class WaitNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла wait + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class WaitNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла wait + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class WaitNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла wait + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи then (LINK)") + + +class WaitNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла wait + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[WaitNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла WAIT +WAIT_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="type_row", + type="row", + label="Parameter", + elements=[ + SelectElement( + name="type", + type="select", + label="Parameter", + data=["seconds", "datetime"], + placeholder="Selected option", + ) + ], + ), + RowElement( + name="wait_for_row", + type="row", + label="Time", + elements=[ + NumberElement( + name="wait_for", + type="number", + label="Time", + placeholder="Compute wait time in seconds", + ) + ], + ), + RowElement( + name="wait_datetime_row", + type="row", + label="Wait until", + elements=[ + DateElement( + name="wait_datetime", + type="date", + label="Wait until", + placeholder="Compute value until specific datetime", + ) + ], + ), + RowElement( + name="then_row", + type="row", + label="Transition", + link_port=LinkPort(id="then_output", label="then"), + ), + ] +) diff --git a/model_nodes/node_while_models.py b/model_nodes/node_while_models.py new file mode 100644 index 0000000..b4bcd6c --- /dev/null +++ b/model_nodes/node_while_models.py @@ -0,0 +1,65 @@ +from typing import Optional +from pydantic import BaseModel, Field +from .form_base_descriptor_models import FormDescriptor, RowElement, AreaElement, LinkPort + + +class WhileNodeData(BaseModel): + """ + Pydantic модель для валидации данных узла while + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + + +class WhileNodeLinks(BaseModel): + """ + Pydantic модель для валидации связей узла while + """ + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + + +class WhileNodeCoreSchemaData(BaseModel): + """ + Pydantic модель для данных портов узла while + """ + then_port_number: Optional[int] = Field(default=0, description="Номер порта для перехода по Связи Then (LINK)") + else_port_number: Optional[int] = Field(default=1, description="Номер порта для перехода по Связи Else (LINK)") + + +class WhileNodeCoreSchema(BaseModel): + """ + Pydantic модель для схемы узла while + """ + ps_id: Optional[int] = Field(default=None, description="ID процесса") + node_type: Optional[str] = Field(default=None, description="Тип узла") + parent_id: Optional[int] = Field(default=None, description="ID родительского узла") + parent_port_number: Optional[int] = Field(default=None, description="Номер порта родительского узла") + data: Optional[WhileNodeCoreSchemaData] = Field(default=None, description="Данные узла") + + +# Дескриптор формы узла WHILE +WHILE_FORM_DESCRIPTOR = FormDescriptor( + elements=[ + RowElement( + name="condition_row", + type="row", + label="Parameter", + link_port=LinkPort(id="then_output", label="Then"), + elements=[ + AreaElement( + name="condition", + type="area", + label="Parameter", + placeholder="P(condition) == true", + ) + ], + ), + RowElement( + name="else_row", + type="row", + label="Alternative path", + link_port=LinkPort(id="else_output", label="Else"), + ), + ] +) diff --git a/nodes/vork_node_callback.py b/nodes/vork_node_callback.py index ab10d33..a1f12bd 100644 --- a/nodes/vork_node_callback.py +++ b/nodes/vork_node_callback.py @@ -1,18 +1,71 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_callback_models import ( + CallbackNodeData, + CallbackNodeLinks, + CallbackNodeCoreSchema, + CallbackNodeCoreSchemaData, + CALLBACK_FORM_DESCRIPTOR, +) class VorkNodeCallback(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла callback + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_callback" + return "CALLBACK" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Callback + """ + return CALLBACK_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> CallbackNodeCoreSchema: + """ + Валидирует данные узла callback и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + node_data = CallbackNodeCoreSchemaData( + then_port_number=0 + ) + + # Создаем схему с валидированными данными + return CallbackNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Callback node validation error: {e}") + raise + + def validate_data(self) -> CallbackNodeData: + """ + Валидирует данные узла callback + """ + return CallbackNodeData(**self.data) + + def validate_links(self) -> CallbackNodeLinks: + """ + Валидирует связи узла callback + """ + return CallbackNodeLinks(**self.links) def process(self, context): pass diff --git a/nodes/vork_node_each.py b/nodes/vork_node_each.py index 388be09..283dd30 100644 --- a/nodes/vork_node_each.py +++ b/nodes/vork_node_each.py @@ -1,18 +1,73 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_each_models import ( + EachNodeData, + EachNodeLinks, + EachNodeCoreSchema, + EachNodeCoreSchemaData, + EACH_FORM_DESCRIPTOR, +) class VorkNodeEach(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла each + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_each" + return "EACH" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Each + """ + return EACH_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> EachNodeCoreSchema: + """ + Валидирует данные узла each и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + # Создаем данные портов (аналогично if) + node_data = EachNodeCoreSchemaData( + then_port_number=0, + else_port_number=1, + ) + + # Создаем схему с валидированными данными + return EachNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Each node validation error: {e}") + raise + + def validate_data(self) -> EachNodeData: + """ + Валидирует данные узла each + """ + return EachNodeData(**self.data) + + def validate_links(self) -> EachNodeLinks: + """ + Валидирует связи узла each + """ + return EachNodeLinks(**self.links) def process(self, context): pass diff --git a/nodes/vork_node_if.py b/nodes/vork_node_if.py index 8605be9..a0fef48 100644 --- a/nodes/vork_node_if.py +++ b/nodes/vork_node_if.py @@ -1,21 +1,65 @@ -from typing import Dict, Any +from typing import Any, Dict from core import VorkNode +from model_nodes.node_if_models import ( + IfNodeData, + IfNodeLinks, + IfNodeCoreSchema, + IfNodeCoreSchemaData, + IF_FORM_DESCRIPTOR, +) class VorkNodeIf(VorkNode): @property def id(self) -> str: - return "vork_node_if" + return "IF" @classmethod def form(cls) -> Dict[str, Any]: - return { + """ + Возвращает статический дескриптор формы для узла IF + """ + return IF_FORM_DESCRIPTOR - } + def validate(self) -> IfNodeCoreSchema: + """ + Валидирует данные и связи узла с помощью Pydantic моделей + и возвращает схему с валидированными данными. + """ + try: + # Валидируем данные + validated_data = self.validate_data() - def validate(self) -> bool: - return True + # Валидируем связи + validated_links = self.validate_links() - def process(self, context: Any) -> bool: - return True + # Создаем вложенную схему с данными портов + node_data = IfNodeCoreSchemaData( + then_port_number=0, + else_port_number=1, + ) + + # Создаем схему с валидированными данными из экземпляра + return IfNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data, + ) + + except Exception as e: + print(f"Node validation error if: {e}") + raise + + def validate_data(self) -> IfNodeData: + + return IfNodeData(**self.data) + + def validate_links(self) -> IfNodeLinks: + + return IfNodeLinks(**self.links) + + def process(self, context): + pass diff --git a/nodes/vork_node_listen.py b/nodes/vork_node_listen.py index c56f29b..9dad076 100644 --- a/nodes/vork_node_listen.py +++ b/nodes/vork_node_listen.py @@ -1,21 +1,72 @@ from typing import Dict, Any from core import VorkNode +from model_nodes.node_listen_models import ( + ListenNodeData, + ListenNodeLinks, + ListenNodeCoreSchema, + ListenNodeCoreSchemaData, + LISTEN_FORM_DESCRIPTOR, +) class VorkNodeListen(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла listen + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_listen" + return "LISTEN" @classmethod def form(cls) -> Dict[str, Any]: - return { + """ + Возвращает статический дескриптор формы для узла Listen + """ + return LISTEN_FORM_DESCRIPTOR - } + def validate(self) -> ListenNodeCoreSchema: + """ + Валидирует данные узла listen и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() - def validate(self) -> bool: - return True + # Валидируем связи узла + validated_links = self.validate_links() - def process(self, context: Any) -> Any: - return context + node_data = ListenNodeCoreSchemaData( + then_port_number=0, + is_start=validated_data.is_start + ) + + # Создаем схему с валидированными данными + return ListenNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Listen node validation error: {e}") + raise + + def validate_data(self) -> ListenNodeData: + """ + Валидирует данные узла listen + """ + return ListenNodeData(**self.data) + + def validate_links(self) -> ListenNodeLinks: + """ + Валидирует связи узла listen + """ + return ListenNodeLinks(**self.links) + + def process(self, context): + pass diff --git a/nodes/vork_node_run.py b/nodes/vork_node_run.py index 79ff542..ba5b056 100644 --- a/nodes/vork_node_run.py +++ b/nodes/vork_node_run.py @@ -1,18 +1,74 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_run_models import ( + RunNodeData, + RunNodeLinks, + RunNodeCoreSchema, + RunNodeCoreSchemaData, + RUN_FORM_DESCRIPTOR, +) class VorkNodeRun(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла run + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_run" + return "RUN" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Run + """ + return RUN_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> RunNodeCoreSchema: + """ + Валидирует данные узла run и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + node_data = RunNodeCoreSchemaData( + then_port_number=0 + ) + + # Создаем схему с валидированными данными + return RunNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Run node validation error: {e}") + raise + + def validate_data(self) -> RunNodeData: + """ + Валидирует данные узла run + """ + return RunNodeData(**self.data) + + def validate_links(self) -> RunNodeLinks: + """ + Валидирует связи узла run + """ + return RunNodeLinks(**self.links) def process(self, context): + """ + Обрабатывает логику узла run - выполнение встроенной задачи + """ pass diff --git a/nodes/vork_node_set.py b/nodes/vork_node_set.py index 93b9635..2ab7530 100644 --- a/nodes/vork_node_set.py +++ b/nodes/vork_node_set.py @@ -1,18 +1,72 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_set_models import ( + SetNodeData, + SetNodeLinks, + SetNodeCoreSchema, + SetNodeCoreSchemaData, + SET_FORM_DESCRIPTOR, +) class VorkNodeSet(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла set + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_set" + return "SET" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Set + """ + return SET_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> SetNodeCoreSchema: + """ + Валидирует данные узла set и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + # Создаем данные портов + node_data = SetNodeCoreSchemaData( + then_port_number=0, + ) + + # Создаем схему с валидированными данными + return SetNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Set node validation error: {e}") + raise + + def validate_data(self) -> SetNodeData: + """ + Валидирует данные узла set + """ + return SetNodeData(**self.data) + + def validate_links(self) -> SetNodeLinks: + """ + Валидирует связи узла set + """ + return SetNodeLinks(**self.links) def process(self, context): pass diff --git a/nodes/vork_node_switch.py b/nodes/vork_node_switch.py index e9e1b4f..0aa8e66 100644 --- a/nodes/vork_node_switch.py +++ b/nodes/vork_node_switch.py @@ -1,18 +1,73 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_switch_models import ( + SwitchNodeData, + SwitchNodeLinks, + SwitchNodeCoreSchema, + SwitchNodeCoreSchemaData, + SWITCH_FORM_DESCRIPTOR, +) class VorkNodeSwitch(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла switch + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_switch" + return "SWITCH" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Switch + """ + return SWITCH_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> SwitchNodeCoreSchema: + """ + Валидирует данные узла switch и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + # Создаем данные портов (default=0, case_1=1) + node_data = SwitchNodeCoreSchemaData( + default_port_number=0, + case_1_port_number=1, + ) + + # Создаем схему с валидированными данными + return SwitchNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Switch node validation error: {e}") + raise + + def validate_data(self) -> SwitchNodeData: + """ + Валидирует данные узла switch + """ + return SwitchNodeData(**self.data) + + def validate_links(self) -> SwitchNodeLinks: + """ + Валидирует связи узла switch + """ + return SwitchNodeLinks(**self.links) def process(self, context): pass diff --git a/nodes/vork_node_trigger.py b/nodes/vork_node_trigger.py index 53417c1..2f8504d 100644 --- a/nodes/vork_node_trigger.py +++ b/nodes/vork_node_trigger.py @@ -1,18 +1,71 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_trigger_models import ( + TriggerNodeData, + TriggerNodeLinks, + TriggerNodeCoreSchema, + TriggerNodeCoreSchemaData, + TRIGGER_FORM_DESCRIPTOR, +) class VorkNodeTrigger(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла trigger + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_trigger" + return "TRIGGER" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Trigger + """ + return TRIGGER_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> TriggerNodeCoreSchema: + """ + Валидирует данные узла trigger и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + node_data = TriggerNodeCoreSchemaData( + then_port_number=0 + ) + + # Создаем схему с валидированными данными + return TriggerNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Trigger node validation error: {e}") + raise + + def validate_data(self) -> TriggerNodeData: + """ + Валидирует данные узла trigger + """ + return TriggerNodeData(**self.data) + + def validate_links(self) -> TriggerNodeLinks: + """ + Валидирует связи узла trigger + """ + return TriggerNodeLinks(**self.links) def process(self, context): pass diff --git a/nodes/vork_node_wait.py b/nodes/vork_node_wait.py index e448aa4..20fab2c 100644 --- a/nodes/vork_node_wait.py +++ b/nodes/vork_node_wait.py @@ -1,18 +1,72 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_wait_models import ( + WaitNodeData, + WaitNodeLinks, + WaitNodeCoreSchema, + WaitNodeCoreSchemaData, + WAIT_FORM_DESCRIPTOR, +) class VorkNodeWait(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла wait + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_wait" + return "WAIT" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла Wait + """ + return WAIT_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> WaitNodeCoreSchema: + """ + Валидирует данные узла wait и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + # Создаем данные портов + node_data = WaitNodeCoreSchemaData( + then_port_number=0, + ) + + # Создаем схему с валидированными данными + return WaitNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"Wait node validation error: {e}") + raise + + def validate_data(self) -> WaitNodeData: + """ + Валидирует данные узла wait + """ + return WaitNodeData(**self.data) + + def validate_links(self) -> WaitNodeLinks: + """ + Валидирует связи узла wait + """ + return WaitNodeLinks(**self.links) def process(self, context): pass diff --git a/nodes/vork_node_while.py b/nodes/vork_node_while.py index e230056..a327d97 100644 --- a/nodes/vork_node_while.py +++ b/nodes/vork_node_while.py @@ -1,18 +1,73 @@ +from typing import Dict, Any from core import VorkNode +from model_nodes.node_while_models import ( + WhileNodeData, + WhileNodeLinks, + WhileNodeCoreSchema, + WhileNodeCoreSchemaData, + WHILE_FORM_DESCRIPTOR, +) class VorkNodeWhile(VorkNode): + def __init__(self, data: Dict[str, Any], links: Dict[str, Any] = None): + """ + Инициализация узла while + """ + super().__init__(data, links or {}) + @property def id(self) -> str: - return "vork_node_while" + return "WHILE" @classmethod - def form(cls): - pass + def form(cls) -> Dict[str, Any]: + """ + Возвращает статический дескриптор формы для узла While + """ + return WHILE_FORM_DESCRIPTOR - def validate(self) -> bool: - return True + def validate(self) -> WhileNodeCoreSchema: + """ + Валидирует данные узла while и возвращает схему + """ + try: + # Валидируем данные узла + validated_data = self.validate_data() + + # Валидируем связи узла + validated_links = self.validate_links() + + # Создаем данные портов (аналогично if) + node_data = WhileNodeCoreSchemaData( + then_port_number=0, + else_port_number=1, + ) + + # Создаем схему с валидированными данными + return WhileNodeCoreSchema( + ps_id=validated_data.ps_id, + node_type=validated_data.node_type, + parent_id=validated_links.parent_id, + parent_port_number=validated_links.parent_port_number, + data=node_data + ) + except Exception as e: + print(f"While node validation error: {e}") + raise + + def validate_data(self) -> WhileNodeData: + """ + Валидирует данные узла while + """ + return WhileNodeData(**self.data) + + def validate_links(self) -> WhileNodeLinks: + """ + Валидирует связи узла while + """ + return WhileNodeLinks(**self.links) def process(self, context): pass diff --git a/orm/schemas/__init__.py b/orm/schemas/__init__.py new file mode 100644 index 0000000..b3ce98e --- /dev/null +++ b/orm/schemas/__init__.py @@ -0,0 +1,6 @@ +# Экспорты для базовых схем +from .base import Base + +__all__ = [ + "Base", +] diff --git a/orm/schemas/base.py b/orm/schemas/base.py new file mode 100644 index 0000000..3e8c5e8 --- /dev/null +++ b/orm/schemas/base.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel, ConfigDict +from pydantic.alias_generators import to_camel + + + +class Base(BaseModel): + model_config = ConfigDict( + from_attributes=True, + alias_generator=to_camel, + populate_by_name=True, + ) diff --git a/__init__.py b/orm/schemas/process/__init__.py similarity index 100% rename from __init__.py rename to orm/schemas/process/__init__.py diff --git a/orm/schemas/process/node_link.py b/orm/schemas/process/node_link.py new file mode 100644 index 0000000..75c01dd --- /dev/null +++ b/orm/schemas/process/node_link.py @@ -0,0 +1,18 @@ +from pydantic import Field +from typing import Dict, Any +from datetime import datetime +from enum import Enum + +from orm.schemas.base import Base +from orm.tables.process import NodeLinkStatus + + +class NodeLink(Base): + id: int + link_name: str = Field(..., max_length=20) + node_id: int + next_node_id: int + settings: Dict[str, Any] + creator_id: int + created_at: datetime + status: NodeLinkStatus diff --git a/orm/schemas/process/process_schema.py b/orm/schemas/process/process_schema.py new file mode 100644 index 0000000..2b4ceb4 --- /dev/null +++ b/orm/schemas/process/process_schema.py @@ -0,0 +1,19 @@ +from pydantic import Field +from typing import Dict, Any +from datetime import datetime +from enum import Enum + +from orm.schemas.base import Base +from orm.tables.process import ProcessStatus + + + +class ProcessSchema(Base): + id: int + title: str = Field(..., max_length=100) + description: str + owner_id: int + creator_id: int + created_at: datetime + settings: Dict[str, Any] + status: ProcessStatus diff --git a/orm/schemas/process/process_version_archive.py b/orm/schemas/process/process_version_archive.py new file mode 100644 index 0000000..2c4c158 --- /dev/null +++ b/orm/schemas/process/process_version_archive.py @@ -0,0 +1,13 @@ +from typing import Dict, Any +from datetime import datetime + +from orm.schemas.base import Base + + +class ProcessStatusSchema(Base): + id: int + version: int + snapshot: Dict[str, Any] + owner_id: int + created_at: datetime + is_last: int diff --git a/orm/schemas/process/ps_node.py b/orm/schemas/process/ps_node.py new file mode 100644 index 0000000..e38577a --- /dev/null +++ b/orm/schemas/process/ps_node.py @@ -0,0 +1,16 @@ +from datetime import datetime +from typing import Dict, Any +from enum import Enum + +from orm.schemas.base import Base +from orm.tables.process import NodeStatus,NodeType + + +class Ps_Node(Base): + id: int + ps_id: int + node_type: NodeType + settings: dict + creator_id: Dict[str, Any] + created_at: datetime + status: NodeStatus diff --git a/orm/tables/process.py b/orm/tables/process.py index f6ab15b..8b67e32 100644 --- a/orm/tables/process.py +++ b/orm/tables/process.py @@ -33,7 +33,8 @@ process_schema_table = Table( Column("title", String(100), nullable=False), Column("description", Text, nullable=False), Column("owner_id", UnsignedInt, ForeignKey("account.id"), nullable=False), - Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("creator_id", UnsignedInt, ForeignKey( + "account.id"), nullable=False), Column("created_at", DateTime(timezone=True), server_default=func.now()), Column("settings", JSON, default={}), Column("status", SQLAEnum(ProcessStatus), nullable=False), @@ -47,7 +48,8 @@ process_version_archive_table = Table( "process_version_archive", metadata, Column("id", UnsignedInt, autoincrement=True, nullable=False), - Column("ps_id", UnsignedInt, ForeignKey("process_schema.id"), nullable=False), + Column("ps_id", UnsignedInt, ForeignKey( + "process_schema.id"), nullable=False), Column("version", UnsignedInt, default=1, nullable=False), Column("snapshot", JSON, default={}), Column("owner_id", UnsignedInt, ForeignKey("account.id"), nullable=False), @@ -64,19 +66,30 @@ class NodeStatus(enum.StrEnum): class NodeType(Enum): - TYPE1 = "Type1" - TYPE2 = "Type2" - TYPE3 = "Type3" + LISTEN = "LISTEN" + IF = "IF" + START = "START" + CALLBACK = "CALLBACK" + EACH = "EACH" + RUN = "RUN" + SET = "SET" + SWITCH = "SWITCH" + TRIGGER = "TRIGGER" + WAIT = "WAIT" + WHILE = "WHILE" ps_node_table = Table( "ps_node", metadata, - Column("id", UnsignedInt, autoincrement=True, primary_key=True, nullable=False), - Column("ps_id", UnsignedInt, ForeignKey("process_schema.id"), nullable=False), + Column("id", UnsignedInt, autoincrement=True, + primary_key=True, nullable=False), + Column("ps_id", UnsignedInt, ForeignKey( + "process_schema.id"), nullable=False), Column("node_type", SQLAEnum(NodeType), nullable=False), Column("settings", JSON, default={}), - Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("creator_id", UnsignedInt, ForeignKey( + "account.id"), nullable=False), Column("created_at", DateTime(timezone=True), server_default=func.now()), Column("status", SQLAEnum(NodeStatus), nullable=False), Index("idx_ps_id", "ps_id"), @@ -93,12 +106,16 @@ class NodeLinkStatus(enum.StrEnum): node_link_table = Table( "node_link", metadata, - Column("id", UnsignedInt, autoincrement=True, primary_key=True, nullable=False), + Column("id", UnsignedInt, autoincrement=True, + primary_key=True, nullable=False), Column("link_name", String(20), nullable=False), Column("node_id", UnsignedInt, ForeignKey("ps_node.id"), nullable=False), - Column("next_node_id", UnsignedInt, ForeignKey("ps_node.id"), nullable=False), + Column("link_point_id", UnsignedInt, nullable=False), + Column("next_node_id", UnsignedInt, ForeignKey( + "ps_node.id"), nullable=False), Column("settings", JSON, default={}), - Column("creator_id", UnsignedInt, ForeignKey("account.id"), nullable=False), + Column("creator_id", UnsignedInt, ForeignKey( + "account.id"), nullable=False), Column("created_at", DateTime(timezone=True), server_default=func.now()), Column("status", SQLAEnum(NodeLinkStatus), nullable=False), Index("idx_node_id", "node_id"), diff --git a/poetry.lock b/poetry.lock index 6eb260d..9a29d49 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,16 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] [[package]] name = "greenlet" @@ -69,6 +81,140 @@ files = [ docs = ["Sphinx", "furo"] test = ["objgraph", "psutil", "setuptools"] +[[package]] +name = "pydantic" +version = "2.11.7" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, + {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.33.2" +typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + [[package]] name = "sqlalchemy" version = "2.0.43" @@ -177,7 +323,22 @@ files = [ {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, ] +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + [metadata] lock-version = "2.1" -python-versions = ">=3.9" -content-hash = "49c96ef184d07ac132dbeb6206c1231ea15e51fbd69da541f4e62d9099ddd903" +python-versions = "^3.9" +content-hash = "01d51b88c538d68359b01cf3a28e98633fafdf244e53550b790cb4ddd44eecac" diff --git a/pyproject.toml b/pyproject.toml index 95a6865..a093d66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,27 +1,23 @@ -[project] -name = "core-library" -version = "0.1.0" -description = "Abstract classes library for the Vorkout project" -authors = [ - {name = "Ivan Rastorguev", email = "ivan.dev@heado.ru"} -] -maintainers = [ - { name = "Ivan Rastorguev", email = "ivan.dev@heado.ru" }, - { name = "Vladislav Syrochkin", email = "vlad.dev@heado.ru" }, -] -repository = "https://gitea.heado.ru/Vorkout/core" -readme = "README.md" -requires-python = ">=3.9" -dependencies = [ - "sqlalchemy (>=2.0.43,<3.0.0)" -] +# Poetry configuration for vork-core library [tool.poetry] +name = "vork-core" +version = "0.1.0" +description = "Core library for Vork workflow engine - nodes, links, and process management" +authors = ["Ivan Rastorguev "] +readme = "README.md" packages = [ { include = "core" }, + { include = "nodes" }, + { include = "model_nodes" }, { include = "orm" } ] +[tool.poetry.dependencies] +python = "^3.9" +sqlalchemy = "^2.0.43" +pydantic = "^2.0.0" + [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api"