From 31edac7eb9eeb4af1ffd99bd30bd9df8cd482e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Mon, 10 Mar 2025 15:42:53 +0100 Subject: [PATCH 1/7] move generation of _choice suffix trying to generate polymorphic protobuf messages leads to the necessary generation of choice messages. naming them is now moved to the naming.py utilities --- aas_core_codegen/protobuf/common.py | 21 +++++++++----- aas_core_codegen/protobuf/description.py | 4 +-- aas_core_codegen/protobuf/main.py | 6 ++-- aas_core_codegen/protobuf/naming.py | 9 ++---- .../protobuf/structure/_generate.py | 29 ++++++++++++------- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/aas_core_codegen/protobuf/common.py b/aas_core_codegen/protobuf/common.py index 0649218c..4afdeeef 100644 --- a/aas_core_codegen/protobuf/common.py +++ b/aas_core_codegen/protobuf/common.py @@ -138,32 +138,37 @@ def generate_type(type_annotation: intermediate.TypeAnnotationUnion) -> Stripped return PRIMITIVE_TYPE_MAP[our_type.constrainee] elif isinstance(our_type, intermediate.Class): + message_name = proto_naming.class_name(our_type.name) + if len(our_type.concrete_descendants) > 0: # NOTE (TomGneuss): - # We add the suffix "_choice" to the type name because this type - # (either abstract or concrete) has concrete subtypes. - # Thus, a choice-object (with that suffix) will be generated and must - # be used here. - message_name = Identifier(message_name + "_choice") + # If the current type is either interface, abstract, or concrete class + # and has concrete descendants, it must have the name of a + # choice-message to simulate polymorphism + message_name = proto_naming.interface_name(our_type.name) return Stripped(message_name) elif isinstance(type_annotation, intermediate.ListTypeAnnotation): item_type = generate_type(type_annotation=type_annotation.items) + # NOTE (TomGneuss): + # Careful: This does not yet cover the hypothetical scenario where + # type_annotation.items is of type intermediate.OptionalTypeAnnotation. + # As below, constructs like "repeated optional " are invalid. return Stripped(f"repeated {item_type}") elif isinstance(type_annotation, intermediate.OptionalTypeAnnotation): - value = generate_type(type_annotation=type_annotation.value) + value_name = generate_type(type_annotation=type_annotation.value) # NOTE (TomGneuss): # Careful: do not generate "optional" keyword for list-type elements since # otherwise we get invalid constructs like "optional repeated ". if isinstance(type_annotation.value, intermediate.ListTypeAnnotation): - return Stripped(f"{value}") + return Stripped(f"{value_name}") else: - return Stripped(f"optional {value}") + return Stripped(f"optional {value_name}") else: assert_never(type_annotation) diff --git a/aas_core_codegen/protobuf/description.py b/aas_core_codegen/protobuf/description.py index 1f2e039f..c9256a24 100644 --- a/aas_core_codegen/protobuf/description.py +++ b/aas_core_codegen/protobuf/description.py @@ -180,7 +180,7 @@ def transform_reference_to_our_type_in_doc( # NOTE (mristin, 2021-12-25): # We do not generate ProtoBuf code for abstract classes, so we have to refer # to the interface. - name = proto_naming.class_name(element.our_type.name) + name = proto_naming.interface_name(element.our_type.name) elif isinstance(element.our_type, intermediate.ConcreteClass): # NOTE (mristin, 2021-12-25): @@ -227,7 +227,7 @@ def transform_reference_to_attribute_in_doc( if isinstance(element.reference.cls, intermediate.AbstractClass): # We do not generate ProtoBuf code for abstract classes, so we have to refer # to the interface. - name_of_our_type = proto_naming.class_name(element.reference.cls.name) + name_of_our_type = proto_naming.interface_name(element.reference.cls.name) elif isinstance(element.reference.cls, intermediate.ConcreteClass): # NOTE (mristin, 2021-12-25): # Though a concrete class can have multiple descendants and the writer diff --git a/aas_core_codegen/protobuf/main.py b/aas_core_codegen/protobuf/main.py index 298f379b..b4a38ff0 100644 --- a/aas_core_codegen/protobuf/main.py +++ b/aas_core_codegen/protobuf/main.py @@ -66,16 +66,16 @@ def execute(context: run.Context, stdout: TextIO, stderr: TextIO) -> int: ) return 1 - namespace_key = specific_implementations.ImplementationKey("namespace.txt") + namespace_key = specific_implementations.ImplementationKey("package.txt") namespace_text = context.spec_impls.get(namespace_key, None) if namespace_text is None: - stderr.write(f"The namespace snippet is missing: {namespace_key}\n") + stderr.write(f"The package snippet is missing: {namespace_key}\n") return 1 if not proto_common.NAMESPACE_IDENTIFIER_RE.fullmatch(namespace_text): stderr.write( f"The text from the snippet {namespace_key} " - f"is not a valid namespace identifier: {namespace_text!r}\n" + f"is not a valid package identifier: {namespace_text!r}\n" ) return 1 diff --git a/aas_core_codegen/protobuf/naming.py b/aas_core_codegen/protobuf/naming.py index d0761b50..189e2578 100644 --- a/aas_core_codegen/protobuf/naming.py +++ b/aas_core_codegen/protobuf/naming.py @@ -13,9 +13,10 @@ def interface_name(identifier: Identifier) -> Identifier: """ Generate a ProtoBuf name for an interface based on its meta-model ``identifier``. - This method is not to be used because proto3 does not support interfaces. + Since proto3 does not directly support interfaces, but only one-of messages + (commonly suffixed "_choice"), these names are generated here. """ - raise NotImplementedError("Interfaces are not supported by proto3.") + return aas_core_codegen.naming.capitalized_camel_case(identifier) + "_choice" def enum_name(identifier: Identifier) -> Identifier: @@ -44,10 +45,6 @@ def enum_literal_name(identifier: Identifier) -> Identifier: return aas_core_codegen.naming.upper_snake_case(identifier) -@ensure( - lambda result: "_" not in result, - "No underscode allowed so that we can attached our own suffixes such as ``_choice``", -) def class_name(identifier: Identifier) -> Identifier: """ Generate a ProtoBuf name for a class based on its meta-model ``identifier``. diff --git a/aas_core_codegen/protobuf/structure/_generate.py b/aas_core_codegen/protobuf/structure/_generate.py index 0315da8a..645101b3 100644 --- a/aas_core_codegen/protobuf/structure/_generate.py +++ b/aas_core_codegen/protobuf/structure/_generate.py @@ -244,7 +244,7 @@ def _generate_enum( # write enum and its name writer.write(f"enum {name} {{\n") - # write at least the unspecified enum entry + # write at least the default enum literal writer.write(textwrap.indent(f"{proto_naming.enum_name(name)}_UNSPECIFIED = 0;", I)) if len(enum.literals) == 0: @@ -275,13 +275,16 @@ def _generate_enum( writer.write(textwrap.indent(literal_comment, I)) writer.write("\n") - # Enums cannot have string-values assigned to them in proto3. Instead, they each get assigned - # an ID that is used for (de-)serialization. - # If that ID is re-assigned to another literal in the same enum in a later version, a system using the - # old version will (de-)serialize that literal differently. Hence, hope that the order of writing the literals - # stays the same in each build so that one literal always gets the same ID. Otherwise, don't mix versions. - # With each version, compare to the previous one and assign same ID. - # With each version, add a `reserved`-statement for deleted literals and their IDs. + # Note (TomGneuss): + # Enums cannot have string-values assigned to them in proto3. Instead, they + # each get an ID assigned that is used for (de-)serialization. If that ID is + # re-assigned to another literal in the same enum in a later version, a system + # using the old version will (de-)serialize that literal differently. + # Hence, hope that the order of writing the literals stays the same in each + # build so that existing literals always get the same ID (backward compatible). + # Otherwise, don't mix versions. Ideally, with each version, compare to the + # previous one and assign the same ID. With every new version, add a + # `reserved`-statement for deleted literals and their IDs. writer.write( textwrap.indent( f"""\ @@ -383,6 +386,10 @@ def _generate_choice_class(cls: intermediate.ClassUnion) -> Stripped: concrete_classes = [] if isinstance(cls, intermediate.ConcreteClass): + # NOTE (TomGneuss): + # The type cls has concrete descendants but is itself concrete, so it must + # be listed as one of its own subtypes in the choice message because that + # is how proto3 tries to model polymorphism concrete_classes.append(cls) concrete_classes.extend(cls.concrete_descendants) @@ -392,7 +399,7 @@ def _generate_choice_class(cls: intermediate.ClassUnion) -> Stripped: subtype_name = proto_naming.property_name(subtype.name) fields.append(Stripped(f"{subtype_type} {subtype_name} = {j + 1};")) - message_name = Identifier(proto_naming.class_name(cls.name) + "_choice") + message_name = Identifier(proto_naming.interface_name(cls.name)) fields_joined = "\n".join(fields) @@ -425,6 +432,7 @@ def generate( errors = [] # type: List[Error] + # generate message definitions for concrete classes and enums first for our_type in symbol_table.our_types: if not isinstance( our_type, @@ -467,6 +475,8 @@ def generate( else: assert_never(our_type) + # generate choice messages for all interfaces and abstract or concrete classes + # that have concrete descendants for cls in symbol_table.classes: if len(cls.concrete_descendants) > 0: code_blocks.append(_generate_choice_class(cls)) @@ -484,7 +494,6 @@ def generate( package {namespace}; - {code_blocks_joined}""" ), proto_common.WARNING, From 103c6a156f3573d5c8257911b58f2c0c68e9bf54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Tue, 11 Mar 2025 07:53:03 +0100 Subject: [PATCH 2/7] move test cases for protobuf the directory structure for the protobuf generator test cases is now aligned with the other generators --- .../expected_output/stdout.txt | 0 .../expected_output/types.proto | 158 +++++++++--------- .../input/snippets/package.txt | 1 + .../expected_output/stdout.txt | 0 .../expected_output/types.proto | 0 .../input/snippets/package.txt} | 0 .../meta_model.py | 0 .../expected_output/stdout.txt | 0 .../expected_output/types.proto | 0 .../input/snippets/package.txt} | 0 .../meta_model.py | 0 .../expected_output/stdout.txt | 0 .../expected_output/types.proto | 0 .../input/snippets/package.txt} | 0 .../concrete_class_with_enum/meta_model.py | 0 .../expected_output/stdout.txt | 0 .../expected_output/types.proto | 0 .../input/snippets/package.txt} | 0 .../meta_model.py | 0 .../expected_output/stdout.txt | 0 .../expected_output/types.proto | 0 .../input/snippets/package.txt} | 0 .../meta_model.py | 0 .../input/snippets/namespace.txt | 1 - 24 files changed, 80 insertions(+), 80 deletions(-) rename test_data/proto/test_main/{expected => }/aas_core_meta.v3/expected_output/stdout.txt (100%) rename test_data/proto/test_main/{expected => }/aas_core_meta.v3/expected_output/types.proto (94%) create mode 100644 test_data/proto/test_main/aas_core_meta.v3/input/snippets/package.txt rename test_data/proto/test_main/{expected => }/abstract_and_concrete_classes/expected_output/stdout.txt (100%) rename test_data/proto/test_main/{expected => }/abstract_and_concrete_classes/expected_output/types.proto (100%) rename test_data/proto/test_main/{expected/abstract_and_concrete_classes/input/snippets/namespace.txt => abstract_and_concrete_classes/input/snippets/package.txt} (100%) rename test_data/proto/test_main/{expected => }/abstract_and_concrete_classes/meta_model.py (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_descendants/expected_output/stdout.txt (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_descendants/expected_output/types.proto (100%) rename test_data/proto/test_main/{expected/concrete_class_with_descendants/input/snippets/namespace.txt => concrete_class_with_descendants/input/snippets/package.txt} (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_descendants/meta_model.py (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_enum/expected_output/stdout.txt (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_enum/expected_output/types.proto (100%) rename test_data/proto/test_main/{expected/concrete_class_with_enum/input/snippets/namespace.txt => concrete_class_with_enum/input/snippets/package.txt} (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_enum/meta_model.py (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_list_of_instances/expected_output/stdout.txt (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_list_of_instances/expected_output/types.proto (100%) rename test_data/proto/test_main/{expected/concrete_class_with_list_of_instances/input/snippets/namespace.txt => concrete_class_with_list_of_instances/input/snippets/package.txt} (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_list_of_instances/meta_model.py (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_primitive_attributes/expected_output/stdout.txt (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_primitive_attributes/expected_output/types.proto (100%) rename test_data/proto/test_main/{expected/concrete_class_with_primitive_attributes/input/snippets/namespace.txt => concrete_class_with_primitive_attributes/input/snippets/package.txt} (100%) rename test_data/proto/test_main/{expected => }/concrete_class_with_primitive_attributes/meta_model.py (100%) delete mode 100644 test_data/proto/test_main/expected/aas_core_meta.v3/input/snippets/namespace.txt diff --git a/test_data/proto/test_main/expected/aas_core_meta.v3/expected_output/stdout.txt b/test_data/proto/test_main/aas_core_meta.v3/expected_output/stdout.txt similarity index 100% rename from test_data/proto/test_main/expected/aas_core_meta.v3/expected_output/stdout.txt rename to test_data/proto/test_main/aas_core_meta.v3/expected_output/stdout.txt diff --git a/test_data/proto/test_main/expected/aas_core_meta.v3/expected_output/types.proto b/test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto similarity index 94% rename from test_data/proto/test_main/expected/aas_core_meta.v3/expected_output/types.proto rename to test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto index 9fa643db..6a20f479 100644 --- a/test_data/proto/test_main/expected/aas_core_meta.v3/expected_output/types.proto +++ b/test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto @@ -5,7 +5,7 @@ syntax = "proto3"; -package aas_core3; +package aas_core.aas3_0; /// @@ -40,7 +40,7 @@ message Extension { ///
    ///
  • /// Constraint AASd-077: - /// The name of an extension (Extension/name) within needs + /// The name of an extension (Extension/name) within needs /// to be unique. ///
  • ///
@@ -164,7 +164,7 @@ enum QualifierKind { /// /// qualifies the semantic definition the element is referring to - /// () + /// () /// Qualifierkind_CONCEPT_QUALIFIER = 2; @@ -271,7 +271,7 @@ message AssetAdministrationShell { ///
/// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -284,8 +284,8 @@ message AssetAdministrationShell { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -585,7 +585,7 @@ message Submodel { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -598,8 +598,8 @@ message Submodel { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -714,7 +714,7 @@ message RelationshipElement { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -727,8 +727,8 @@ message RelationshipElement { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -863,23 +863,23 @@ enum AasSubmodelElements { ///
  • /// Constraint AASd-107: /// If a first level child element in a has -/// a it +/// a it /// shall be identical to . ///
  • ///
  • /// Constraint AASd-114: /// If two first level child elements in a have -/// a then they shall be identical. +/// a then they shall be identical. ///
  • ///
  • /// Constraint AASd-115: /// If a first level child element in a does not -/// specify a then the value is assumed to be +/// specify a then the value is assumed to be /// identical to . ///
  • ///
  • /// Constraint AASd-120: -/// The of a being a direct child of a +/// The of a being a direct child of a /// shall not be specified. ///
  • ///
  • @@ -912,7 +912,7 @@ message SubmodelElementList { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -925,8 +925,8 @@ message SubmodelElementList { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1049,7 +1049,7 @@ message SubmodelElementCollection { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1062,8 +1062,8 @@ message SubmodelElementCollection { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1168,7 +1168,7 @@ message Property { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1181,8 +1181,8 @@ message Property { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1300,7 +1300,7 @@ message MultiLanguageProperty { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1313,8 +1313,8 @@ message MultiLanguageProperty { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1414,7 +1414,7 @@ message Range { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1427,8 +1427,8 @@ message Range { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1538,7 +1538,7 @@ message ReferenceElement { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1551,8 +1551,8 @@ message ReferenceElement { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1647,7 +1647,7 @@ message Blob { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1660,8 +1660,8 @@ message Blob { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1777,7 +1777,7 @@ message File { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1790,8 +1790,8 @@ message File { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -1895,7 +1895,7 @@ message AnnotatedRelationshipElement { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -1908,8 +1908,8 @@ message AnnotatedRelationshipElement { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -2025,7 +2025,7 @@ message Entity { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -2038,8 +2038,8 @@ message Entity { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -2210,12 +2210,12 @@ message EventPayload { /// /// Reference to the source event element, including identification of /// , , - /// 's. + /// 's. /// Reference source = 1; /// - /// of the source event element, if available + /// of the source event element, if available /// /// /// It is recommended to use a global reference. @@ -2227,12 +2227,12 @@ message EventPayload { /// /// /// Can be , or - /// . + /// . /// Reference observable_reference = 3; /// - /// of the referable which defines the scope of + /// of the referable which defines the scope of /// the event, if available. /// /// @@ -2286,7 +2286,7 @@ message BasicEventElement { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -2299,8 +2299,8 @@ message BasicEventElement { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -2370,9 +2370,9 @@ message BasicEventElement { repeated EmbeddedDataSpecification embedded_data_specifications = 9; /// - /// Reference to the , which defines the scope of the event. + /// Reference to the , which defines the scope of the event. /// Can be , , or - /// . + /// . /// /// /// Reference to a referable, e.g., a data element or @@ -2404,9 +2404,9 @@ message BasicEventElement { /// /// Information, which outer message infrastructure shall handle messages for - /// the . Refers to a , + /// the . Refers to a , /// , or - /// , which contains 's describing + /// , which contains 's describing /// the proprietary specification for the message broker. /// /// @@ -2462,7 +2462,7 @@ message BasicEventElement { ///
      ///
    • /// Constraint AASd-134: -/// For an the of all +/// For an the of all /// 's in /// , /// and shall be unique. @@ -2483,7 +2483,7 @@ message Operation { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -2496,8 +2496,8 @@ message Operation { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -2615,7 +2615,7 @@ message Capability { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -2628,8 +2628,8 @@ message Capability { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -2802,7 +2802,7 @@ message ConceptDescription { /// /// /// The category is not identical to the semantic definition - /// () of an element. The category e.g. could denote that + /// () of an element. The category e.g. could denote that /// the element is a measurement value whereas the semantic definition of /// the element would denote that it is the measured temperature. /// @@ -2815,8 +2815,8 @@ message ConceptDescription { /// /// /// In case the element is a property and the property has a semantic definition - /// () conformant to IEC61360 - /// the is typically identical to the short name in English. + /// () conformant to IEC61360 + /// the is typically identical to the short name in English. /// optional string id_short = 3; @@ -3002,7 +3002,7 @@ message Reference { ReferenceTypes type = 1; /// - /// of the referenced model element + /// of the referenced model element /// ( = ). /// /// @@ -3084,7 +3084,7 @@ enum KeyTypes { /// Event. /// /// - /// is abstract. + /// is abstract. /// Keytypes_EVENT_ELEMENT = 9; @@ -3232,7 +3232,7 @@ message LangStringNameType { string language = 1; /// - /// Text in the + /// Text in the /// string text = 2; } @@ -3247,7 +3247,7 @@ message LangStringTextType { string language = 1; /// - /// Text in the + /// Text in the /// string text = 2; } @@ -3282,14 +3282,14 @@ message Environment { /// message EmbeddedDataSpecification { /// - /// Reference to the data specification + /// Actual content of the data specification /// - Reference data_specification = 1; + DataSpecificationContent_choice data_specification_content = 1; /// - /// Actual content of the data specification + /// Reference to the data specification /// - DataSpecificationContent_choice data_specification_content = 2; + Reference data_specification = 2; } enum DataTypeIec61360 { @@ -3559,7 +3559,7 @@ message LangStringPreferredNameTypeIec61360 { string language = 1; /// - /// Text in the + /// Text in the /// string text = 2; } @@ -3574,7 +3574,7 @@ message LangStringShortNameTypeIec61360 { string language = 1; /// - /// Text in the + /// Text in the /// string text = 2; } @@ -3589,7 +3589,7 @@ message LangStringDefinitionTypeIec61360 { string language = 1; /// - /// Text in the + /// Text in the /// string text = 2; } @@ -3603,7 +3603,7 @@ message LangStringDefinitionTypeIec61360 { /// IEC61360 requires also a globally unique identifier for a concept /// description. This ID is not part of the data specification template. /// Instead the as inherited via -/// is used. Same holds for administrative +/// is used. Same holds for administrative /// information like the version and revision. /// /// diff --git a/test_data/proto/test_main/aas_core_meta.v3/input/snippets/package.txt b/test_data/proto/test_main/aas_core_meta.v3/input/snippets/package.txt new file mode 100644 index 00000000..f448a2d7 --- /dev/null +++ b/test_data/proto/test_main/aas_core_meta.v3/input/snippets/package.txt @@ -0,0 +1 @@ +aas_core.aas3_0 diff --git a/test_data/proto/test_main/expected/abstract_and_concrete_classes/expected_output/stdout.txt b/test_data/proto/test_main/abstract_and_concrete_classes/expected_output/stdout.txt similarity index 100% rename from test_data/proto/test_main/expected/abstract_and_concrete_classes/expected_output/stdout.txt rename to test_data/proto/test_main/abstract_and_concrete_classes/expected_output/stdout.txt diff --git a/test_data/proto/test_main/expected/abstract_and_concrete_classes/expected_output/types.proto b/test_data/proto/test_main/abstract_and_concrete_classes/expected_output/types.proto similarity index 100% rename from test_data/proto/test_main/expected/abstract_and_concrete_classes/expected_output/types.proto rename to test_data/proto/test_main/abstract_and_concrete_classes/expected_output/types.proto diff --git a/test_data/proto/test_main/expected/abstract_and_concrete_classes/input/snippets/namespace.txt b/test_data/proto/test_main/abstract_and_concrete_classes/input/snippets/package.txt similarity index 100% rename from test_data/proto/test_main/expected/abstract_and_concrete_classes/input/snippets/namespace.txt rename to test_data/proto/test_main/abstract_and_concrete_classes/input/snippets/package.txt diff --git a/test_data/proto/test_main/expected/abstract_and_concrete_classes/meta_model.py b/test_data/proto/test_main/abstract_and_concrete_classes/meta_model.py similarity index 100% rename from test_data/proto/test_main/expected/abstract_and_concrete_classes/meta_model.py rename to test_data/proto/test_main/abstract_and_concrete_classes/meta_model.py diff --git a/test_data/proto/test_main/expected/concrete_class_with_descendants/expected_output/stdout.txt b/test_data/proto/test_main/concrete_class_with_descendants/expected_output/stdout.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_descendants/expected_output/stdout.txt rename to test_data/proto/test_main/concrete_class_with_descendants/expected_output/stdout.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_descendants/expected_output/types.proto b/test_data/proto/test_main/concrete_class_with_descendants/expected_output/types.proto similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_descendants/expected_output/types.proto rename to test_data/proto/test_main/concrete_class_with_descendants/expected_output/types.proto diff --git a/test_data/proto/test_main/expected/concrete_class_with_descendants/input/snippets/namespace.txt b/test_data/proto/test_main/concrete_class_with_descendants/input/snippets/package.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_descendants/input/snippets/namespace.txt rename to test_data/proto/test_main/concrete_class_with_descendants/input/snippets/package.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_descendants/meta_model.py b/test_data/proto/test_main/concrete_class_with_descendants/meta_model.py similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_descendants/meta_model.py rename to test_data/proto/test_main/concrete_class_with_descendants/meta_model.py diff --git a/test_data/proto/test_main/expected/concrete_class_with_enum/expected_output/stdout.txt b/test_data/proto/test_main/concrete_class_with_enum/expected_output/stdout.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_enum/expected_output/stdout.txt rename to test_data/proto/test_main/concrete_class_with_enum/expected_output/stdout.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_enum/expected_output/types.proto b/test_data/proto/test_main/concrete_class_with_enum/expected_output/types.proto similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_enum/expected_output/types.proto rename to test_data/proto/test_main/concrete_class_with_enum/expected_output/types.proto diff --git a/test_data/proto/test_main/expected/concrete_class_with_enum/input/snippets/namespace.txt b/test_data/proto/test_main/concrete_class_with_enum/input/snippets/package.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_enum/input/snippets/namespace.txt rename to test_data/proto/test_main/concrete_class_with_enum/input/snippets/package.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_enum/meta_model.py b/test_data/proto/test_main/concrete_class_with_enum/meta_model.py similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_enum/meta_model.py rename to test_data/proto/test_main/concrete_class_with_enum/meta_model.py diff --git a/test_data/proto/test_main/expected/concrete_class_with_list_of_instances/expected_output/stdout.txt b/test_data/proto/test_main/concrete_class_with_list_of_instances/expected_output/stdout.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_list_of_instances/expected_output/stdout.txt rename to test_data/proto/test_main/concrete_class_with_list_of_instances/expected_output/stdout.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_list_of_instances/expected_output/types.proto b/test_data/proto/test_main/concrete_class_with_list_of_instances/expected_output/types.proto similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_list_of_instances/expected_output/types.proto rename to test_data/proto/test_main/concrete_class_with_list_of_instances/expected_output/types.proto diff --git a/test_data/proto/test_main/expected/concrete_class_with_list_of_instances/input/snippets/namespace.txt b/test_data/proto/test_main/concrete_class_with_list_of_instances/input/snippets/package.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_list_of_instances/input/snippets/namespace.txt rename to test_data/proto/test_main/concrete_class_with_list_of_instances/input/snippets/package.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_list_of_instances/meta_model.py b/test_data/proto/test_main/concrete_class_with_list_of_instances/meta_model.py similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_list_of_instances/meta_model.py rename to test_data/proto/test_main/concrete_class_with_list_of_instances/meta_model.py diff --git a/test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/expected_output/stdout.txt b/test_data/proto/test_main/concrete_class_with_primitive_attributes/expected_output/stdout.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/expected_output/stdout.txt rename to test_data/proto/test_main/concrete_class_with_primitive_attributes/expected_output/stdout.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/expected_output/types.proto b/test_data/proto/test_main/concrete_class_with_primitive_attributes/expected_output/types.proto similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/expected_output/types.proto rename to test_data/proto/test_main/concrete_class_with_primitive_attributes/expected_output/types.proto diff --git a/test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/input/snippets/namespace.txt b/test_data/proto/test_main/concrete_class_with_primitive_attributes/input/snippets/package.txt similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/input/snippets/namespace.txt rename to test_data/proto/test_main/concrete_class_with_primitive_attributes/input/snippets/package.txt diff --git a/test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/meta_model.py b/test_data/proto/test_main/concrete_class_with_primitive_attributes/meta_model.py similarity index 100% rename from test_data/proto/test_main/expected/concrete_class_with_primitive_attributes/meta_model.py rename to test_data/proto/test_main/concrete_class_with_primitive_attributes/meta_model.py diff --git a/test_data/proto/test_main/expected/aas_core_meta.v3/input/snippets/namespace.txt b/test_data/proto/test_main/expected/aas_core_meta.v3/input/snippets/namespace.txt deleted file mode 100644 index 74a993a9..00000000 --- a/test_data/proto/test_main/expected/aas_core_meta.v3/input/snippets/namespace.txt +++ /dev/null @@ -1 +0,0 @@ -aas_core3 \ No newline at end of file From b378f29b1623cedd37b44a744d0651f9c18dee20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Tue, 11 Mar 2025 07:54:15 +0100 Subject: [PATCH 3/7] improve protobuf file formatting bring back the two new lines between protobuf package name and message definitions --- aas_core_codegen/protobuf/structure/_generate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aas_core_codegen/protobuf/structure/_generate.py b/aas_core_codegen/protobuf/structure/_generate.py index 645101b3..13f27e0a 100644 --- a/aas_core_codegen/protobuf/structure/_generate.py +++ b/aas_core_codegen/protobuf/structure/_generate.py @@ -494,6 +494,7 @@ def generate( package {namespace}; + {code_blocks_joined}""" ), proto_common.WARNING, From 67844a6bf3d0c6fc4c3ca6758db1b513e4f3b2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Tue, 11 Mar 2025 08:00:31 +0100 Subject: [PATCH 4/7] update test to latest aas-core-meta align the expected output of the protobuf generator with the latest version of aas-core-meta --- .../aas_core_meta.v3/expected_output/types.proto | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto b/test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto index 6a20f479..e7e5aa29 100644 --- a/test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto +++ b/test_data/proto/test_main/aas_core_meta.v3/expected_output/types.proto @@ -3282,14 +3282,14 @@ message Environment { /// message EmbeddedDataSpecification { /// - /// Actual content of the data specification + /// Reference to the data specification /// - DataSpecificationContent_choice data_specification_content = 1; + Reference data_specification = 1; /// - /// Reference to the data specification + /// Actual content of the data specification /// - Reference data_specification = 2; + DataSpecificationContent_choice data_specification_content = 2; } enum DataTypeIec61360 { From 5bfcd1e7ab1ab5ea9b9a3ceec2bb20b33fb4ff3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Tue, 11 Mar 2025 08:04:51 +0100 Subject: [PATCH 5/7] apply code formatting checks --- aas_core_codegen/protobuf/description.py | 4 +++- aas_core_codegen/protobuf/naming.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/aas_core_codegen/protobuf/description.py b/aas_core_codegen/protobuf/description.py index c9256a24..06e22ff5 100644 --- a/aas_core_codegen/protobuf/description.py +++ b/aas_core_codegen/protobuf/description.py @@ -227,7 +227,9 @@ def transform_reference_to_attribute_in_doc( if isinstance(element.reference.cls, intermediate.AbstractClass): # We do not generate ProtoBuf code for abstract classes, so we have to refer # to the interface. - name_of_our_type = proto_naming.interface_name(element.reference.cls.name) + name_of_our_type = proto_naming.interface_name( + element.reference.cls.name + ) elif isinstance(element.reference.cls, intermediate.ConcreteClass): # NOTE (mristin, 2021-12-25): # Though a concrete class can have multiple descendants and the writer diff --git a/aas_core_codegen/protobuf/naming.py b/aas_core_codegen/protobuf/naming.py index 189e2578..a6addd1e 100644 --- a/aas_core_codegen/protobuf/naming.py +++ b/aas_core_codegen/protobuf/naming.py @@ -16,7 +16,9 @@ def interface_name(identifier: Identifier) -> Identifier: Since proto3 does not directly support interfaces, but only one-of messages (commonly suffixed "_choice"), these names are generated here. """ - return aas_core_codegen.naming.capitalized_camel_case(identifier) + "_choice" + return Identifier( + aas_core_codegen.naming.capitalized_camel_case(identifier) + "_choice" + ) def enum_name(identifier: Identifier) -> Identifier: From 98b48acd68998c687e85f5eda5042285a2a0028b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Tue, 11 Mar 2025 08:36:29 +0100 Subject: [PATCH 6/7] fix test setup for protobuf generator --- dev_scripts/run_tests_with_rerecord.py | 1 + tests/proto/test_main.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dev_scripts/run_tests_with_rerecord.py b/dev_scripts/run_tests_with_rerecord.py index 366aac06..3252ed32 100644 --- a/dev_scripts/run_tests_with_rerecord.py +++ b/dev_scripts/run_tests_with_rerecord.py @@ -24,6 +24,7 @@ def main() -> int: "tests.smoke.test_main.Test_against_recorded", "tests.typescript.test_main.Test_against_recorded", "tests.xsd.test_main.Test_against_recorded", + "tests.proto.test_main.Test_against_recorded", ] parser = argparse.ArgumentParser(description=__doc__) diff --git a/tests/proto/test_main.py b/tests/proto/test_main.py index f6f0d3b7..8736a4c5 100644 --- a/tests/proto/test_main.py +++ b/tests/proto/test_main.py @@ -18,7 +18,7 @@ class Test_against_recorded(unittest.TestCase): def test_against_expected_meta_models(self) -> None: - parent_case_dir = REPO_DIR / "test_data" / "proto" / "test_main" / "expected" + parent_case_dir = REPO_DIR / "test_data" / "proto" / "test_main" assert parent_case_dir.exists() and parent_case_dir.is_dir(), parent_case_dir # fmt: off From 7c16e68a48df8056af3dd92ca8fed6b046b1bba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Gneu=C3=9F?= Date: Tue, 11 Mar 2025 09:14:39 +0100 Subject: [PATCH 7/7] fix pylint warnings --- aas_core_codegen/protobuf/common.py | 2 +- aas_core_codegen/protobuf/naming.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/aas_core_codegen/protobuf/common.py b/aas_core_codegen/protobuf/common.py index 4afdeeef..e2a4b25a 100644 --- a/aas_core_codegen/protobuf/common.py +++ b/aas_core_codegen/protobuf/common.py @@ -6,7 +6,7 @@ from icontract import ensure, require from aas_core_codegen import intermediate -from aas_core_codegen.common import Stripped, assert_never, Identifier +from aas_core_codegen.common import Stripped, assert_never from aas_core_codegen.protobuf import naming as proto_naming diff --git a/aas_core_codegen/protobuf/naming.py b/aas_core_codegen/protobuf/naming.py index a6addd1e..8ca011ee 100644 --- a/aas_core_codegen/protobuf/naming.py +++ b/aas_core_codegen/protobuf/naming.py @@ -2,8 +2,6 @@ from typing import Union -from icontract import ensure - import aas_core_codegen.naming from aas_core_codegen import intermediate from aas_core_codegen.common import Identifier, assert_never