Skip to content

Commit

Permalink
Refactor ElementTemplate
Browse files Browse the repository at this point in the history
  • Loading branch information
cogu committed Feb 8, 2024
1 parent 6a1b652 commit de09029
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 44 deletions.
96 changes: 72 additions & 24 deletions examples/xml/template/demo_system/factory.py
Original file line number Diff line number Diff line change
@@ -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


Expand All @@ -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
"""
Expand All @@ -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


Expand All @@ -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


Expand All @@ -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
"""
Expand All @@ -92,7 +99,6 @@ def apply(self,
desc=self.desc,
category=self.category,
int_to_phys=computation)
package.append(elem)
return elem


Expand Down Expand Up @@ -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
"""
Expand All @@ -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


Expand Down Expand Up @@ -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
"""
Expand All @@ -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


Expand All @@ -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


Expand All @@ -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
19 changes: 19 additions & 0 deletions examples/xml/template/demo_system/portinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
1 change: 1 addition & 0 deletions examples/xml/template/generate_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
18 changes: 18 additions & 0 deletions examples/xml/template/generated/PortInterfaces.arxml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@
<TYPE-TREF DEST="MODE-DECLARATION-GROUP">/ModeDclrGroups/EcuM_Mode</TYPE-TREF>
</MODE-GROUP>
</MODE-SWITCH-INTERFACE>
<CLIENT-SERVER-INTERFACE>
<SHORT-NAME>NvMService_I</SHORT-NAME>
<IS-SERVICE>true</IS-SERVICE>
<OPERATIONS>
<CLIENT-SERVER-OPERATION>
<SHORT-NAME>EraseBlock</SHORT-NAME>
<POSSIBLE-ERROR-REFS>
<POSSIBLE-ERROR-REF DEST="APPLICATION-ERROR">/PortInterfaces/NvMService_I/E_NOT_OK</POSSIBLE-ERROR-REF>
</POSSIBLE-ERROR-REFS>
</CLIENT-SERVER-OPERATION>
</OPERATIONS>
<POSSIBLE-ERRORS>
<APPLICATION-ERROR>
<SHORT-NAME>E_NOT_OK</SHORT-NAME>
<ERROR-CODE>1</ERROR-CODE>
</APPLICATION-ERROR>
</POSSIBLE-ERRORS>
</CLIENT-SERVER-INTERFACE>
</ELEMENTS>
</AR-PACKAGE>
</AR-PACKAGES>
Expand Down
9 changes: 7 additions & 2 deletions src/autosar/xml/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
19 changes: 13 additions & 6 deletions src/autosar/xml/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
21 changes: 15 additions & 6 deletions src/autosar/xml/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit de09029

Please sign in to comment.