From 65ca5abfd7da0d3d1f28dc16be6fe36b50e8c83a Mon Sep 17 00:00:00 2001 From: huyenngn Date: Wed, 16 Oct 2024 10:55:32 +0200 Subject: [PATCH] fix: Fix class properties with primitive types --- capella_ros_tools/importer.py | 77 +-- tests/data/data_model/example_msgs.yaml | 809 ++++++++++++------------ tests/test_import_msgs.py | 4 +- 3 files changed, 446 insertions(+), 444 deletions(-) diff --git a/capella_ros_tools/importer.py b/capella_ros_tools/importer.py index 0a74b94..29e5509 100644 --- a/capella_ros_tools/importer.py +++ b/capella_ros_tools/importer.py @@ -35,6 +35,7 @@ def __init__( self.messages = data_model.MessagePkgDef("root", [], []) self._promise_ids: dict[str, None] = {} self._promise_id_refs: dict[str, None] = {} + self._needed_associations: dict[str, str] = {} self._license_header = None if license_header_path is not None: self._license_header = license_header_path.read_text("utf-8") @@ -88,15 +89,11 @@ def _convert_package( classes = [] enums = [] packages = [] - associations = [] for msg_def in pkg_def.messages: if msg_def.fields: - cls_yml, cls_associations = self._convert_class( - pkg_def.name, msg_def - ) + cls_yml = self._convert_class(pkg_def.name, msg_def) classes.append(cls_yml) - associations.extend(cls_associations) for enum_def in msg_def.enums: enums.append(self._convert_enum(msg_def.name, enum_def)) @@ -115,8 +112,6 @@ def _convert_package( sync["enumerations"] = enums if packages: sync["packages"] = packages - if associations: - sync["owned_associations"] = associations yml = {} if sync: @@ -126,11 +121,10 @@ def _convert_package( def _convert_class( self, pkg_name: str, msg_def: data_model.MessageDef - ) -> tuple[dict[str, t.Any], list[dict[str, t.Any]]]: + ) -> dict[str, t.Any]: promise_id = f"{pkg_name}.{msg_def.name}" self._promise_ids[promise_id] = None props = [] - associations = [] for field_def in msg_def.fields: prop_promise_id = f"{promise_id}.{field_def.name}" promise_ref = ( @@ -155,33 +149,7 @@ def _convert_class( }, } props.append(prop_yml) - - associations.append( - { - "find": { - "navigable_members": [decl.Promise(prop_promise_id)], - }, - "sync": { - "members": [ - { - "find": { - "type": decl.Promise(promise_id), - }, - "set": { - "_type": "Property", - "kind": "ASSOCIATION", - "min_card": decl.NewObject( - "LiteralNumericValue", value="1" - ), - "max_card": decl.NewObject( - "LiteralNumericValue", value="1" - ), - }, - } - ], - }, - } - ) + self._needed_associations[prop_promise_id] = promise_id yml = { "promise_id": promise_id, @@ -195,7 +163,7 @@ def _convert_class( "properties": props, }, } - return yml, associations + return yml def _convert_enum( self, pkg_name: str, enum_def: data_model.EnumDef @@ -239,6 +207,7 @@ def to_yaml( ) -> str: """Import ROS messages into a Capella data package.""" logger.info("Generating decl YAML") + instructions = [ {"parent": decl.UUIDReference(helpers.UUIDString(root_uuid))} | self._convert_package(self.messages), @@ -246,6 +215,40 @@ def to_yaml( needed_types = [ p for p in self._promise_id_refs if p not in self._promise_ids ] + + associations = [] + for prop_promise_id, promise_id in self._needed_associations.items(): + if prop_promise_id in needed_types: + continue + associations.append( + { + "find": { + "navigable_members": [decl.Promise(prop_promise_id)], + }, + "sync": { + "members": [ + { + "find": { + "type": decl.Promise(promise_id), + }, + "set": { + "_type": "Property", + "kind": "ASSOCIATION", + "min_card": decl.NewObject( + "LiteralNumericValue", value="1" + ), + "max_card": decl.NewObject( + "LiteralNumericValue", value="1" + ), + }, + } + ], + }, + } + ) + if associations: + instructions[0]["sync"]["owned_associations"] = associations + if not needed_types: return decl.dump(instructions) diff --git a/tests/data/data_model/example_msgs.yaml b/tests/data/data_model/example_msgs.yaml index 304a3cc..df017f6 100644 --- a/tests/data/data_model/example_msgs.yaml +++ b/tests/data/data_model/example_msgs.yaml @@ -3,411 +3,410 @@ - parent: !uuid "00000000-0000-0000-0000-000000000000" sync: - packages: - - find: - name: package1 - sync: - classes: - - promise_id: package1.SampleClass - find: - name: SampleClass - set: - description: "SampleClass.msg The first comment block at the top of the file is added to the class description of SampleClass. " - sync: - properties: - - promise_id: package1.SampleClass.sample_field1 - find: - name: sample_field1 - set: - description: "This block comment is added to the property description of sample_field1. This block comment is also added to the property description of sample_field1. " - type: !promise package1.uint8 - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "0" - max_card: !new_object - _type: LiteralNumericValue - value: "10" - - promise_id: package1.SampleClass.sample_field2 - find: - name: sample_field2 - set: - description: "This block comment is added to the property descriptions of sample_field2 and sample_field3. " - type: !promise package2.SampleClassEnum - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "0" - max_card: !new_object - _type: LiteralNumericValue - value: "*" - - promise_id: package1.SampleClass.sample_field3 - find: - name: sample_field3 - set: - description: "This block comment is added to the property descriptions of sample_field2 and sample_field3. " - type: !promise package1.uint8 - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "3" - max_card: !new_object - _type: LiteralNumericValue - value: "3" - - promise_id: package1.SampleClass.sample_field4 - find: - name: sample_field4 - set: - description: "This block comment is added to the property descriptions of sample_field4 and sample_field5. Fields in SampleClass can reference enums in other files. The property sample_field4 is of type SampleEnum. cf. SampleEnum " - type: !promise SampleEnum.SampleEnum - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - promise_id: package1.SampleClass.sample_field5 - find: - name: sample_field5 - set: - description: "This block comment is added to the property descriptions of sample_field4 and sample_field5. This inline comment is added to the property description of sample_field5. The property sample_field5 is of type SampleEnumValue. cf. SampleEnum, SAMPLE_ENUM_VALUE_XXX " - type: !promise SampleEnum.SampleEnumValue - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - enumerations: - - promise_id: SampleEnum.SampleEnumValue - find: - name: SampleEnumValue - set: - description: "SampleEnum.msg This block comment is added to the enum description of SampleEnumValue. " - sync: - literals: - - find: - name: RED - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "0" - - find: - name: BLUE - set: - description: "This inline comment is added to the enum literal description of BLUE. " - value: !new_object - _type: LiteralNumericValue - value: "1" - - find: - name: YELLOW - set: - description: "This block comment is added to the enum literal descriptions of YELLOW and GREEN. " - value: !new_object - _type: LiteralNumericValue - value: "2" - - find: - name: GREEN - set: - description: "This block comment is added to the enum literal descriptions of YELLOW and GREEN. " - value: !new_object - _type: LiteralNumericValue - value: "3" - - promise_id: SampleEnum.SampleEnum - find: - name: SampleEnum - set: - description: "This block comment is added to the enum description of SampleEnum. In a file, there can only be one or no enum whose literal names do not share a common prefix. " - sync: - literals: - - find: - name: OK - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "0" - - find: - name: WARN - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "1" - - find: - name: ERROR - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "2" - - find: - name: STALE - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "3" - owned_associations: - - find: - navigable_members: - - !promise package1.SampleClass.sample_field1 - sync: - members: - - find: - type: !promise package1.SampleClass - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - navigable_members: - - !promise package1.SampleClass.sample_field2 - sync: - members: - - find: - type: !promise package1.SampleClass - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - navigable_members: - - !promise package1.SampleClass.sample_field3 - sync: - members: - - find: - type: !promise package1.SampleClass - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - navigable_members: - - !promise package1.SampleClass.sample_field4 - sync: - members: - - find: - type: !promise package1.SampleClass - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - navigable_members: - - !promise package1.SampleClass.sample_field5 - sync: - members: - - find: - type: !promise package1.SampleClass - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - name: package2 - sync: - classes: - - promise_id: package2.SampleClassEnum - find: - name: SampleClassEnum - set: - description: "SampleClassEnum.msg Properties in SampleClassEnum can reference enums in the same file. " - sync: - properties: - - promise_id: package2.SampleClassEnum.status - find: - name: status - set: - description: "The property status is of type SampleClassEnumStatus. " - type: !promise SampleClassEnum.SampleClassEnumStatus - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - promise_id: package2.SampleClassEnum.color - find: - name: color - set: - description: "The property color is of type Color. " - type: !promise SampleClassEnum.Color - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - promise_id: package2.SampleClassEnum.field - find: - name: field - set: - description: "" - type: !promise package2.uint8 - kind: COMPOSITION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - enumerations: - - promise_id: SampleClassEnum.SampleClassEnumStatus - find: - name: SampleClassEnumStatus - set: - description: "This block comment is added to the enum description of SampleClassEnumStatus. " - sync: - literals: - - find: - name: OK - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "0" - - find: - name: WARN - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "1" - - find: - name: ERROR - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "2" - - find: - name: STALE - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "3" - - promise_id: SampleClassEnum.Color - find: - name: Color - set: - description: "This block comment is added to the enum description of Color. " - sync: - literals: - - find: - name: RED - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "0" - - find: - name: BLUE - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "1" - - find: - name: YELLOW - set: - description: "" - value: !new_object - _type: LiteralNumericValue - value: "2" - owned_associations: - - find: - navigable_members: - - !promise package2.SampleClassEnum.status - sync: - members: - - find: - type: !promise package2.SampleClassEnum - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - navigable_members: - - !promise package2.SampleClassEnum.color - sync: - members: - - find: - type: !promise package2.SampleClassEnum - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" - - find: - navigable_members: - - !promise package2.SampleClassEnum.field - sync: - members: - - find: - type: !promise package2.SampleClassEnum - set: - _type: Property - kind: ASSOCIATION - min_card: !new_object - _type: LiteralNumericValue - value: "1" - max_card: !new_object - _type: LiteralNumericValue - value: "1" + owned_associations: + - find: + navigable_members: + - !promise package1.SampleClass.sample_field1 + sync: + members: + - find: + type: !promise package1.SampleClass + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package1.SampleClass.sample_field2 + sync: + members: + - find: + type: !promise package1.SampleClass + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package1.SampleClass.sample_field3 + sync: + members: + - find: + type: !promise package1.SampleClass + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package1.SampleClass.sample_field4 + sync: + members: + - find: + type: !promise package1.SampleClass + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package1.SampleClass.sample_field5 + sync: + members: + - find: + type: !promise package1.SampleClass + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package2.SampleClassEnum.status + sync: + members: + - find: + type: !promise package2.SampleClassEnum + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package2.SampleClassEnum.color + sync: + members: + - find: + type: !promise package2.SampleClassEnum + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - find: + navigable_members: + - !promise package2.SampleClassEnum.field + sync: + members: + - find: + type: !promise package2.SampleClassEnum + set: + _type: Property + kind: ASSOCIATION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + packages: + - find: + name: package1 + sync: + classes: + - promise_id: package1.SampleClass + find: + name: SampleClass + set: + description: "SampleClass.msg The first comment block at the top of the file is added to the class description of SampleClass. " + sync: + properties: + - promise_id: package1.SampleClass.sample_field1 + find: + name: sample_field1 + set: + description: "This block comment is added to the property description of sample_field1. This block comment is also added to the property description of sample_field1. " + type: !promise package1.uint8 + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "0" + max_card: !new_object + _type: LiteralNumericValue + value: "10" + - promise_id: package1.SampleClass.sample_field2 + find: + name: sample_field2 + set: + description: "This block comment is added to the property descriptions of sample_field2 and sample_field3. " + type: !promise package2.SampleClassEnum + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "0" + max_card: !new_object + _type: LiteralNumericValue + value: "*" + - promise_id: package1.SampleClass.sample_field3 + find: + name: sample_field3 + set: + description: "This block comment is added to the property descriptions of sample_field2 and sample_field3. " + type: !promise package1.uint8 + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "3" + max_card: !new_object + _type: LiteralNumericValue + value: "3" + - promise_id: package1.SampleClass.sample_field4 + find: + name: sample_field4 + set: + description: "This block comment is added to the property descriptions of sample_field4 and sample_field5. Fields in SampleClass can reference enums in other files. The property sample_field4 is of type SampleEnum. cf. SampleEnum " + type: !promise SampleEnum.SampleEnum + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - promise_id: package1.SampleClass.sample_field5 + find: + name: sample_field5 + set: + description: "This block comment is added to the property descriptions of sample_field4 and sample_field5. This inline comment is added to the property description of sample_field5. The property sample_field5 is of type SampleEnumValue. cf. SampleEnum, SAMPLE_ENUM_VALUE_XXX " + type: !promise SampleEnum.SampleEnumValue + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + enumerations: + - promise_id: SampleEnum.SampleEnumValue + find: + name: SampleEnumValue + set: + description: "SampleEnum.msg This block comment is added to the enum description of SampleEnumValue. " + sync: + literals: + - find: + name: RED + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "0" + - find: + name: BLUE + set: + description: "This inline comment is added to the enum literal description of BLUE. " + value: !new_object + _type: LiteralNumericValue + value: "1" + - find: + name: YELLOW + set: + description: "This block comment is added to the enum literal descriptions of YELLOW and GREEN. " + value: !new_object + _type: LiteralNumericValue + value: "2" + - find: + name: GREEN + set: + description: "This block comment is added to the enum literal descriptions of YELLOW and GREEN. " + value: !new_object + _type: LiteralNumericValue + value: "3" + - promise_id: SampleEnum.SampleEnum + find: + name: SampleEnum + set: + description: "This block comment is added to the enum description of SampleEnum. In a file, there can only be one or no enum whose literal names do not share a common prefix. " + sync: + literals: + - find: + name: OK + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "0" + - find: + name: WARN + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "1" + - find: + name: ERROR + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "2" + - find: + name: STALE + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "3" + - find: + name: package2 + sync: + classes: + - promise_id: package2.SampleClassEnum + find: + name: SampleClassEnum + set: + description: "SampleClassEnum.msg Properties in SampleClassEnum can reference enums in the same file. " + sync: + properties: + - promise_id: package2.SampleClassEnum.status + find: + name: status + set: + description: "The property status is of type SampleClassEnumStatus. " + type: !promise SampleClassEnum.SampleClassEnumStatus + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - promise_id: package2.SampleClassEnum.color + find: + name: color + set: + description: "The property color is of type Color. " + type: !promise SampleClassEnum.Color + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + - promise_id: package2.SampleClassEnum.field + find: + name: field + set: + description: "" + type: !promise package2.uint8 + kind: COMPOSITION + min_card: !new_object + _type: LiteralNumericValue + value: "1" + max_card: !new_object + _type: LiteralNumericValue + value: "1" + enumerations: + - promise_id: SampleClassEnum.SampleClassEnumStatus + find: + name: SampleClassEnumStatus + set: + description: "This block comment is added to the enum description of SampleClassEnumStatus. " + sync: + literals: + - find: + name: OK + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "0" + - find: + name: WARN + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "1" + - find: + name: ERROR + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "2" + - find: + name: STALE + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "3" + - promise_id: SampleClassEnum.Color + find: + name: Color + set: + description: "This block comment is added to the enum description of Color. " + sync: + literals: + - find: + name: RED + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "0" + - find: + name: BLUE + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "1" + - find: + name: YELLOW + set: + description: "" + value: !new_object + _type: LiteralNumericValue + value: "2" - parent: !uuid "00000000-0000-0000-0000-000000000001" sync: - packages: - - find: - name: "Data Types" - sync: - datatypes: - - promise_id: package1.uint8 - find: - name: uint8 - _type: NumericType - - promise_id: package2.uint8 - find: - name: uint8 - _type: NumericType + packages: + - find: + name: "Data Types" + sync: + datatypes: + - promise_id: package1.uint8 + find: + name: uint8 + _type: NumericType + - promise_id: package2.uint8 + find: + name: uint8 + _type: NumericType diff --git a/tests/test_import_msgs.py b/tests/test_import_msgs.py index d8e807c..be5548f 100644 --- a/tests/test_import_msgs.py +++ b/tests/test_import_msgs.py @@ -172,7 +172,7 @@ def test_convert_class(importer: Importer): }, } - actual, _ = importer._convert_class("my_package", class_def) + actual = importer._convert_class("my_package", class_def) assert decl.dump([actual]) == decl.dump([expected]) assert "my_package.MyMessage" in importer._promise_ids @@ -224,7 +224,7 @@ def test_convert_class_with_ref(importer: Importer): }, } - actual, _ = importer._convert_class(pkg_name, msg_def) + actual = importer._convert_class(pkg_name, msg_def) assert decl.dump([actual]) == decl.dump([expected]) assert "my_package.MyMessage" in importer._promise_ids