diff --git a/examples/xml/template/demo_system/factory.py b/examples/xml/template/demo_system/factory.py index 6f793e5..2e85b9b 100644 --- a/examples/xml/template/demo_system/factory.py +++ b/examples/xml/template/demo_system/factory.py @@ -1,9 +1,11 @@ """ Example template classes """ +from typing import Callable import autosar.xml.template as ar_template import autosar.xml.element as ar_element import autosar.xml.enumeration as ar_enum +from autosar.xml.template import TemplateBase import autosar.xml.workspace as ar_workspace @@ -24,7 +26,11 @@ def __init__(self, self.encoding = encoding self.native_declaration = native_declaration - def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, **kwargs) -> ar_element.SwBaseType: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.SwBaseType: """ Factory method for SwBaseType """ @@ -33,7 +39,7 @@ def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, size=self.bit_size, encoding=self.encoding, native_declaration=self.native_declaration) - package.append(elem) + return elem @@ -51,15 +57,15 @@ def __init__(self, self.lower_limit = lower_limit self.upper_limit = upper_limit - def apply(self, - package: ar_element.Package, - workspace: ar_workspace.Workspace, - **kwargs) -> ar_element.DataConstraint: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.DataConstraint: """ Factory method """ elem = ar_element.DataConstraint.make_internal(self.element_name, self.lower_limit, self.upper_limit) - package.append(elem) return elem @@ -80,10 +86,11 @@ def __init__(self, self.auto_label = auto_label self.desc = desc - def apply(self, - package: ar_element.Package, - workspace: ar_workspace.Workspace, - **kwargs) -> ar_element.CompuMethod: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.CompuMethod: """ Factory method """ @@ -92,7 +99,6 @@ def apply(self, desc=self.desc, category=self.category, int_to_phys=computation) - package.append(elem) return elem @@ -126,7 +132,11 @@ def __init__(self, self.calibration_access = calibration_access self.type_emitter = type_emitter - def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, **kwargs) -> ar_element.SwBaseType: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.ImplementationDataType: """ Factory method """ @@ -143,7 +153,6 @@ def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, category=self.category, sw_data_def_props=sw_data_def_props, type_emitter=self.type_emitter) - package.append(elem) return elem @@ -195,8 +204,11 @@ def _create_compu_method(self, value_table: list[str]) -> ar_template.ElementTemplate: return CompuMethodEnumTemplate(element_name + suffix, namespace_name, value_table, auto_label=False) - def apply(self, package: ar_element.Package, - workspace: ar_workspace.Workspace, **kwargs) -> ar_element.ImplementationDataType: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.ImplementationDataType: """ Factory method """ @@ -212,7 +224,6 @@ def apply(self, package: ar_element.Package, desc=self.desc, category=self.category, sw_data_def_props=sw_data_def_props) - package.append(elem) return elem @@ -230,15 +241,20 @@ def __init__(self, self.mode_declarations = list(mode_declarations) self.initial_mode_name = initial_mode_name - def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, **kwargs) -> ar_element.SwBaseType: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.ModeDeclarationGroup: """ Factory method for SwBaseType """ - elem = ar_element.ModeDeclarationGroup(name=self.element_name, - mode_declarations=self.mode_declarations) - package.append(elem) + initial_mode_ref = None if self.initial_mode_name is not None: - elem.initial_mode_ref = elem.find(self.initial_mode_name).ref() + initial_mode_ref = '/'.join([element_ref, self.initial_mode_name]) + elem = ar_element.ModeDeclarationGroup(name=self.element_name, + mode_declarations=self.mode_declarations, + initial_mode_ref=initial_mode_ref) return elem @@ -259,11 +275,43 @@ def __init__(self, self.mode_declaration_group = mode_declaration_group self.is_service = is_service - def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, **kwargs) -> ar_element.SwBaseType: + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.ModeSwitchInterface: """ Element creation method """ elem = ar_element.ModeSwitchInterface(self.element_name, is_service=self.is_service) elem.create_mode_group(self.mode_group_name, self.mode_declaration_group.ref(workspace)) - package.append(elem) + return elem + + +CreateFuncType = Callable[[str, ar_workspace.Workspace, dict[str, ar_element.ARElement] | None], + ar_element.PortInterface] + + +class GenericPortInterfaceTemplate(ar_template.ElementTemplate): + """ + Generic element template + """ + + def __init__(self, + element_name: str, + namespace_name: str, + create_func: CreateFuncType, + depends: list[TemplateBase] | None = None) -> None: + super().__init__(element_name, namespace_name, ar_enum.PackageRole.PORT_INTERFACE, depends) + self.create_func = create_func + + def create(self, + element_ref: str, + workspace: ar_workspace.Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.PortInterface: + """ + Create method + """ + elem = self.create_func(element_ref, workspace, dependencies, **kwargs) return elem diff --git a/examples/xml/template/demo_system/portinterface.py b/examples/xml/template/demo_system/portinterface.py index 0666575..710417d 100644 --- a/examples/xml/template/demo_system/portinterface.py +++ b/examples/xml/template/demo_system/portinterface.py @@ -5,8 +5,27 @@ # pylint: disable=C0103, C0301 +import autosar.xml.element as ar_element +import autosar.xml.workspace as ar_workspace from . import factory, mode NAMESPACE = "Default" EcuM_CurrentMode = factory.ModeSwitchInterfaceTemplate("EcuM_CurrentMode", NAMESPACE, mode.EcuM_Mode, "currentMode", is_service=True) + + +def create_NvMService_interface(element_ref: str, + _1: ar_workspace.Workspace, + _2: dict[str, ar_element.ARElement] | None, + **_3) -> ar_element.ClientServerInterface: + """ + Create NvmService interface + """ + + interface = ar_element.ClientServerInterface("NvMService_I", is_service=True) + e_not_ok = interface.create_possible_error("E_NOT_OK", 1) + interface.create_operation("EraseBlock", possible_error_refs=element_ref + "/" + e_not_ok.name) + return interface + + +NvMService_I = factory.GenericPortInterfaceTemplate("NvMService_I", NAMESPACE, create_NvMService_interface) diff --git a/examples/xml/template/generate_xml.py b/examples/xml/template/generate_xml.py index 751d1d8..525947f 100644 --- a/examples/xml/template/generate_xml.py +++ b/examples/xml/template/generate_xml.py @@ -71,6 +71,7 @@ def apply_portinterfaces(workspace: ar_workspace.Workspace): Applies mode templates """ workspace.apply(portinterface.EcuM_CurrentMode) + workspace.apply(portinterface.NvMService_I) def main(): diff --git a/examples/xml/template/generated/PortInterfaces.arxml b/examples/xml/template/generated/PortInterfaces.arxml index d6b5962..df587a5 100644 --- a/examples/xml/template/generated/PortInterfaces.arxml +++ b/examples/xml/template/generated/PortInterfaces.arxml @@ -41,6 +41,24 @@ /ModeDclrGroups/EcuM_Mode + + NvMService_I + true + + + EraseBlock + + /PortInterfaces/NvMService_I/E_NOT_OK + + + + + + E_NOT_OK + 1 + + + diff --git a/src/autosar/xml/element.py b/src/autosar/xml/element.py index 9d985d7..d2612f9 100644 --- a/src/autosar/xml/element.py +++ b/src/autosar/xml/element.py @@ -3386,6 +3386,9 @@ def __init__(self, self._assign_optional_strict("error_code", error_code, int) +PossibleErrorRefsTypes = ApplicationErrorRef | list[ApplicationErrorRef] | str | list[str] + + class ClientServerOperation(Identifiable): """ Complex type AR:CLIENT-SERVER-OPERATION @@ -3397,7 +3400,7 @@ def __init__(self, arguments: ArgumentDataPrototype | list[ArgumentDataPrototype] | None = None, diag_arg_integrity: bool | None = None, fire_and_forget: bool | None = None, - possible_error_refs: ApplicationErrorRef | list[ApplicationErrorRef] | None = None, + possible_error_refs: PossibleErrorRefsTypes | None = None, **kwargs) -> None: super().__init__(name, **kwargs) self.arguments: list[ArgumentDataPrototype] = [] # .ARGUMENTS @@ -3422,7 +3425,9 @@ def __init__(self, if possible_error_refs is not None: if isinstance(possible_error_refs, ApplicationErrorRef): - self.append_argument(arguments) + self.append_possible_error_ref(possible_error_refs) + elif isinstance(possible_error_refs, str): + self.append_possible_error_ref(ApplicationErrorRef(possible_error_refs)) elif isinstance(possible_error_refs, list): for possible_error_ref in possible_error_refs: self.append_possible_error_ref(possible_error_ref) diff --git a/src/autosar/xml/template.py b/src/autosar/xml/template.py index e7dae64..a16cf44 100644 --- a/src/autosar/xml/template.py +++ b/src/autosar/xml/template.py @@ -51,19 +51,26 @@ def __init__(self, self.depends = depends @abstractmethod - def apply(self, package: Package, workspace: Workspace, **kwargs) -> ar_element.ARElement: + def create(self, + element_ref: str, + workspace: Workspace, + dependencies: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.ARElement: """ - This apply method shall solely focus on creating the - new element and return it. The workspace will handle the rest. + Element creation method. The workspace will automatically do the following: - * Make sure any dependencies have been created (optional) + Before call: + + * Make sure any (optional) dependencies have been created * Make sure the necessary package has been created * Make sure the element doesn't already exists - It's up to the implementer of the apply-method to call package.append to add the newly - created element + After call: + + * Appends the returned element to the package + """ def ref(self, workspace: Workspace) -> str: diff --git a/src/autosar/xml/workspace.py b/src/autosar/xml/workspace.py index 02da03c..f94b8ec 100644 --- a/src/autosar/xml/workspace.py +++ b/src/autosar/xml/workspace.py @@ -180,18 +180,27 @@ def _apply_element_template(self, template: ar_template.ElementTemplate, kwargs: created element """ if template.depends is not None: - self._create_dependencies(template.depends) + depends_map = self._create_dependencies(template.depends) + else: + depends_map = None package_ref = self.get_package_ref_by_role(template.namespace_name, template.package_role) package: ar_element.Package = self.make_packages(package_ref) if isinstance(package, ar_element.Package): elem = package.find(template.element_name) if elem is None: - elem = template.apply(package, self, **kwargs) + element_ref = package_ref + "/" + template.element_name + elem = template.create(element_ref, self, depends_map, **kwargs) + assert isinstance(elem, ar_element.ARElement) + package.append(elem) return elem raise TypeError(f"Expected Package, got {str(type(package))}") - def _create_dependencies(self, dependencies: list[ar_template.TemplateBase]) -> list[Any]: - items = [] + def _create_dependencies(self, dependencies: list[ar_template.TemplateBase] + ) -> dict[str, ar_element.ARElement]: + item_map = {} for dependency in dependencies: - items.append(self.apply(dependency)) - return items + elem = self.apply(dependency) + assert isinstance(elem, ar_element.ARElement) + assert hasattr(elem, "ref") + item_map[str(elem.ref())] = elem + return item_map diff --git a/tests/xml/test_template.py b/tests/xml/test_template.py index 56222c8..cf40a3a 100644 --- a/tests/xml/test_template.py +++ b/tests/xml/test_template.py @@ -28,7 +28,11 @@ def __init__(self, self.encoding = encoding self.native_declaration = native_declaration - def apply(self, package: ar_element.Package, _: ar_workspace.Workspace, **kwargs) -> ar_element.SwBaseType: + def create(self, + _1: str, + _2: ar_workspace.Workspace, + _3: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.SwBaseType: """ Template method """ @@ -37,7 +41,6 @@ def apply(self, package: ar_element.Package, _: ar_workspace.Workspace, **kwargs size=self.bit_size, encoding=self.encoding, native_declaration=self.native_declaration) - package.append(elem) return elem @@ -55,12 +58,15 @@ def __init__(self, self.lower_limit = lower_limit self.upper_limit = upper_limit - def apply(self, package: ar_element.Package, _: ar_workspace.Workspace, **kwargs) -> ar_element.DataConstraint: + def create(self, + _1: str, + _2: ar_workspace.Workspace, + _3: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.DataConstraint: """ Create new internal data constraint """ elem = ar_element.DataConstraint.make_internal(self.element_name, self.lower_limit, self.upper_limit) - package.append(elem) return elem @@ -85,7 +91,11 @@ def __init__(self, self.data_constraint = data_constraint self.calibration_access = calibration_access - def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, **kwargs) -> ar_element.SwBaseType: + def create(self, + _1: str, + workspace: ar_workspace.Workspace, + _2: dict[str, ar_element.ARElement] | None, + **kwargs) -> ar_element.SwBaseType: """ Template method """ @@ -99,7 +109,6 @@ def apply(self, package: ar_element.Package, workspace: ar_workspace.Workspace, desc=self.desc, category=self.category, sw_data_def_props=sw_data_def_props) - package.append(elem) return elem