diff --git a/examples/xml/component/application_component.py b/examples/xml/component/application_component.py
index bb498d3..06f29ab 100644
--- a/examples/xml/component/application_component.py
+++ b/examples/xml/component/application_component.py
@@ -103,25 +103,23 @@ def create_application_component(workspace: autosar.xml.Workspace):
swc.create_provide_port("EngineSpeed", engine_speed_interface, com_spec={"init_value": engine_speed_init.ref(),
"uses_end_to_end_protection": False,
})
+ swc.create_internal_behavior()
workspace.add_element("ComponentTypes", swc)
+ impl = ar_element.SwcImplementation("SenderComponent_Implementation", behavior_ref=swc.internal_behavior.ref())
+ workspace.add_element("ComponentTypes", impl)
def save_xml_files(workspace: autosar.xml.Workspace):
"""
Saves workspace as XML documents
"""
- interface_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'portinterfaces.arxml'))
- platform_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'platform.arxml'))
- component_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'sender_component.arxml'))
- constant_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'constants.arxml'))
- workspace.create_document(interface_document_path, packages="/PortInterfaces")
- workspace.create_document(constant_document_path, packages="/Constants")
- workspace.create_document(platform_document_path, packages="/AUTOSAR_Platform")
- workspace.create_document(component_document_path, packages="/ComponentTypes")
+ workspace.set_document_root(os.path.abspath(os.path.join(os.path.dirname(__file__), "data")))
+ workspace.create_document("portinterfaces.arxml", packages="/PortInterfaces")
+ workspace.create_document("constants.arxml", packages="/Constants")
+ workspace.create_document("platform.arxml", packages="/AUTOSAR_Platform")
+ workspace.create_document_mapping(package_ref="/ComponentTypes",
+ element_types=ar_element.SwComponentType,
+ suffix_filters=["_Implementation"])
workspace.write_documents()
diff --git a/examples/xml/component/composition_component.py b/examples/xml/component/composition_component.py
index ad781ac..6d34cd5 100644
--- a/examples/xml/component/composition_component.py
+++ b/examples/xml/component/composition_component.py
@@ -111,7 +111,10 @@ def create_receiver_component(workspace: autosar.xml.Workspace):
"handle_never_received": False
})
swc.create_require_port("FreeRunningTimer", timer_interface, com_spec={"GetTime": {}, "IsTimerElapsed": {}})
+ swc.create_internal_behavior()
workspace.add_element("ComponentTypes", swc)
+ impl = ar_element.SwcImplementation("ReceiverComponent_Implementation", behavior_ref=swc.internal_behavior.ref())
+ workspace.add_element("ComponentTypes", impl)
def create_server_component(workspace: autosar.xml.Workspace):
@@ -123,7 +126,10 @@ def create_server_component(workspace: autosar.xml.Workspace):
swc.create_provide_port("FreeRunningTimer", timer_interface, com_spec={"GetTime": {"queue_length": 1},
"IsTimerElapsed": {"queue_length": 1}
})
+ swc.create_internal_behavior()
workspace.add_element("ComponentTypes", swc)
+ impl = ar_element.SwcImplementation("TimerComponent_Implementation", behavior_ref=swc.internal_behavior.ref())
+ workspace.add_element("ComponentTypes", impl)
def create_composition_component(workspace: autosar.xml.Workspace):
@@ -153,18 +159,13 @@ def save_xml_files(workspace: autosar.xml.Workspace):
"""
Saves workspace as XML documents
"""
- interface_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'portinterfaces.arxml'))
- platform_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'platform.arxml'))
- component_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'composition.arxml'))
- constant_document_path = os.path.abspath(os.path.join(os.path.dirname(
- __file__), 'data', 'constants.arxml'))
- workspace.create_document(interface_document_path, packages="/PortInterfaces")
- workspace.create_document(constant_document_path, packages="/Constants")
- workspace.create_document(platform_document_path, packages="/AUTOSAR_Platform")
- workspace.create_document(component_document_path, packages="/ComponentTypes")
+ workspace.set_document_root(os.path.abspath(os.path.join(os.path.dirname(__file__), "data")))
+ workspace.create_document("portinterfaces.arxml", packages="/PortInterfaces")
+ workspace.create_document("constants.arxml", packages="/Constants")
+ workspace.create_document("platform.arxml", packages="/AUTOSAR_Platform")
+ workspace.create_document_mapping(package_ref="/ComponentTypes",
+ element_types=ar_element.SwComponentType,
+ suffix_filters=["_Implementation"])
workspace.write_documents()
diff --git a/examples/xml/component/data/composition.arxml b/examples/xml/component/data/CompositionComponent.arxml
similarity index 56%
rename from examples/xml/component/data/composition.arxml
rename to examples/xml/component/data/CompositionComponent.arxml
index 2167833..9c461ed 100644
--- a/examples/xml/component/data/composition.arxml
+++ b/examples/xml/component/data/CompositionComponent.arxml
@@ -4,78 +4,6 @@
ComponentTypes
-
- ReceiverComponent
-
-
- VehicleSpeed
-
-
- /PortInterfaces/VehicleSpeed_I/VehicleSpeed
- false
- 0
- false
- false
-
-
- /Constants/VehicleSpeed_IV
-
-
-
-
- /PortInterfaces/VehicleSpeed_I
-
-
- EngineSpeed
-
-
- /PortInterfaces/EngineSpeed_I/EngineSpeed
- false
- 0
- false
- false
-
-
- /Constants/EngineSpeed_IV
-
-
-
-
- /PortInterfaces/EngineSpeed_I
-
-
- FreeRunningTimer
-
-
- /PortInterfaces/FreeRunningTimer_I/GetTime
-
-
- /PortInterfaces/FreeRunningTimer_I/IsTimerElapsed
-
-
- /PortInterfaces/FreeRunningTimer_I
-
-
-
-
- TimerComponent
-
-
- FreeRunningTimer
-
-
- /PortInterfaces/FreeRunningTimer_I/GetTime
- 1
-
-
- /PortInterfaces/FreeRunningTimer_I/IsTimerElapsed
- 1
-
-
- /PortInterfaces/FreeRunningTimer_I
-
-
-
CompositionComponent
diff --git a/examples/xml/component/data/ReceiverComponent.arxml b/examples/xml/component/data/ReceiverComponent.arxml
new file mode 100644
index 0000000..3c0a559
--- /dev/null
+++ b/examples/xml/component/data/ReceiverComponent.arxml
@@ -0,0 +1,72 @@
+
+
+
+
+ ComponentTypes
+
+
+ ReceiverComponent
+
+
+ VehicleSpeed
+
+
+ /PortInterfaces/VehicleSpeed_I/VehicleSpeed
+ false
+ 0
+ false
+ false
+
+
+ /Constants/VehicleSpeed_IV
+
+
+
+
+ /PortInterfaces/VehicleSpeed_I
+
+
+ EngineSpeed
+
+
+ /PortInterfaces/EngineSpeed_I/EngineSpeed
+ false
+ 0
+ false
+ false
+
+
+ /Constants/EngineSpeed_IV
+
+
+
+
+ /PortInterfaces/EngineSpeed_I
+
+
+ FreeRunningTimer
+
+
+ /PortInterfaces/FreeRunningTimer_I/GetTime
+
+
+ /PortInterfaces/FreeRunningTimer_I/IsTimerElapsed
+
+
+ /PortInterfaces/FreeRunningTimer_I
+
+
+
+
+ ReceiverComponent_InternalBehavior
+
+
+
+
+ ReceiverComponent_Implementation
+ /ComponentTypes/ReceiverComponent/ReceiverComponent_InternalBehavior
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/xml/component/data/sender_component.arxml b/examples/xml/component/data/SenderComponent.arxml
similarity index 82%
rename from examples/xml/component/data/sender_component.arxml
rename to examples/xml/component/data/SenderComponent.arxml
index 32f5ee2..4dc5947 100644
--- a/examples/xml/component/data/sender_component.arxml
+++ b/examples/xml/component/data/SenderComponent.arxml
@@ -38,7 +38,16 @@
/PortInterfaces/EngineSpeed_I
+
+
+ SenderComponent_InternalBehavior
+
+
+
+ SenderComponent_Implementation
+ /ComponentTypes/SenderComponent/SenderComponent_InternalBehavior
+
diff --git a/examples/xml/component/data/TimerComponent.arxml b/examples/xml/component/data/TimerComponent.arxml
new file mode 100644
index 0000000..e6599fb
--- /dev/null
+++ b/examples/xml/component/data/TimerComponent.arxml
@@ -0,0 +1,38 @@
+
+
+
+
+ ComponentTypes
+
+
+ TimerComponent
+
+
+ FreeRunningTimer
+
+
+ /PortInterfaces/FreeRunningTimer_I/GetTime
+ 1
+
+
+ /PortInterfaces/FreeRunningTimer_I/IsTimerElapsed
+ 1
+
+
+ /PortInterfaces/FreeRunningTimer_I
+
+
+
+
+ TimerComponent_InternalBehavior
+
+
+
+
+ TimerComponent_Implementation
+ /ComponentTypes/TimerComponent/TimerComponent_InternalBehavior
+
+
+
+
+
\ No newline at end of file
diff --git a/run_examples.cmd b/run_examples.cmd
index 26ecf16..81e9116 100644
--- a/run_examples.cmd
+++ b/run_examples.cmd
@@ -15,8 +15,8 @@ python examples\xml\port_interface\client_server_interface.py
python examples\xml\port_interface\mode_switch_interface.py
python examples\xml\component\application_component.py
python examples\xml\component\composition_component.py
-python examples\xml\template\generate_xml_using_config.py
-python examples\xml\template\generate_xml_without_config.py
+python examples\template\generate_xml_using_config.py
+python examples\template\generate_xml_without_config.py
python examples\generator\data_types\gen_type_defs_scalar.py
python examples\generator\data_types\gen_type_defs_array.py
python examples\generator\data_types\gen_type_defs_record.py
diff --git a/src/autosar/xml/document.py b/src/autosar/xml/document.py
index 2187e98..42a4f79 100644
--- a/src/autosar/xml/document.py
+++ b/src/autosar/xml/document.py
@@ -3,7 +3,7 @@
AUTOSAR Document
"""
# pylint: disable=R0801
-from typing import Any
+from autosar.base import DEFAULT_SCHEMA_VERSION
import autosar.xml.element as ar_element
@@ -23,49 +23,14 @@ def schema_file(self) -> str:
return f'AUTOSAR_{self.schema_version:05d}.xsd'
-class Document(DocumentMeta):
+class Document(ar_element.PackageCollection, DocumentMeta):
"""
Implements AUTOSAR root description element
"""
- def __init__(self, packages: list[ar_element.Package] | None = None, schema_version=51) -> None:
- super().__init__(schema_version)
+ def __init__(self, packages: list[ar_element.Package] | None = None, schema_version=DEFAULT_SCHEMA_VERSION) -> None:
+ ar_element.PackageCollection.__init__(self, packages)
+ DocumentMeta.__init__(self, schema_version)
self.file_info_comment = None # .FILE-INFO-COMMENT
self.admin_data = None # .ADMIN-DATA
self.introduction = None # .INTRODUCTION
- self.packages: list[ar_element.Package] = [] # .PACKAGES
- self._package_map = {} # internal package map
- if packages is not None:
- for package in packages:
- self.append(package)
-
- def append(self, package: ar_element.Package):
- """
- Appends package to this document and
- appropriately updates reference links
- """
- if isinstance(package, ar_element.Package):
- if package.name in self._package_map:
- raise ValueError(
- f"Package with SHORT-NAME '{package.name}' already exists")
- package.parent = self
- self.packages.append(package)
- self._package_map[package.name] = package
-
- def find(self, ref: str) -> Any:
- """
- Finds item by reference
- """
- if ref.startswith('/'):
- ref = ref[1:]
- parts = ref.partition('/')
- package = self._package_map.get(parts[0], None)
- if (package is not None) and (len(parts[2]) > 0):
- return package.find(parts[2])
- return package
-
- def update_ref_parts(self, ref_parts: list[str]):
- """
- Utility method used generating XML references
- """
- ref_parts.append('')
diff --git a/src/autosar/xml/element.py b/src/autosar/xml/element.py
index 6d6559b..1caf2ba 100644
--- a/src/autosar/xml/element.py
+++ b/src/autosar/xml/element.py
@@ -559,6 +559,19 @@ def __str__(self) -> str:
return self.value
+class PackageRef(BaseRef):
+ """
+ References to AR-PACKAGE--SUBTYPES-ENUM
+ """
+
+ def __init__(self, value: str) -> None:
+ super().__init__(value, ar_enum.IdentifiableSubTypes.AR_PACKAGE)
+
+ def _accepted_subtypes(self) -> set[ar_enum.IdentifiableSubTypes]:
+ """Acceptable values for dest"""
+ return {ar_enum.IdentifiableSubTypes.AR_PACKAGE}
+
+
class CompuMethodRef(BaseRef):
"""
CompuMethod reference
@@ -3362,7 +3375,7 @@ def __init__(self,
class Package(CollectableElement):
"""
- AR:PACKAGE
+ AR:AR-PACKAGE
"""
def __init__(self, name: str, **kwargs: dict) -> None:
@@ -3460,6 +3473,88 @@ def filter_regex(self, pattern: str | re.Pattern) -> Iterator[ARElement]:
if regex.match(elem.name):
yield elem
+ def ref(self) -> PackageRef:
+ """
+ Returns a reference to this package or
+ None if the package is not a sub-package or a root package
+ in a document/workspace
+ """
+ ref_str = self._calc_ref_string()
+ return None if ref_str is None else PackageRef(ref_str)
+
+
+class PackageCollection:
+ """
+ Base class that maintains a collection of AUTOSAR packages
+ """
+
+ def __init__(self, packages: list[Package] | None = None) -> None:
+ self.packages: list[Package] = [] # .PACKAGES
+ self._package_dict = {} # internal package map
+ if packages is not None:
+ for package in packages:
+ self.append(package)
+
+ def append(self, package: Package):
+ """
+ Appends package to this document and
+ appropriately updates reference links
+ """
+ if isinstance(package, Package):
+ if package.name in self._package_dict:
+ raise ValueError(
+ f"Package with SHORT-NAME '{package.name}' already exists")
+ package.parent = self
+ self.packages.append(package)
+ self._package_dict[package.name] = package
+
+ def find(self, ref: str) -> Any:
+ """
+ Finds item by reference
+ """
+ if ref.startswith('/'):
+ ref = ref[1:]
+ parts = ref.partition('/')
+ package = self._package_dict.get(parts[0], None)
+ if (package is not None) and (len(parts[2]) > 0):
+ return package.find(parts[2])
+ return package
+
+ def update_ref_parts(self, ref_parts: list[str]):
+ """
+ Utility method used generating XML references
+ """
+ ref_parts.append('')
+
+ def create_package(self, name: str, **kwargs) -> Package:
+ """
+ Creates new package in collection
+ """
+ if name in self._package_dict:
+ return ValueError(f"Package with name '{name}' already exists")
+ package = Package(name, **kwargs)
+ self.append(package)
+ return package
+
+ def make_packages(self, *refs: list[str]) -> Package | list[Package]:
+ """
+ Recursively creates packages from reference(s)
+ Returns a list of created packages.
+ If only one argument is given it will return that package (not a list).
+ """
+ result = []
+ for ref in refs:
+ if ref.startswith('/'):
+ ref = ref[1:]
+ parts = ref.partition('/')
+ package = self._package_dict.get(parts[0], None)
+ if package is None:
+ package = self.create_package(parts[0])
+ if len(parts[2]) > 0:
+ package = package.make_packages(parts[2])
+ result.append(package)
+ return result[0] if len(result) == 1 else result
+
# --- ModeDeclaration elements
@@ -5263,11 +5358,38 @@ def __init__(self,
symbol_props: SymbolProps | None = None,
**kwargs) -> None:
super().__init__(name, **kwargs)
- self.internal_behavior: SwcInternalBehavior | None = None
+ self._internal_behavior: SwcInternalBehavior | None = None
self.symbol_props = None # AR:SYMBOL-PROPS
- self._assign_optional_strict("internal_behavior", internal_behavior, SwcInternalBehavior)
+ self._assign_optional_strict("_internal_behavior", internal_behavior, SwcInternalBehavior)
self._assign_optional_strict("symbol_props", symbol_props, SymbolProps)
+ @property
+ def internal_behavior(self) -> Union["SwcInternalBehavior", None]:
+ """
+ Internal behavior getter
+ """
+ return self._internal_behavior
+
+ @internal_behavior.setter
+ def internal_behavior(self, value: Union["SwcInternalBehavior", None]):
+ """
+ Internal behavior setter
+ """
+ self._internal_behavior = value
+ if value is not None:
+ value.parent = self
+
+ def create_internal_behavior(self, name: str = None, **kwargs) -> "SwcInternalBehavior":
+ """
+ Creates an empty internal behavior object and adds it to the component.
+ If the name argument is left as None, a default name will be created based on the name of
+ the software component
+ """
+ if name is None:
+ name = self.name + "_InternalBehavior"
+ self.internal_behavior = SwcInternalBehavior(name, **kwargs)
+ return self.internal_behavior
+
class ApplicationSoftwareComponentType(AtomicSoftwareComponentType):
"""
@@ -5793,6 +5915,14 @@ def __init__(self,
**kwargs) -> None:
super().__init__(name, **kwargs)
+ def ref(self) -> SwcInternalBehaviorRef | None:
+ """
+ Returns a reference to this element or
+ None if the element is not yet part of a package
+ """
+ ref_str = self._calc_ref_string()
+ return None if ref_str is None else SwcInternalBehaviorRef(ref_str)
+
class SwcImplementation(Implementation):
"""
diff --git a/src/autosar/xml/enumeration.py b/src/autosar/xml/enumeration.py
index 190eb2a..a8aacb2 100644
--- a/src/autosar/xml/enumeration.py
+++ b/src/autosar/xml/enumeration.py
@@ -206,39 +206,40 @@ class IdentifiableSubTypes(Enum):
APPLICATION_RECORD_DATA_TYPE = 12
APPLICATION_RECORD_ELEMENT = 13
APPLICATION_SW_COMPONENT_TYPE = 14
- ARGUMENT_DATA_PROTOTYPE = 15
- AUTOSAR_DATA_PROTOTYPE = 16
- AUTOSAR_DATA_TYPE = 17
- BSW_MODULE_ENTRY = 18
- CLIENT_SERVER_INTERFACE = 19
- CLIENT_SERVER_OPERATION = 20
- COMPOSITION_SW_COMPONENT_TYPE = 21
- COMPU_METHOD = 22
- CONSTANT_SPECIFICATION = 23
- DATA_CONSTR = 24
- DATA_PROTOTYPE = 25
- E2E_PROFILE_COMPATIBILITY_PROPS = 26
- IMPLEMENTATION_DATA_TYPE = 27
- IMPLEMENTATION_DATA_TYPE_ELEMENT = 28
- MODE_DECLARATION = 29
- MODE_DECLARATION_GROUP = 30
- MODE_DECLARATION_GROUP_PROTOTYPE = 31
- MODE_SWITCH_INTERFACE = 32
- NV_DATA_INTERFACE = 33
- P_PORT_PROTOTYPE = 34
- PARAMETER_INTERFACE = 35
- PARAMETER_DATA_PROTOTYPE = 36
- PHYSICAL_DIMENSION = 37
- PORT_PROTOTYPE = 38
- PR_PORT_PROTOTYPE = 39
- R_PORT_PROTOTYPE = 40
- SENDER_RECEIVER_INTERFACE = 41
- SW_ADDR_METHOD = 42
- SW_BASE_TYPE = 43
- SW_COMPONENT_PROTOTYPE = 44
- SWC_INTERNAL_BEHAVIOR = 45
- UNIT = 46
- VARIABLE_DATA_PROTOTYPE = 47
+ AR_PACKAGE = 15
+ ARGUMENT_DATA_PROTOTYPE = 16
+ AUTOSAR_DATA_PROTOTYPE = 17
+ AUTOSAR_DATA_TYPE = 18
+ BSW_MODULE_ENTRY = 19
+ CLIENT_SERVER_INTERFACE = 20
+ CLIENT_SERVER_OPERATION = 21
+ COMPOSITION_SW_COMPONENT_TYPE = 22
+ COMPU_METHOD = 23
+ CONSTANT_SPECIFICATION = 24
+ DATA_CONSTR = 25
+ DATA_PROTOTYPE = 26
+ E2E_PROFILE_COMPATIBILITY_PROPS = 27
+ IMPLEMENTATION_DATA_TYPE = 28
+ IMPLEMENTATION_DATA_TYPE_ELEMENT = 29
+ MODE_DECLARATION = 30
+ MODE_DECLARATION_GROUP = 31
+ MODE_DECLARATION_GROUP_PROTOTYPE = 32
+ MODE_SWITCH_INTERFACE = 33
+ NV_DATA_INTERFACE = 34
+ P_PORT_PROTOTYPE = 35
+ PARAMETER_INTERFACE = 36
+ PARAMETER_DATA_PROTOTYPE = 37
+ PHYSICAL_DIMENSION = 38
+ PORT_PROTOTYPE = 39
+ PR_PORT_PROTOTYPE = 40
+ R_PORT_PROTOTYPE = 41
+ SENDER_RECEIVER_INTERFACE = 42
+ SW_ADDR_METHOD = 43
+ SW_BASE_TYPE = 44
+ SW_COMPONENT_PROTOTYPE = 45
+ SWC_INTERNAL_BEHAVIOR = 46
+ UNIT = 47
+ VARIABLE_DATA_PROTOTYPE = 48
class IntervalType(Enum):
@@ -706,6 +707,7 @@ class VersionedTextValue:
"APPLICATION-RECORD-DATA-TYPE": IdentifiableSubTypes.APPLICATION_RECORD_DATA_TYPE,
"APPLICATION-RECORD-ELEMENT": IdentifiableSubTypes.APPLICATION_RECORD_ELEMENT,
"APPLICATION-SW-COMPONENT-TYPE": IdentifiableSubTypes.APPLICATION_SW_COMPONENT_TYPE,
+ "AR-PACKAGE": IdentifiableSubTypes.AR_PACKAGE,
"ARGUMENT-DATA-PROTOTYPE": IdentifiableSubTypes.ARGUMENT_DATA_PROTOTYPE,
"AUTOSAR-DATA-PROTOTYPE": IdentifiableSubTypes.AUTOSAR_DATA_PROTOTYPE,
"AUTOSAR-DATA-TYPE": IdentifiableSubTypes.AUTOSAR_DATA_TYPE,
@@ -1061,38 +1063,39 @@ def xml_to_enum(enum_type_name: str, xml_text: str, schema_version: int = ar_bas
"APPLICATION-RECORD-ELEMENT", # 13
"APPLICATION-SW-COMPONENT-TYPE", # 14
"ARGUMENT-DATA-PROTOTYPE", # 15
- "AUTOSAR-DATA-PROTOTYPE", # 16
- "AUTOSAR-DATA-TYPE", # 17
- "BSW-MODULE-ENTRY", # 18
- "CLIENT-SERVER-INTERFACE", # 19
- "CLIENT-SERVER-OPERATION", # 20
- "COMPOSITION-SW-COMPONENT-TYPE", # 21
- "COMPU-METHOD", # 22
- "CONSTANT-SPECIFICATION", # 23
- "DATA-CONSTR", # 24
- "DATA-PROTOTYPE", # 25
- "E-2-E-PROFILE-COMPATIBILITY-PROPS", # 26
- "IMPLEMENTATION-DATA-TYPE", # 27
- "IMPLEMENTATION-DATA-TYPE-ELEMENT", # 28
- "MODE-DECLARATION", # 29
- "MODE-DECLARATION-GROUP", # 30
- "MODE-DECLARATION-GROUP-PROTOTYPE", # 31
- "MODE-SWITCH-INTERFACE", # 32
- "NV-DATA-INTERFACE", # 33
- "P-PORT-PROTOTYPE", # 34
- "PARAMETER-INTERFACE", # 35
- "PARAMETER-DATA-PROTOTYPE", # 36
- "PHYSICAL-DIMENSION", # 37
- "PORT-PROTOTYPE", # 38
- "PR-PORT-PROTOTYPE", # 39
- "R-PORT-PROTOTYPE", # 40
- "SENDER-RECEIVER-INTERFACE", # 41
- "SW-ADDR-METHOD", # 42
- "SW-BASE-TYPE", # 43
- "SW-COMPONENT-PROTOTYPE", # 44
- "SWC-INTERNAL-BEHAVIOR", # 45
- "UNIT", # 46
- "VARIABLE-DATA-PROTOTYPE", # 47
+ "AR-PACKAGE", # 16
+ "AUTOSAR-DATA-PROTOTYPE", # 17
+ "AUTOSAR-DATA-TYPE", # 18
+ "BSW-MODULE-ENTRY", # 19
+ "CLIENT-SERVER-INTERFACE", # 20
+ "CLIENT-SERVER-OPERATION", # 21
+ "COMPOSITION-SW-COMPONENT-TYPE", # 22
+ "COMPU-METHOD", # 23
+ "CONSTANT-SPECIFICATION", # 24
+ "DATA-CONSTR", # 25
+ "DATA-PROTOTYPE", # 26
+ "E-2-E-PROFILE-COMPATIBILITY-PROPS", # 27
+ "IMPLEMENTATION-DATA-TYPE", # 28
+ "IMPLEMENTATION-DATA-TYPE-ELEMENT", # 29
+ "MODE-DECLARATION", # 30
+ "MODE-DECLARATION-GROUP", # 31
+ "MODE-DECLARATION-GROUP-PROTOTYPE", # 32
+ "MODE-SWITCH-INTERFACE", # 33
+ "NV-DATA-INTERFACE", # 34
+ "P-PORT-PROTOTYPE", # 35
+ "PARAMETER-INTERFACE", # 36
+ "PARAMETER-DATA-PROTOTYPE", # 37
+ "PHYSICAL-DIMENSION", # 38
+ "PORT-PROTOTYPE", # 39
+ "PR-PORT-PROTOTYPE", # 40
+ "R-PORT-PROTOTYPE", # 41
+ "SENDER-RECEIVER-INTERFACE", # 42
+ "SW-ADDR-METHOD", # 43
+ "SW-BASE-TYPE", # 44
+ "SW-COMPONENT-PROTOTYPE", # 45
+ "SWC-INTERNAL-BEHAVIOR", # 46
+ "UNIT", # 47
+ "VARIABLE-DATA-PROTOTYPE", # 48
],
"IntervalType": [
"CLOSED", # 0
diff --git a/src/autosar/xml/reader.py b/src/autosar/xml/reader.py
index 92c9978..6528707 100644
--- a/src/autosar/xml/reader.py
+++ b/src/autosar/xml/reader.py
@@ -3993,9 +3993,12 @@ def _read_atomic_sw_component_type(self, child_elements: ChildElementMap, data:
"""
Reads group AR:ATOMIC-SW-COMPONENT-TYPE
"""
- xml_child = child_elements.get("SWC-INTERNAL-BEHAVIOR")
+ xml_child = child_elements.get("INTERNAL-BEHAVIORS")
if xml_child is not None:
- data["internal_behavior"] = self._read_swc_internal_behavior(xml_child)
+ # We only support max 1 internal behavior element
+ xml_grand_child = xml_child.find("./SWC-INTERNAL-BEHAVIOR")
+ if xml_grand_child is not None:
+ data["internal_behavior"] = self._read_swc_internal_behavior(xml_grand_child)
xml_child = child_elements.get("SYMBOL-PROPS")
if xml_child is not None:
data["symbol_props"] = self._read_symbol_props(xml_child)
diff --git a/src/autosar/xml/workspace.py b/src/autosar/xml/workspace.py
index 4062b4d..e4763f0 100644
--- a/src/autosar/xml/workspace.py
+++ b/src/autosar/xml/workspace.py
@@ -18,7 +18,7 @@
class DocumentConfig:
"""
- Internal class used during document creation
+ Used to store settings about a document creation action
"""
def __init__(self, file_path: str, package_refs: list[str] | str | None = None) -> None:
@@ -33,6 +33,27 @@ def __init__(self, file_path: str, package_refs: list[str] | str | None = None)
self.package_refs.append(package_ref)
+class PackageToDocumentMapping:
+ """
+ Used to store settings for a package-to-document-mapping action.
+ This is used to split a package into multiple documents based on element types
+ """
+
+ def __init__(self,
+ package_ref: str,
+ element_types: type | tuple[type],
+ suffix_filters: str | list[str]):
+ self.package_ref: str = package_ref
+ self.element_types: type | tuple[type] = element_types
+ self.suffix_filters: list[str] = []
+ if isinstance(suffix_filters, str):
+ self.element_types.append(suffix_filters)
+ else:
+ for suffix_filter in suffix_filters:
+ assert isinstance(package_ref, str)
+ self.suffix_filters.append(suffix_filter)
+
+
class Namespace:
"""
Namespace
@@ -52,18 +73,18 @@ def __init__(self, name: str, package_map: dict[str, str], base_ref: str | None
self.package_map[package_role] = abs_path
-class Workspace:
+class Workspace(ar_element.PackageCollection):
"""
Workspace
"""
def __init__(self, config_file_path: str | None = None, document_root: str | None = None) -> None:
self.namespaces: dict[str, Namespace] = {}
- self.packages: list[ar_element.Package] = []
- self._package_dict: dict[str, ar_element.Package] = {} # Each key is the name of an actual package
self.documents: list[DocumentConfig] = []
+ self.document_mappings: list[PackageToDocumentMapping] = []
self.document_root = document_root
self.package_map: dict[str, ar_element.Package] = {} # Each key is user-defined
+ super().__init__()
if config_file_path is not None:
self.load_config(config_file_path)
@@ -97,35 +118,6 @@ def get_package_ref_by_role(self, namespace_name: str, role: ar_enum.PackageRole
raise ValueError(f"Role '{str(role)}'not in namespace map") from ex
return posixpath.normpath(posixpath.join(base_ref, rel_path))
- def create_package(self, name: str, **kwargs) -> ar_element.Package:
- """
- Creates new package in workspace
- """
- if name in self._package_dict:
- return ValueError(f"Package with name '{name}' already exists")
- package = ar_element.Package(name, **kwargs)
- self.append(package)
- return package
-
- def make_packages(self, *refs: list[str]) -> ar_element.Package | list[ar_element.Package]:
- """
- Recursively creates packages from reference(s)
- Returns a list of created packages.
- If only one argument is given it will return that package (not a list).
- """
- result = []
- for ref in refs:
- if ref.startswith('/'):
- ref = ref[1:]
- parts = ref.partition('/')
- package = self._package_dict.get(parts[0], None)
- if package is None:
- package = self.create_package(parts[0])
- if len(parts[2]) > 0:
- package = package.make_packages(parts[2])
- result.append(package)
- return result[0] if len(result) == 1 else result
-
def init_package_map(self, mapping: dict[str, str]) -> None:
"""
Initializes an internally stored package map using key-value pairs.
@@ -161,7 +153,7 @@ def find_element(self, package_key: str, element_name: str) -> ar_element.ARElem
raise RuntimeError("Internal package map not initialized")
return self.package_map[package_key].find(element_name)
- def get_package(self, package_key: str) -> ar_element.Package:
+ def get_package_by_key(self, package_key: str) -> ar_element.Package:
"""
Returns the package referenced by package_key.
@@ -171,33 +163,6 @@ def get_package(self, package_key: str) -> ar_element.Package:
raise RuntimeError("Internal package map not initialized")
return self.package_map[package_key]
- def append(self, package: ar_element.Package):
- """
- Appends package to this worksapace
- """
- assert isinstance(package, ar_element.Package)
- self._package_dict[package.name] = package
- self.packages.append(package)
- package.parent = self
-
- def find(self, ref: str) -> ar_element.Identifiable | None:
- """
- Finds item by reference
- """
- if ref.startswith('/'):
- ref = ref[1:]
- parts = ref.partition('/')
- package = self._package_dict.get(parts[0], None)
- if (package is not None) and (len(parts[2]) > 0):
- return package.find(parts[2])
- return package
-
- def update_ref_parts(self, ref_parts: list[str]):
- """
- Utility method used generating XML references
- """
- ref_parts.append('')
-
def apply(self, template: Any, **kwargs) -> Any:
"""
Applies template oject in this workspace
@@ -216,31 +181,30 @@ def create_document(self, file_path: str, packages: str | list[str] | None = Non
"""
self.documents.append(DocumentConfig(file_path, packages))
+ def create_document_mapping(self,
+ package_ref: str,
+ element_types: type | tuple[type],
+ suffix_filters: str | list[str]):
+ """
+ Splits a package into multiple documents. The document name(s) equal the short-name of the found element(s)
+ """
+ self.document_mappings.append(PackageToDocumentMapping(package_ref, element_types, suffix_filters))
+
def set_document_root(self, directory: str) -> None:
"""
Sets root directory where documents are written
"""
self.document_root = directory
- def write_documents(self, scehema_version=ar_base.DEFAULT_SCHEMA_VERSION) -> None:
+ def write_documents(self, schema_version=ar_base.DEFAULT_SCHEMA_VERSION) -> None:
"""
Writes all documents to file system
"""
writer = Writer()
for document_config in self.documents:
- document = document_config.document
- file_path = document_config.file_path
- package_refs = document_config.package_refs
- document.schema_version = scehema_version
- for package_ref in package_refs:
- package = self.find(package_ref)
- if package is not None:
- if not isinstance(package, ar_element.Package):
- raise ValueError(f"'{package_ref}' does not reference a package element")
- document.append(package)
- if self.document_root is not None:
- file_path = os.path.join(self.document_root, file_path)
- writer.write_file(document, file_path)
+ self._write_document_from_config(writer, schema_version, document_config)
+ for package_document_mapping in self.document_mappings:
+ self._gen_package_to_document_mapping(writer, schema_version, package_document_mapping)
def load_config(self, file_path: str) -> None:
"""
@@ -257,6 +221,58 @@ def load_config(self, file_path: str) -> None:
for name, doc_config in document.items():
self._create_document_from_config(name, doc_config)
+ def _write_document_from_config(self,
+ writer: Writer,
+ schema_version: int,
+ document_config: DocumentConfig) -> None:
+ document = document_config.document
+ file_path = document_config.file_path
+ package_refs = document_config.package_refs
+ document.schema_version = schema_version
+ for package_ref in package_refs:
+ package = self.find(package_ref)
+ if package is not None:
+ if not isinstance(package, ar_element.Package):
+ raise ValueError(f"'{package_ref}' does not reference a package element")
+ document.append(package)
+ if self.document_root is not None:
+ file_path = os.path.join(self.document_root, file_path)
+ writer.write_file(document, file_path)
+
+ def _gen_package_to_document_mapping(self,
+ writer: Writer,
+ schema_version: int,
+ mapping: PackageToDocumentMapping) -> None:
+ package = self.find(mapping.package_ref)
+ if package is not None:
+ if not isinstance(package, ar_element.Package):
+ raise ValueError(f"'{mapping.package_ref}' does not reference a package element")
+ element_map = {}
+ type_matched_elements = {}
+ for element in package.elements:
+ element_map[element.name] = element
+ if isinstance(element, mapping.element_types):
+ type_matched_elements[element.name] = element
+ for matched_element in type_matched_elements.values():
+ document_name = matched_element.name + ".arxml"
+ element_list = [matched_element]
+ if mapping.suffix_filters:
+ for suffix in mapping.suffix_filters:
+ if len(suffix) > 0:
+ name = matched_element.name + suffix
+ extra_element = element_map.get(name, None)
+ if extra_element is not None:
+ element_list.append(extra_element)
+ document = ar_document.Document(schema_version=schema_version)
+ new_package = document.make_packages(str(package.ref()))
+ for element in sorted(element_list, key=lambda x: x.name):
+ new_package.append(element)
+ if self.document_root is not None:
+ file_path = os.path.join(self.document_root, document_name)
+ else:
+ file_path = document_name
+ writer.write_file(document, file_path)
+
def _create_namespace_from_config(self, name: str, config: dict):
base_ref = None
package_map = {}
diff --git a/src/autosar/xml/writer.py b/src/autosar/xml/writer.py
index 626d1f1..b9294c1 100644
--- a/src/autosar/xml/writer.py
+++ b/src/autosar/xml/writer.py
@@ -3459,7 +3459,9 @@ def _write_atomic_sw_component_type(self, elem: ar_element.AtomicSoftwareCompone
Writes AR:ATOMIC-SW-COMPONENT-TYPE
"""
if elem.internal_behavior is not None:
+ self._add_child("INTERNAL-BEHAVIORS")
self._write_swc_internal_behavior(elem.internal_behavior)
+ self._leave_child()
if elem.symbol_props is not None:
self._write_symbol_props(elem.symbol_props, "SYMBOL-PROPS")
diff --git a/tests/xml/test_software_component_elements.py b/tests/xml/test_software_component_elements.py
index 0c219fd..92b3a17 100644
--- a/tests/xml/test_software_component_elements.py
+++ b/tests/xml/test_software_component_elements.py
@@ -1341,9 +1341,11 @@ def test_internal_behavior(self):
writer = autosar.xml.Writer()
xml = '''
ShortName
-
- BehaviorName
-
+
+
+ BehaviorName
+
+
'''
self.assertEqual(writer.write_str_elem(element), xml)
reader = autosar.xml.Reader()