From dab8efe18f3a0ac36ee41549a2c1748c994ff46d Mon Sep 17 00:00:00 2001 From: Marco Lampacrescia <marco.lampacrescia@de.bosch.com> Date: Wed, 9 Oct 2024 17:07:06 +0200 Subject: [PATCH] Check type of BtTickChild id Signed-off-by: Marco Lampacrescia <marco.lampacrescia@de.bosch.com> --- .../scxml_converter/scxml_entries/bt_utils.py | 5 +++ .../scxml_entries/scxml_bt_ticks.py | 36 +++++++++++++++++-- .../scxml_entries/scxml_transition.py | 18 +++++----- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/as2fm/scxml_converter/scxml_entries/bt_utils.py b/src/as2fm/scxml_converter/scxml_entries/bt_utils.py index 00fda812..eb4cb222 100644 --- a/src/as2fm/scxml_converter/scxml_entries/bt_utils.py +++ b/src/as2fm/scxml_converter/scxml_entries/bt_utils.py @@ -44,6 +44,11 @@ def str_to_int(resp_str: str) -> int: raise ValueError(f"Error: {resp_str} is an invalid BT Status type.") +def generate_bt_tick_event(instance_id: str) -> str: + """Generate the BT tick event name for a given BT node instance.""" + return f"bt_{instance_id}_tick" + + def is_bt_event(event_name: str) -> bool: """Given an event name, returns whether it is related to a BT event or not.""" bt_events = [f"bt_{suffix}" for suffix in ["tick", "running", "success", "failure"]] diff --git a/src/as2fm/scxml_converter/scxml_entries/scxml_bt_ticks.py b/src/as2fm/scxml_converter/scxml_entries/scxml_bt_ticks.py index 1b6b9b85..f2c1b3cb 100644 --- a/src/as2fm/scxml_converter/scxml_entries/scxml_bt_ticks.py +++ b/src/as2fm/scxml_converter/scxml_entries/scxml_bt_ticks.py @@ -17,17 +17,20 @@ SCXML entries related to Behavior Tree Ticks and related responses. """ -from typing import Optional, Union +from typing import List, Optional, Union from lxml import etree as ET from as2fm.scxml_converter.scxml_entries import ( ScxmlExecutionBody, + ScxmlIf, ScxmlSend, ScxmlTransition, execution_body_from_xml, + instantiate_exec_body_bt_events, ) -from as2fm.scxml_converter.scxml_entries.bt_utils import BtResponse +from as2fm.scxml_converter.scxml_entries.bt_utils import BtResponse, generate_bt_tick_event +from as2fm.scxml_converter.scxml_entries.utils import is_non_empty_string from as2fm.scxml_converter.scxml_entries.xml_utils import assert_xml_tag_ok, get_xml_argument @@ -56,6 +59,14 @@ def __init__( ): super().__init__(target, ["bt_tick"], condition, body) + def check_validity(self) -> bool: + return super().check_validity() + + def instantiate_bt_events(self, instance_id: int, children_ids: List[int]) -> ScxmlTransition: + self._events = [generate_bt_tick_event(instance_id)] + instantiate_exec_body_bt_events(self._body, instance_id, children_ids) + return ScxmlTransition(self._target, self._events, self._condition, self._body) + def as_xml(self) -> ET.Element: xml_bt_tick = ET.Element(BtTick.get_tag_name(), {"target": self._target}) if self._condition is not None: @@ -84,6 +95,27 @@ def __init__(self, child_id: Union[str, int]): child_id, (str, int) ), f"Error: SCXML BT Tick Child: invalid child id type {type(child_id)}." self._child = child_id + if isinstance(child_id, str): + child_id = child_id.strip() + try: + self._child = int(child_id) + except ValueError: + self._child = child_id + assert is_non_empty_string(BtTickChild, "id", self._child) + assert ( + self._child.isidentifier() + ), f"Error: SCXML BT Tick Child: invalid child id '{self._child}'." + + def check_validity(self) -> bool: + return True + + def instantiate_bt_events( + self, instance_id: int, children_ids: List[int] + ) -> Union[ScxmlIf, ScxmlSend]: + """ + Convert the BtTickChild to ScxmlSend if the child id is constant and an ScxmlIf otherwise. + """ + raise NotImplementedError("Error: SCXML BT Tick Child: instantiation not implemented.") def as_xml(self) -> ET.Element: xml_bt_tick_child = ET.Element(BtTickChild.get_tag_name(), {"id": str(self._child)}) diff --git a/src/as2fm/scxml_converter/scxml_entries/scxml_transition.py b/src/as2fm/scxml_converter/scxml_entries/scxml_transition.py index f3613db5..6b65fe86 100644 --- a/src/as2fm/scxml_converter/scxml_entries/scxml_transition.py +++ b/src/as2fm/scxml_converter/scxml_entries/scxml_transition.py @@ -39,7 +39,11 @@ valid_execution_body, valid_execution_body_entry_types, ) -from as2fm.scxml_converter.scxml_entries.utils import CallbackType, get_plain_expression +from as2fm.scxml_converter.scxml_entries.utils import ( + CallbackType, + get_plain_expression, + is_non_empty_string, +) class ScxmlTransition(ScxmlBase): @@ -145,22 +149,18 @@ def append_body_executable_entry(self, exec_entry: ScxmlExecutableEntry): ), "Error SCXML transition: invalid body entry found after extension." def check_validity(self) -> bool: - valid_target = isinstance(self._target, str) and len(self._target) > 0 + valid_target = is_non_empty_string(type(self), "target", self._target) + valid_condition = self._condition is None or ( + is_non_empty_string(type(self), "condition", self._condition) + ) valid_events = self._events is None or ( isinstance(self._events, list) and all(isinstance(ev, str) for ev in self._events) ) - valid_condition = self._condition is None or ( - isinstance(self._condition, str) and len(self._condition) > 0 - ) valid_body = self._body is None or valid_execution_body(self._body) - if not valid_target: - print("Error: SCXML transition: target is not valid.") if not valid_events: print("Error: SCXML transition: events are not valid.\nList of events:") for event in self._events: print(f"\t-'{event}'.") - if not valid_condition: - print("Error: SCXML transition: condition is not valid.") if not valid_body: print("Error: SCXML transition: executable content is not valid.") return valid_target and valid_events and valid_condition and valid_body