diff --git a/.gitignore b/.gitignore index 353cf084a..397552b70 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # Coverage artifacts /.coverage /htmlcov/ +/docs/build/ # customized config files /test/test_config.ini diff --git a/README.md b/README.md index 675b0f1e4..4793b3241 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,23 @@ (formerly known as PyI40AAS – Python Industry 4.0 Asset Administration Shell) -The Eclipse BaSyx Python project focuses on providing a Python implementation of the Asset Administration Shell (AAS) for Industry 4.0 Systems, -compliant with the meta model and interface specification provided in -[the document “Details of the Asset Administration Shell” (v2.0.1)](https://www.plattform-i40.de/IP/Redaktion/DE/Downloads/Publikation/Details_of_the_Asset_Administration_Shell_Part1_V2.html). -It currently adheres to version 2.0.1 of the specification. -An updated version with support for version 3.0RC01 is already in preparation and will be made available on an additional branch of this repository and in a future major release. +The Eclipse BaSyx Python project focuses on providing a Python implementation of the Asset Administration Shell (AAS) +for Industry 4.0 Systems. +These are the currently implemented specifications: + +| Specification | Version | +|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| +| Part 1: Metamodel | [v3.0 (01001-3-0)](https://industrialdigitaltwin.org/content-hub/aasspecifications/idta_01001-3-0_metamodel) | +| Part 2: API | not implemented yet | +| Part 3a: Data Specification IEC 61360 | [v3.0 (01003-a-3-0)](https://industrialdigitaltwin.org/content-hub/aasspecifications/idta_01003-a-3-0_data_specification) | +| Part 5: Package File Format (AASX) | [v3.0 (01005-3-0)](https://industrialdigitaltwin.org/content-hub/aasspecifications/idta-01005-3-0_package_file_format_aasx) | ## Features -* Modelling of AASs as Python objects (according to DotAAS sec. 4) - * **except for**: Security extension of the metamodel (according to DotAAS sec. 5), *HasDataSpecification* -* Reading and writing of AASX package files (according to DotAAS sec. 6) -* (De-)serialization of AAS objects into/from JSON and XML (according to DotAAS sec. 7) +* Modelling of AASs as Python objects + * **except for**: *HasDataSpecification* +* Reading and writing of AASX package files +* (De-)serialization of AAS objects into/from JSON and XML * Storing of AAS objects in CouchDB, Backend infrastructure for easy expansion * Compliance checking of AAS XML and JSON files @@ -53,9 +58,12 @@ Optional production usage dependencies: * For using the Compliance Tool to validate JSON files against the JSON Schema: `jsonschema` and its dependencies (MIT License, Apache License, PSF License) -Development/testing/example dependencies (see `requirements.txt`): +Development/testing/documentation/example dependencies (see `requirements.txt`): * `jsonschema` and its dependencies (MIT License, Apache License, PSF License) * `psutil` (BSD 3-clause License) +* `Sphinx` and its dependencies (multiple licenses) +* `sphinx-rtd-theme` and its dependencies +* `sphinx-argparse` (MIT License) Dependencies for building the documentation: * `Sphinx` and its dependencies (BSD 2-clause License, MIT License, Apache License) @@ -89,19 +97,17 @@ Create a `Submodel`: ```python from basyx.aas import model # Import all BaSyx Python SDK classes from the model package -identifier = model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) -submodel = model.Submodel(identification=identifier) +identifier = 'https://acplt.org/Simple_Submodel' +submodel = model.Submodel(identifier) ``` Create a `Property` and add it to the `Submodel`: ```python -# create a global reference to a semantic description of the property -semantic_reference = model.Reference( +# create an external reference to a semantic description of the property +semantic_reference = model.ExternalReference( (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/SimpleProperty' ),) ) property = model.Property( diff --git a/basyx/aas/adapter/_generic.py b/basyx/aas/adapter/_generic.py index 6ae76a688..34c3412b1 100644 --- a/basyx/aas/adapter/_generic.py +++ b/basyx/aas/adapter/_generic.py @@ -12,87 +12,104 @@ from basyx.aas import model -MODELING_KIND: Dict[model.ModelingKind, str] = { - model.ModelingKind.TEMPLATE: 'Template', - model.ModelingKind.INSTANCE: 'Instance'} +# XML Namespace definition +XML_NS_MAP = {"aas": "https://admin-shell.io/aas/3/0"} +XML_NS_AAS = "{" + XML_NS_MAP["aas"] + "}" + +MODELLING_KIND: Dict[model.ModellingKind, str] = { + model.ModellingKind.TEMPLATE: 'Template', + model.ModellingKind.INSTANCE: 'Instance'} ASSET_KIND: Dict[model.AssetKind, str] = { model.AssetKind.TYPE: 'Type', - model.AssetKind.INSTANCE: 'Instance'} + model.AssetKind.INSTANCE: 'Instance', + model.AssetKind.NOT_APPLICABLE: 'NotApplicable'} + +QUALIFIER_KIND: Dict[model.QualifierKind, str] = { + model.QualifierKind.CONCEPT_QUALIFIER: 'ConceptQualifier', + model.QualifierKind.TEMPLATE_QUALIFIER: 'TemplateQualifier', + model.QualifierKind.VALUE_QUALIFIER: 'ValueQualifier'} + +DIRECTION: Dict[model.Direction, str] = { + model.Direction.INPUT: 'input', + model.Direction.OUTPUT: 'output'} -KEY_ELEMENTS: Dict[model.KeyElements, str] = { - model.KeyElements.ASSET: 'Asset', - model.KeyElements.ASSET_ADMINISTRATION_SHELL: 'AssetAdministrationShell', - model.KeyElements.CONCEPT_DESCRIPTION: 'ConceptDescription', - model.KeyElements.SUBMODEL: 'Submodel', - model.KeyElements.ANNOTATED_RELATIONSHIP_ELEMENT: 'AnnotatedRelationshipElement', - model.KeyElements.BASIC_EVENT: 'BasicEvent', - model.KeyElements.BLOB: 'Blob', - model.KeyElements.CAPABILITY: 'Capability', - model.KeyElements.CONCEPT_DICTIONARY: 'ConceptDictionary', - model.KeyElements.DATA_ELEMENT: 'DataElement', - model.KeyElements.ENTITY: 'Entity', - model.KeyElements.EVENT: 'Event', - model.KeyElements.FILE: 'File', - model.KeyElements.MULTI_LANGUAGE_PROPERTY: 'MultiLanguageProperty', - model.KeyElements.OPERATION: 'Operation', - model.KeyElements.PROPERTY: 'Property', - model.KeyElements.RANGE: 'Range', - model.KeyElements.REFERENCE_ELEMENT: 'ReferenceElement', - model.KeyElements.RELATIONSHIP_ELEMENT: 'RelationshipElement', - model.KeyElements.SUBMODEL_ELEMENT: 'SubmodelElement', - model.KeyElements.SUBMODEL_ELEMENT_COLLECTION: 'SubmodelElementCollection', - model.KeyElements.VIEW: 'View', - model.KeyElements.GLOBAL_REFERENCE: 'GlobalReference', - model.KeyElements.FRAGMENT_REFERENCE: 'FragmentReference'} +STATE_OF_EVENT: Dict[model.StateOfEvent, str] = { + model.StateOfEvent.ON: 'on', + model.StateOfEvent.OFF: 'off'} -KEY_TYPES: Dict[model.KeyType, str] = { - model.KeyType.CUSTOM: 'Custom', - model.KeyType.IRDI: 'IRDI', - model.KeyType.IRI: 'IRI', - model.KeyType.IDSHORT: 'IdShort', - model.KeyType.FRAGMENT_ID: 'FragmentId'} +REFERENCE_TYPES: Dict[Type[model.Reference], str] = { + model.ExternalReference: 'ExternalReference', + model.ModelReference: 'ModelReference'} -IDENTIFIER_TYPES: Dict[model.IdentifierType, str] = { - model.IdentifierType.CUSTOM: 'Custom', - model.IdentifierType.IRDI: 'IRDI', - model.IdentifierType.IRI: 'IRI'} +KEY_TYPES: Dict[model.KeyTypes, str] = { + model.KeyTypes.ASSET_ADMINISTRATION_SHELL: 'AssetAdministrationShell', + model.KeyTypes.CONCEPT_DESCRIPTION: 'ConceptDescription', + model.KeyTypes.SUBMODEL: 'Submodel', + model.KeyTypes.ANNOTATED_RELATIONSHIP_ELEMENT: 'AnnotatedRelationshipElement', + model.KeyTypes.BASIC_EVENT_ELEMENT: 'BasicEventElement', + model.KeyTypes.BLOB: 'Blob', + model.KeyTypes.CAPABILITY: 'Capability', + model.KeyTypes.DATA_ELEMENT: 'DataElement', + model.KeyTypes.ENTITY: 'Entity', + model.KeyTypes.EVENT_ELEMENT: 'EventElement', + model.KeyTypes.FILE: 'File', + model.KeyTypes.MULTI_LANGUAGE_PROPERTY: 'MultiLanguageProperty', + model.KeyTypes.OPERATION: 'Operation', + model.KeyTypes.PROPERTY: 'Property', + model.KeyTypes.RANGE: 'Range', + model.KeyTypes.REFERENCE_ELEMENT: 'ReferenceElement', + model.KeyTypes.RELATIONSHIP_ELEMENT: 'RelationshipElement', + model.KeyTypes.SUBMODEL_ELEMENT: 'SubmodelElement', + model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION: 'SubmodelElementCollection', + model.KeyTypes.SUBMODEL_ELEMENT_LIST: 'SubmodelElementList', + model.KeyTypes.GLOBAL_REFERENCE: 'GlobalReference', + model.KeyTypes.FRAGMENT_REFERENCE: 'FragmentReference'} ENTITY_TYPES: Dict[model.EntityType, str] = { model.EntityType.CO_MANAGED_ENTITY: 'CoManagedEntity', model.EntityType.SELF_MANAGED_ENTITY: 'SelfManagedEntity'} -IEC61360_DATA_TYPES: Dict[model.concept.IEC61360DataType, str] = { - model.concept.IEC61360DataType.DATE: 'DATE', - model.concept.IEC61360DataType.STRING: 'STRING', - model.concept.IEC61360DataType.STRING_TRANSLATABLE: 'STRING_TRANSLATABLE', - model.concept.IEC61360DataType.REAL_MEASURE: 'REAL_MEASURE', - model.concept.IEC61360DataType.REAL_COUNT: 'REAL_COUNT', - model.concept.IEC61360DataType.REAL_CURRENCY: 'REAL_CURRENCY', - model.concept.IEC61360DataType.BOOLEAN: 'BOOLEAN', - model.concept.IEC61360DataType.URL: 'URL', - model.concept.IEC61360DataType.RATIONAL: 'RATIONAL', - model.concept.IEC61360DataType.RATIONAL_MEASURE: 'RATIONAL_MEASURE', - model.concept.IEC61360DataType.TIME: 'TIME', - model.concept.IEC61360DataType.TIMESTAMP: 'TIMESTAMP', +IEC61360_DATA_TYPES: Dict[model.base.DataTypeIEC61360, str] = { + model.base.DataTypeIEC61360.DATE: 'DATE', + model.base.DataTypeIEC61360.STRING: 'STRING', + model.base.DataTypeIEC61360.STRING_TRANSLATABLE: 'STRING_TRANSLATABLE', + model.base.DataTypeIEC61360.INTEGER_MEASURE: 'INTEGER_MEASURE', + model.base.DataTypeIEC61360.INTEGER_COUNT: 'INTEGER_COUNT', + model.base.DataTypeIEC61360.INTEGER_CURRENCY: 'INTEGER_CURRENCY', + model.base.DataTypeIEC61360.REAL_MEASURE: 'REAL_MEASURE', + model.base.DataTypeIEC61360.REAL_COUNT: 'REAL_COUNT', + model.base.DataTypeIEC61360.REAL_CURRENCY: 'REAL_CURRENCY', + model.base.DataTypeIEC61360.BOOLEAN: 'BOOLEAN', + model.base.DataTypeIEC61360.IRI: 'IRI', + model.base.DataTypeIEC61360.IRDI: 'IRDI', + model.base.DataTypeIEC61360.RATIONAL: 'RATIONAL', + model.base.DataTypeIEC61360.RATIONAL_MEASURE: 'RATIONAL_MEASURE', + model.base.DataTypeIEC61360.TIME: 'TIME', + model.base.DataTypeIEC61360.TIMESTAMP: 'TIMESTAMP', + model.base.DataTypeIEC61360.HTML: 'HTML', + model.base.DataTypeIEC61360.BLOB: 'BLOB', + model.base.DataTypeIEC61360.FILE: 'FILE', } -IEC61360_LEVEL_TYPES: Dict[model.concept.IEC61360LevelType, str] = { - model.concept.IEC61360LevelType.MIN: 'Min', - model.concept.IEC61360LevelType.MAX: 'Max', - model.concept.IEC61360LevelType.NOM: 'Nom', - model.concept.IEC61360LevelType.TYP: 'Typ', +IEC61360_LEVEL_TYPES: Dict[model.base.IEC61360LevelType, str] = { + model.base.IEC61360LevelType.MIN: 'min', + model.base.IEC61360LevelType.NOM: 'nom', + model.base.IEC61360LevelType.TYP: 'typ', + model.base.IEC61360LevelType.MAX: 'max', } -MODELING_KIND_INVERSE: Dict[str, model.ModelingKind] = {v: k for k, v in MODELING_KIND.items()} +MODELLING_KIND_INVERSE: Dict[str, model.ModellingKind] = {v: k for k, v in MODELLING_KIND.items()} ASSET_KIND_INVERSE: Dict[str, model.AssetKind] = {v: k for k, v in ASSET_KIND.items()} -KEY_ELEMENTS_INVERSE: Dict[str, model.KeyElements] = {v: k for k, v in KEY_ELEMENTS.items()} -KEY_TYPES_INVERSE: Dict[str, model.KeyType] = {v: k for k, v in KEY_TYPES.items()} -IDENTIFIER_TYPES_INVERSE: Dict[str, model.IdentifierType] = {v: k for k, v in IDENTIFIER_TYPES.items()} +QUALIFIER_KIND_INVERSE: Dict[str, model.QualifierKind] = {v: k for k, v in QUALIFIER_KIND.items()} +DIRECTION_INVERSE: Dict[str, model.Direction] = {v: k for k, v in DIRECTION.items()} +STATE_OF_EVENT_INVERSE: Dict[str, model.StateOfEvent] = {v: k for k, v in STATE_OF_EVENT.items()} +REFERENCE_TYPES_INVERSE: Dict[str, Type[model.Reference]] = {v: k for k, v in REFERENCE_TYPES.items()} +KEY_TYPES_INVERSE: Dict[str, model.KeyTypes] = {v: k for k, v in KEY_TYPES.items()} ENTITY_TYPES_INVERSE: Dict[str, model.EntityType] = {v: k for k, v in ENTITY_TYPES.items()} -IEC61360_DATA_TYPES_INVERSE: Dict[str, model.concept.IEC61360DataType] = {v: k for k, v in IEC61360_DATA_TYPES.items()} -IEC61360_LEVEL_TYPES_INVERSE: Dict[str, model.concept.IEC61360LevelType] = \ +IEC61360_DATA_TYPES_INVERSE: Dict[str, model.base.DataTypeIEC61360] = {v: k for k, v in IEC61360_DATA_TYPES.items()} +IEC61360_LEVEL_TYPES_INVERSE: Dict[str, model.base.IEC61360LevelType] = \ {v: k for k, v in IEC61360_LEVEL_TYPES.items()} -KEY_ELEMENTS_CLASSES_INVERSE: Dict[model.KeyElements, Type[model.Referable]] = \ - {v: k for k, v in model.KEY_ELEMENTS_CLASSES.items()} +KEY_TYPES_CLASSES_INVERSE: Dict[model.KeyTypes, Type[model.Referable]] = \ + {v: k for k, v in model.KEY_TYPES_CLASSES.items()} diff --git a/basyx/aas/adapter/aasx.py b/basyx/aas/adapter/aasx.py index 5e4711994..a43f8c706 100644 --- a/basyx/aas/adapter/aasx.py +++ b/basyx/aas/adapter/aasx.py @@ -39,10 +39,10 @@ logger = logging.getLogger(__name__) -RELATIONSHIP_TYPE_AASX_ORIGIN = "http://www.admin-shell.io/aasx/relationships/aasx-origin" -RELATIONSHIP_TYPE_AAS_SPEC = "http://www.admin-shell.io/aasx/relationships/aas-spec" -RELATIONSHIP_TYPE_AAS_SPEC_SPLIT = "http://www.admin-shell.io/aasx/relationships/aas-spec-split" -RELATIONSHIP_TYPE_AAS_SUPL = "http://www.admin-shell.io/aasx/relationships/aas-suppl" +RELATIONSHIP_TYPE_AASX_ORIGIN = "http://admin-shell.io/aasx/relationships/aasx-origin" +RELATIONSHIP_TYPE_AAS_SPEC = "http://admin-shell.io/aasx/relationships/aas-spec" +RELATIONSHIP_TYPE_AAS_SPEC_SPLIT = "http://admin-shell.io/aasx/relationships/aas-spec-split" +RELATIONSHIP_TYPE_AAS_SUPL = "http://admin-shell.io/aasx/relationships/aas-suppl" class AASXReader: @@ -58,6 +58,7 @@ class AASXReader: with AASXReader("filename.aasx") as reader: meta_data = reader.get_core_properties() reader.read_into(objects, files) + """ def __init__(self, file: Union[os.PathLike, str, IO]): """ @@ -191,9 +192,9 @@ def _read_aas_part_into(self, part_name: str, AASX that have the same Identifer. Default behavior is to skip those objects from the AASX. """ for obj in self._parse_aas_part(part_name, **kwargs): - if obj.identification in read_identifiables: + if obj.id in read_identifiables: continue - if obj.identification in object_store: + if obj.id in object_store: if override_existing: logger.info("Overriding existing object in ObjectStore with {} ...".format(obj)) object_store.discard(obj) @@ -202,7 +203,7 @@ def _read_aas_part_into(self, part_name: str, "ObjectStore".format(obj)) continue object_store.add(obj) - read_identifiables.add(obj.identification) + read_identifiables.add(obj.id) if isinstance(obj, model.Submodel): self._collect_supplementary_files(part_name, obj, file_store) @@ -274,10 +275,10 @@ class AASXWriter: cp.created = datetime.datetime.now() with AASXWriter("filename.aasx") as writer: - writer.write_aas(Identifier("https://acplt.org/AssetAdministrationShell", IdentifierType.IRI), + writer.write_aas("https://acplt.org/AssetAdministrationShell", object_store, file_store) - writer.write_aas(Identifier("https://acplt.org/AssetAdministrationShell2", IdentifierType.IRI), + writer.write_aas("https://acplt.org/AssetAdministrationShell2", object_store, file_store) writer.write_core_properties(cp) @@ -306,7 +307,6 @@ def __init__(self, file: Union[os.PathLike, str, IO]): self._properties_part: Optional[str] = None # names and hashes of all supplementary file parts that have already been written self._supplementary_part_names: Dict[str, Optional[bytes]] = {} - self._aas_name_friendlyfier = NameFriendlyfier() # Open OPC package writer self.writer = pyecma376_2.ZipPackageWriter(file) @@ -317,83 +317,106 @@ def __init__(self, file: Union[os.PathLike, str, IO]): p.close() def write_aas(self, - aas_id: model.Identifier, + aas_ids: Union[model.Identifier, Iterable[model.Identifier]], object_store: model.AbstractObjectStore, file_store: "AbstractSupplementaryFileContainer", - write_json: bool = False, - submodel_split_parts: bool = True) -> None: + write_json: bool = False) -> None: """ - Convenience method to add an :class:`~aas.model.aas.AssetAdministrationShell` with all included and referenced + Convenience method to write one or more + :class:`AssetAdministrationShells ` with all included and referenced objects to the AASX package according to the part name conventions from DotAAS. - This method takes the AAS's :class:`~aas.model.base.Identifier` (as `aas_id`) to retrieve it from the given - object_store. :class:`References <~aas.model.base.Reference>` to - the :class:`~aas.model.aas.Asset`, :class:`ConceptDescriptions ` and - :class:`Submodels ` are also resolved using the object_store. All of these objects - are written to aas-spec parts in the AASX package, following the conventions presented in "Details of the Asset - Administration Shell". For each Submodel, a aas-spec-split part is used. Supplementary files which are - referenced by a File object in any of the Submodels, are also added to the AASX package. - - Internally, this method uses :meth:`aas.adapter.aasx.AASXWriter.write_aas_objects` to write the individual AASX - parts for the AAS and each submodel. - - :param aas_id: :class:`~aas.model.base.Identifier` of the :class:`~aas.model.aas.AssetAdministrationShell` to - be added to the AASX file + This method takes the AASs' :class:`Identifiers ` (as `aas_ids`) to retrieve the + AASs from the given object_store. + :class:`References ` to :class:`Submodels ` and + :class:`ConceptDescriptions ` (via semanticId attributes) are also + resolved using the + `object_store`. All of these objects are written to an aas-spec part `/aasx/data.xml` or `/aasx/data.json` in + the AASX package, compliant to the convention presented in "Details of the Asset Administration Shell". + Supplementary files which are referenced by a :class:`~aas.model.submodel.File` object in any of the + :class:`Submodels ` are also added to the AASX + package. + + This method uses `write_all_aas_objects()` to write the AASX part. + + .. attention:: + + This method **must only be used once** on a single AASX package. Otherwise, the `/aasx/data.json` + (or `...xml`) part would be written twice to the package, hiding the first part and possibly causing + problems when reading the package. + + To write multiple Asset Administration Shells to a single AASX package file, call this method once, passing + a list of AAS Identifiers to the `aas_ids` parameter. + + :param aas_ids: :class:`~aas.model.base.Identifier` or Iterable of + :class:`Identifiers ` of the AAS(s) to be written to the AASX file :param object_store: :class:`ObjectStore ` to retrieve the :class:`~aas.model.base.Identifiable` AAS objects (:class:`~aas.model.aas.AssetAdministrationShell`, - :class:`~aas.model.aas.Asset`, :class:`~aas.model.concept.ConceptDescription` and - :class:`~aas.model.submodel.Submodel`) from - :param file_store: :class:`SupplementaryFileContainer ` to - retrieve supplementary files from, which are referenced by :class:`~aas.model.submodel.File` objects - :param write_json: If `True`, JSON parts are created for the AAS and each submodel in the AASX package file - instead of XML parts. Defaults to `False`. - :param submodel_split_parts: If `True` (default), submodels are written to separate AASX parts instead of being - included in the AAS part with in the AASX package. - """ - aas_friendly_name = self._aas_name_friendlyfier.get_friendly_name(aas_id) - aas_part_name = "/aasx/{0}/{0}.aas.{1}".format(aas_friendly_name, "json" if write_json else "xml") - - aas = object_store.get_identifiable(aas_id) - if not isinstance(aas, model.AssetAdministrationShell): - raise ValueError(f"Identifier does not belong to an AssetAdminstrationShell object but to {aas!r}") - - objects_to_be_written: Set[model.Identifier] = {aas.identification} - - # Add the Asset object to the objects in the AAS part - objects_to_be_written.add(aas.asset.get_identifier()) - - # Add referenced ConceptDescriptions to the AAS part - for dictionary in aas.concept_dictionary: - for concept_description_ref in dictionary.concept_description: - objects_to_be_written.add(concept_description_ref.get_identifier()) - - # Write submodels: Either create a split part for each of them or otherwise add them to objects_to_be_written - aas_split_part_names: List[str] = [] - if submodel_split_parts: - # Create a AAS split part for each (available) submodel of the AAS - aas_friendlyfier = NameFriendlyfier() - for submodel_ref in aas.submodel: - submodel_identification = submodel_ref.get_identifier() - submodel_friendly_name = aas_friendlyfier.get_friendly_name(submodel_identification) - submodel_part_name = "/aasx/{0}/{1}/{1}.submodel.{2}".format(aas_friendly_name, submodel_friendly_name, - "json" if write_json else "xml") - self.write_aas_objects(submodel_part_name, [submodel_identification], object_store, file_store, - write_json, split_part=True) - aas_split_part_names.append(submodel_part_name) - else: + :class:`~aas.model.concept.ConceptDescription` and :class:`~aas.model.submodel.Submodel`) from + :param file_store: :class:`SupplementaryFileContainer <~.AbstractSupplementaryFileContainer>` to retrieve + supplementary files from, which are referenced by :class:`~aas.model.submodel.File` objects + :param write_json: If `True`, JSON parts are created for the AAS and each :class:`~aas.model.submodel.Submodel` + in the AASX package file instead of XML parts. Defaults to `False`. + :raises KeyError: If one of the AAS could not be retrieved from the object store (unresolvable + :class:`Submodels ` and + :class:`ConceptDescriptions ` are skipped, logging a warning/info + message) + :raises TypeError: If one of the given AAS ids does not resolve to an AAS (but another + :class:`~aas.model.base.Identifiable` object) + """ + if isinstance(aas_ids, model.Identifier): + aas_ids = (aas_ids,) + + objects_to_be_written: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() + for aas_id in aas_ids: + try: + aas = object_store.get_identifiable(aas_id) + # TODO add failsafe mode + except KeyError: + raise + if not isinstance(aas, model.AssetAdministrationShell): + raise TypeError(f"Identifier {aas_id} does not belong to an AssetAdminstrationShell object but to " + f"{aas!r}") + + # Add the AssetAdministrationShell object to the data part + objects_to_be_written.add(aas) + + # Add referenced Submodels to the data part for submodel_ref in aas.submodel: - objects_to_be_written.add(submodel_ref.get_identifier()) - - # Write AAS part - logger.debug("Writing AAS {} to part {} in AASX package ...".format(aas.identification, aas_part_name)) - self.write_aas_objects(aas_part_name, objects_to_be_written, object_store, file_store, write_json, - split_part=False, - additional_relationships=(pyecma376_2.OPCRelationship("r{}".format(i), - RELATIONSHIP_TYPE_AAS_SPEC_SPLIT, - submodel_part_name, - pyecma376_2.OPCTargetMode.INTERNAL) - for i, submodel_part_name in enumerate(aas_split_part_names))) + try: + submodel = submodel_ref.resolve(object_store) + except KeyError: + logger.warning("Could not find submodel %s. Skipping it.", str(submodel_ref)) + continue + objects_to_be_written.add(submodel) + + # Traverse object tree and check if semanticIds are referencing to existing ConceptDescriptions in the + # ObjectStore + concept_descriptions: List[model.ConceptDescription] = [] + for identifiable in objects_to_be_written: + for semantic_id in traversal.walk_semantic_ids_recursive(identifiable): + if not isinstance(semantic_id, model.ModelReference) \ + or semantic_id.type is not model.ConceptDescription: + logger.info("semanticId %s does not reference a ConceptDescription.", str(semantic_id)) + continue + try: + cd = semantic_id.resolve(object_store) + except KeyError: + logger.info("ConceptDescription for semantidId %s not found in object store.", str(semantic_id)) + continue + except model.UnexpectedTypeError as e: + logger.error("semantidId %s resolves to %s, which is not a ConceptDescription", + str(semantic_id), e.value) + continue + concept_descriptions.append(cd) + objects_to_be_written.update(concept_descriptions) + + # Write AAS data part + self.write_all_aas_objects("/aasx/data.{}".format("json" if write_json else "xml"), + objects_to_be_written, file_store, write_json) + # TODO remove `method` parameter in future version. + # Not actually required since you can always create a local dict def write_aas_objects(self, part_name: str, object_ids: Iterable[model.Identifier], @@ -403,8 +426,7 @@ def write_aas_objects(self, split_part: bool = False, additional_relationships: Iterable[pyecma376_2.OPCRelationship] = ()) -> None: """ - Write a defined list of AAS objects to an XML or JSON part in the AASX package and append the referenced - supplementary files to the package. + A thin wrapper around :meth:`write_all_aas_objects` to ensure downwards compatibility This method takes the AAS's :class:`~aas.model.base.Identifier` (as `aas_id`) to retrieve it from the given object_store. If the list @@ -412,7 +434,10 @@ def write_aas_objects(self, referenced by :class:`~aas.model.submodel.File` objects within those submodels, are also added to the AASX package. - You must make sure to call this method only once per unique `part_name` on a single package instance. + .. attention:: + + You must make sure to call this method or `write_all_aas_objects` only once per unique `part_name` on a + single package instance. :param part_name: Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2 part name and unique within the package. The extension of the part should match the data format (i.e. @@ -433,7 +458,6 @@ def write_aas_objects(self, logger.debug("Writing AASX part {} with AAS objects ...".format(part_name)) objects: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - supplementary_files: List[str] = [] # Retrieve objects and scan for referenced supplementary files for identifier in object_ids: @@ -443,6 +467,50 @@ def write_aas_objects(self, logger.error("Could not find object {} in ObjectStore".format(identifier)) continue objects.add(the_object) + + self.write_all_aas_objects(part_name, objects, file_store, write_json, split_part, additional_relationships) + + # TODO remove `split_part` parameter in future version. + # Not required anymore since changes from DotAAS version 2.0.1 to 3.0RC01 + def write_all_aas_objects(self, + part_name: str, + objects: model.AbstractObjectStore[model.Identifiable], + file_store: "AbstractSupplementaryFileContainer", + write_json: bool = False, + split_part: bool = False, + additional_relationships: Iterable[pyecma376_2.OPCRelationship] = ()) -> None: + """ + Write all AAS objects in a given :class:`ObjectStore ` to an XML or + JSON part in the AASX package and add the referenced supplementary files to the package. + + This method takes an :class:`ObjectStore ` and writes all contained + objects into an "aas_env" part in the AASX package. If + the ObjectStore includes :class:`~aas.model.submodel.Submodel` objects, supplementary files which are + referenced by :class:`~aas.model.submodel.File` objects + within those Submodels, are fetched from the `file_store` and added to the AASX package. + + .. attention:: + + You must make sure to call this method only once per unique `part_name` on a single package instance. + + :param part_name: Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2 + part name and unique within the package. The extension of the part should match the data format (i.e. + '.json' if `write_json` else '.xml'). + :param objects: The objects to be written to the AASX package. Only these Identifiable objects (and included + Referable objects) are written to the package. + :param file_store: The SupplementaryFileContainer to retrieve supplementary files from (if there are any `File` + objects within the written objects. + :param write_json: If True, the part is written as a JSON file instead of an XML file. Defaults to False. + :param split_part: If True, no aas-spec relationship is added from the aasx-origin to this part. You must make + sure to reference it via a aas-spec-split relationship from another aas-spec part + :param additional_relationships: Optional OPC/ECMA376 relationships which should originate at the AAS object + part to be written, in addition to the aas-suppl relationships which are created automatically. + """ + logger.debug("Writing AASX part {} with AAS objects ...".format(part_name)) + supplementary_files: List[str] = [] + + # Retrieve objects and scan for referenced supplementary files + for the_object in objects: if isinstance(the_object, model.Submodel): for element in traversal.walk_submodel(the_object): if isinstance(element, model.File): @@ -458,6 +526,7 @@ def write_aas_objects(self, self._aas_part_names.append(part_name) # Write part + # TODO allow writing xml *and* JSON part with self.writer.open_part(part_name, "application/json" if write_json else "application/xml") as p: if write_json: write_aas_json_file(io.TextIOWrapper(p, encoding='utf-8'), objects) @@ -587,6 +656,8 @@ def _write_package_relationships(self): self.writer.write_relationships(package_relationships) +# TODO remove in future version. +# Not required anymore since changes from DotAAS version 2.0.1 to 3.0RC01 class NameFriendlyfier: """ A simple helper class to create unique "AAS friendly names" according to DotAAS, section 7.6. @@ -602,6 +673,8 @@ def get_friendly_name(self, identifier: model.Identifier): """ Generate a friendly name from an AAS identifier. + TODO: This information is outdated. The whole class is no longer needed. + According to section 7.6 of "Details of the Asset Administration Shell", all non-alphanumerical characters are replaced with underscores. We also replace all non-ASCII characters to generate valid URIs as the result. If this replacement results in a collision with a previously generated friendly name of this NameFriendlifier, @@ -612,15 +685,15 @@ def get_friendly_name(self, identifier: model.Identifier): .. code-block:: python friendlyfier = NameFriendlyfier() - friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS-a", model.IdentifierType.IRI)) + friendlyfier.get_friendly_name("http://example.com/AAS-a") > "http___example_com_AAS_a" - friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS+a", model.IdentifierType.IRI)) + friendlyfier.get_friendly_name("http://example.com/AAS+a") > "http___example_com_AAS_a_1" """ # friendlify name - raw_name = self.RE_NON_ALPHANUMERICAL.sub('_', identifier.id) + raw_name = self.RE_NON_ALPHANUMERICAL.sub('_', identifier) # Unify name (avoid collisions) amended_name = raw_name diff --git a/basyx/aas/adapter/json/aasJSONSchema.json b/basyx/aas/adapter/json/aasJSONSchema.json index 1c7020ace..f48db4d17 100644 --- a/basyx/aas/adapter/json/aasJSONSchema.json +++ b/basyx/aas/adapter/json/aasJSONSchema.json @@ -1,1439 +1,1528 @@ { - "$schema": "https://json-schema.org/draft/2019-09/schema", - "title": "AssetAdministrationShellEnvironment", - "$id": "http://www.admin-shell.io/schema/json/v2.0.1", - "type": "object", - "required": [ - "assetAdministrationShells", - "submodels", - "assets", - "conceptDescriptions" - ], - "properties": { - "assetAdministrationShells": { - "type": "array", - "items": { - "$ref": "#/definitions/AssetAdministrationShell" - } - }, - "submodels": { - "type": "array", - "items": { - "$ref": "#/definitions/Submodel" - } - }, - "assets": { - "type": "array", - "items": { - "$ref": "#/definitions/Asset" - } - }, - "conceptDescriptions": { - "type": "array", - "items": { - "$ref": "#/definitions/ConceptDescription" - } - } - }, - "definitions": { - "Referable": { - "type": "object", - "properties": { - "idShort": { - "type": "string" - }, - "category": { - "type": "string" - }, - "description": { - "type": "array", - "items": { - "$ref": "#/definitions/LangString" - } - }, - "parent": { - "$ref": "#/definitions/Reference" - }, - "modelType": { - "$ref": "#/definitions/ModelType" - } - }, - "required": [ - "idShort", - "modelType" - ] - }, - "Identifiable": { - "allOf": [ - { - "$ref": "#/definitions/Referable" - }, - { - "properties": { - "identification": { - "$ref": "#/definitions/Identifier" - }, - "administration": { - "$ref": "#/definitions/AdministrativeInformation" - } - }, - "required": [ - "identification" - ] - } - ] - }, - "Qualifiable": { - "type": "object", - "properties": { - "qualifiers": { - "type": "array", - "items": { - "$ref": "#/definitions/Constraint" - } - } - } - }, - "HasSemantics": { - "type": "object", - "properties": { - "semanticId": { - "$ref": "#/definitions/Reference" - } - } - }, - "HasDataSpecification": { - "type": "object", - "properties": { - "embeddedDataSpecifications": { - "type": "array", - "items": { - "$ref": "#/definitions/EmbeddedDataSpecification" - } - } - } - }, - "AssetAdministrationShell": { - "allOf": [ - { - "$ref": "#/definitions/Identifiable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "properties": { - "derivedFrom": { - "$ref": "#/definitions/Reference" - }, - "asset": { - "$ref": "#/definitions/Reference" - }, - "submodels": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - }, - "views": { - "type": "array", - "items": { - "$ref": "#/definitions/View" - } - }, - "conceptDictionaries": { - "type": "array", - "items": { - "$ref": "#/definitions/ConceptDictionary" - } - }, - "security": { - "$ref": "#/definitions/Security" - } - }, - "required": [ - "asset" - ] - } - ] - }, - "Identifier": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "idType": { - "$ref": "#/definitions/KeyType" - } - }, - "required": [ - "id", - "idType" - ] - }, - "KeyType": { - "type": "string", - "enum": [ - "Custom", - "IRDI", - "IRI", - "IdShort", - "FragmentId" - ] - }, - "AdministrativeInformation": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "revision": { - "type": "string" - } - } - }, - "LangString": { - "type": "object", - "properties": { - "language": { - "type": "string" - }, - "text": { - "type": "string" - } - }, - "required": [ - "language", - "text" - ] - }, - "Reference": { - "type": "object", - "properties": { - "keys": { - "type": "array", - "items": { - "$ref": "#/definitions/Key" - } - } - }, - "required": [ - "keys" - ] - }, - "Key": { - "type": "object", - "properties": { - "type": { - "$ref": "#/definitions/KeyElements" - }, - "idType": { - "$ref": "#/definitions/KeyType" - }, - "value": { - "type": "string" - }, - "local": { - "type": "boolean" - } - }, - "required": [ - "type", - "idType", - "value", - "local" - ] - }, - "KeyElements": { - "type": "string", - "enum": [ - "Asset", - "AssetAdministrationShell", - "ConceptDescription", - "Submodel", - "AccessPermissionRule", - "AnnotatedRelationshipElement", - "BasicEvent", - "Blob", - "Capability", - "ConceptDictionary", - "DataElement", - "File", - "Entity", - "Event", - "MultiLanguageProperty", - "Operation", - "Property", - "Range", - "ReferenceElement", - "RelationshipElement", - "SubmodelElement", - "SubmodelElementCollection", - "View", - "GlobalReference", - "FragmentReference" - ] - }, - "ModelTypes": { - "type": "string", - "enum": [ - "Asset", - "AssetAdministrationShell", - "ConceptDescription", - "Submodel", - "AccessPermissionRule", - "AnnotatedRelationshipElement", - "BasicEvent", - "Blob", - "Capability", - "ConceptDictionary", - "DataElement", - "File", - "Entity", - "Event", - "MultiLanguageProperty", - "Operation", - "Property", - "Range", - "ReferenceElement", - "RelationshipElement", - "SubmodelElement", - "SubmodelElementCollection", - "View", - "GlobalReference", - "FragmentReference", - "Constraint", - "Formula", - "Qualifier" - ] - }, - "ModelType": { - "type": "object", - "properties": { - "name": { - "$ref": "#/definitions/ModelTypes" - } - }, - "required": [ - "name" - ] - }, - "EmbeddedDataSpecification": { - "type": "object", - "properties": { - "dataSpecification": { - "$ref": "#/definitions/Reference" - }, - "dataSpecificationContent": { - "$ref": "#/definitions/DataSpecificationContent" - } - }, - "required": [ - "dataSpecification", - "dataSpecificationContent" - ] - }, - "DataSpecificationContent": { - "oneOf": [ - { - "$ref": "#/definitions/DataSpecificationIEC61360Content" - }, - { - "$ref": "#/definitions/DataSpecificationPhysicalUnitContent" - } - ] - }, - "DataSpecificationPhysicalUnitContent": { - "type": "object", - "properties": { - "unitName": { - "type": "string" - }, - "unitSymbol": { - "type": "string" - }, - "definition": { - "type": "array", - "items": { - "$ref": "#/definitions/LangString" - } - }, - "siNotation": { - "type": "string" - }, - "siName": { - "type": "string" - }, - "dinNotation": { - "type": "string" - }, - "eceName": { - "type": "string" - }, - "eceCode": { - "type": "string" - }, - "nistName": { - "type": "string" - }, - "sourceOfDefinition": { - "type": "string" - }, - "conversionFactor": { - "type": "string" - }, - "registrationAuthorityId": { - "type": "string" - }, - "supplier": { - "type": "string" - } - }, - "required": [ - "unitName", - "unitSymbol", - "definition" - ] - }, - "DataSpecificationIEC61360Content": { - "allOf": [ - { - "$ref": "#/definitions/ValueObject" - }, - { - "type": "object", - "properties": { - "dataType": { - "enum": [ - "DATE", - "STRING", - "STRING_TRANSLATABLE", - "REAL_MEASURE", - "REAL_COUNT", - "REAL_CURRENCY", - "BOOLEAN", - "URL", - "RATIONAL", - "RATIONAL_MEASURE", - "TIME", - "TIMESTAMP", - "INTEGER_COUNT", - "INTEGER_MEASURE", - "INTEGER_CURRENCY" - ] - }, - "definition": { - "type": "array", - "items": { - "$ref": "#/definitions/LangString" - } - }, - "preferredName": { - "type": "array", - "items": { - "$ref": "#/definitions/LangString" - } - }, - "shortName": { - "type": "array", - "items": { - "$ref": "#/definitions/LangString" - } - }, - "sourceOfDefinition": { - "type": "string" - }, - "symbol": { - "type": "string" - }, - "unit": { - "type": "string" - }, - "unitId": { - "$ref": "#/definitions/Reference" - }, - "valueFormat": { - "type": "string" - }, - "valueList": { - "$ref": "#/definitions/ValueList" - }, - "levelType": { - "type": "array", - "items": { - "$ref": "#/definitions/LevelType" - } - } - }, - "required": [ - "preferredName" - ] - } - ] - }, - "LevelType": { - "type": "string", - "enum": [ - "Min", - "Max", - "Nom", - "Typ" - ] - }, - "ValueList": { - "type": "object", - "properties": { - "valueReferencePairTypes": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#/definitions/ValueReferencePairType" - } - } - }, - "required": [ - "valueReferencePairTypes" - ] - }, - "ValueReferencePairType": { - "allOf": [ - { - "$ref": "#/definitions/ValueObject" - } - ] - }, - "ValueObject": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "valueId": { - "$ref": "#/definitions/Reference" - }, - "valueType": { - "type": "string", - "enum": [ - "anyUri", - "base64Binary", - "boolean", - "date", - "dateTime", - "dateTimeStamp", - "decimal", - "integer", - "long", - "int", - "short", - "byte", - "nonNegativeInteger", - "positiveInteger", - "unsignedLong", - "unsignedInt", - "unsignedShort", - "unsignedByte", - "nonPositiveInteger", - "negativeInteger", - "double", - "duration", - "dayTimeDuration", - "yearMonthDuration", - "float", - "gDay", - "gMonth", - "gMonthDay", - "gYear", - "gYearMonth", - "hexBinary", - "NOTATION", - "QName", - "string", - "normalizedString", - "token", - "language", - "Name", - "NCName", - "ENTITY", - "ID", - "IDREF", - "NMTOKEN", - "time" - ] - } - } - }, - "Asset": { - "allOf": [ - { - "$ref": "#/definitions/Identifiable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "properties": { - "kind": { - "$ref": "#/definitions/AssetKind" - }, - "assetIdentificationModel": { - "$ref": "#/definitions/Reference" - }, - "billOfMaterial": { - "$ref": "#/definitions/Reference" - } - }, - "required": [ - "kind" - ] - } - ] - }, - "AssetKind": { - "type": "string", - "enum": [ - "Type", - "Instance" - ] - }, - "ModelingKind": { - "type": "string", - "enum": [ - "Template", - "Instance" - ] - }, - "Submodel": { - "allOf": [ - { - "$ref": "#/definitions/Identifiable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "$ref": "#/definitions/Qualifiable" - }, - { - "$ref": "#/definitions/HasSemantics" - }, - { - "properties": { - "kind": { - "$ref": "#/definitions/ModelingKind" - }, - "submodelElements": { - "type": "array", - "items": { - "$ref": "#/definitions/SubmodelElement" - } - } - } - } - ] - }, - "Constraint": { - "type": "object", - "properties": { - "modelType": { - "$ref": "#/definitions/ModelType" - } - }, - "required": [ - "modelType" - ] - }, - "Operation": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "inputVariable": { - "type": "array", - "items": { - "$ref": "#/definitions/OperationVariable" - } - }, - "outputVariable": { - "type": "array", - "items": { - "$ref": "#/definitions/OperationVariable" - } - }, - "inoutputVariable": { - "type": "array", - "items": { - "$ref": "#/definitions/OperationVariable" - } - } - } - } - ] - }, - "OperationVariable": { - "type": "object", - "properties": { - "value": { - "oneOf": [ - { - "$ref": "#/definitions/Blob" - }, - { - "$ref": "#/definitions/File" - }, - { - "$ref": "#/definitions/Capability" - }, - { - "$ref": "#/definitions/Entity" - }, - { - "$ref": "#/definitions/Event" - }, - { - "$ref": "#/definitions/BasicEvent" - }, - { - "$ref": "#/definitions/MultiLanguageProperty" - }, - { - "$ref": "#/definitions/Operation" - }, - { - "$ref": "#/definitions/Property" - }, - { - "$ref": "#/definitions/Range" - }, - { - "$ref": "#/definitions/ReferenceElement" - }, - { - "$ref": "#/definitions/RelationshipElement" - }, - { - "$ref": "#/definitions/SubmodelElementCollection" - } - ] - } - }, - "required": [ - "value" - ] - }, - "SubmodelElement": { - "allOf": [ - { - "$ref": "#/definitions/Referable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "$ref": "#/definitions/HasSemantics" - }, - { - "$ref": "#/definitions/Qualifiable" - }, - { - "properties": { - "kind": { - "$ref": "#/definitions/ModelingKind" - } - } - } - ] - }, - "Event": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - } - ] - }, - "BasicEvent": { - "allOf": [ - { - "$ref": "#/definitions/Event" - }, - { - "properties": { - "observed": { - "$ref": "#/definitions/Reference" - } - }, - "required": [ - "observed" - ] - } - ] - }, - "EntityType": { - "type": "string", - "enum": [ - "CoManagedEntity", - "SelfManagedEntity" - ] - }, - "Entity": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "statements": { - "type": "array", - "items": { - "$ref": "#/definitions/SubmodelElement" - } - }, - "entityType": { - "$ref": "#/definitions/EntityType" - }, - "asset": { - "$ref": "#/definitions/Reference" - } - }, - "required": [ - "entityType" - ] - } - ] - }, - "View": { - "allOf": [ - { - "$ref": "#/definitions/Referable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "$ref": "#/definitions/HasSemantics" - }, - { - "properties": { - "containedElements": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - } - } - } - ] - }, - "ConceptDictionary": { - "allOf": [ - { - "$ref": "#/definitions/Referable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "properties": { - "conceptDescriptions": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - } - } - } - ] - }, - "ConceptDescription": { - "allOf": [ - { - "$ref": "#/definitions/Identifiable" - }, - { - "$ref": "#/definitions/HasDataSpecification" - }, - { - "properties": { - "isCaseOf": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - } - } - } - ] - }, - "Capability": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - } - ] - }, - "Property": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "$ref": "#/definitions/ValueObject" - } - ] - }, - "Range": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "valueType": { - "type": "string", - "enum": [ - "anyUri", - "base64Binary", - "boolean", - "date", - "dateTime", - "dateTimeStamp", - "decimal", - "integer", - "long", - "int", - "short", - "byte", - "nonNegativeInteger", - "positiveInteger", - "unsignedLong", - "unsignedInt", - "unsignedShort", - "unsignedByte", - "nonPositiveInteger", - "negativeInteger", - "double", - "duration", - "dayTimeDuration", - "yearMonthDuration", - "float", - "gDay", - "gMonth", - "gMonthDay", - "gYear", - "gYearMonth", - "hexBinary", - "NOTATION", - "QName", - "string", - "normalizedString", - "token", - "language", - "Name", - "NCName", - "ENTITY", - "ID", - "IDREF", - "NMTOKEN", - "time" - ] - }, - "min": { - "type": "string" - }, - "max": { - "type": "string" - } - }, - "required": [ - "valueType" - ] - } - ] - }, - "MultiLanguageProperty": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/LangString" - } - }, - "valueId": { - "$ref": "#/definitions/Reference" - } - } - } - ] - }, - "File": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "value": { - "type": "string" - }, - "mimeType": { - "type": "string" - } - }, - "required": [ - "mimeType" - ] - } - ] - }, - "Blob": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "value": { - "type": "string" - }, - "mimeType": { - "type": "string" - } - }, - "required": [ - "mimeType" - ] - } - ] - }, - "ReferenceElement": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "value": { - "$ref": "#/definitions/Reference" - } - } - } - ] - }, - "SubmodelElementCollection": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "value": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Blob" - }, - { - "$ref": "#/definitions/File" - }, - { - "$ref": "#/definitions/Capability" - }, - { - "$ref": "#/definitions/Entity" - }, - { - "$ref": "#/definitions/Event" - }, - { - "$ref": "#/definitions/BasicEvent" - }, - { - "$ref": "#/definitions/MultiLanguageProperty" - }, - { - "$ref": "#/definitions/Operation" - }, - { - "$ref": "#/definitions/Property" - }, - { - "$ref": "#/definitions/Range" - }, - { - "$ref": "#/definitions/ReferenceElement" - }, - { - "$ref": "#/definitions/RelationshipElement" - }, - { - "$ref": "#/definitions/SubmodelElementCollection" - } - ] - } - }, - "allowDuplicates": { - "type": "boolean" - }, - "ordered": { - "type": "boolean" - } - } - } - ] - }, - "RelationshipElement": { - "allOf": [ - { - "$ref": "#/definitions/SubmodelElement" - }, - { - "properties": { - "first": { - "$ref": "#/definitions/Reference" - }, - "second": { - "$ref": "#/definitions/Reference" - } - }, - "required": [ - "first", - "second" - ] - } - ] - }, - "AnnotatedRelationshipElement": { - "allOf": [ - { - "$ref": "#/definitions/RelationshipElement" - }, - { - "properties": { - "annotation": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Blob" - }, - { - "$ref": "#/definitions/File" - }, - { - "$ref": "#/definitions/MultiLanguageProperty" - }, - { - "$ref": "#/definitions/Property" - }, - { - "$ref": "#/definitions/Range" - }, - { - "$ref": "#/definitions/ReferenceElement" - } - ] - } - } - } - } - ] - }, - "Qualifier": { - "allOf": [ - { - "$ref": "#/definitions/Constraint" - }, - { - "$ref": "#/definitions/HasSemantics" - }, - { - "$ref": "#/definitions/ValueObject" - }, - { - "properties": { - "type": { - "type": "string" - } - }, - "required": [ - "type" - ] - } - ] - }, - "Formula": { - "allOf": [ - { - "$ref": "#/definitions/Constraint" - }, - { - "properties": { - "dependsOn": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - } - } - } - ] - }, - "Security": { - "type": "object", - "properties": { - "accessControlPolicyPoints": { - "$ref": "#/definitions/AccessControlPolicyPoints" - }, - "certificate": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/BlobCertificate" - } - ] - } - }, - "requiredCertificateExtension": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - } - }, - "required": [ - "accessControlPolicyPoints" - ] - }, - "Certificate": { - "type": "object" - }, - "BlobCertificate": { - "allOf": [ - { - "$ref": "#/definitions/Certificate" - }, - { - "properties": { - "blobCertificate": { - "$ref": "#/definitions/Blob" - }, - "containedExtension": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - }, - "lastCertificate": { - "type": "boolean" - } - } - } - ] - }, - "AccessControlPolicyPoints": { - "type": "object", - "properties": { - "policyAdministrationPoint": { - "$ref": "#/definitions/PolicyAdministrationPoint" - }, - "policyDecisionPoint": { - "$ref": "#/definitions/PolicyDecisionPoint" - }, - "policyEnforcementPoint": { - "$ref": "#/definitions/PolicyEnforcementPoint" - }, - "policyInformationPoints": { - "$ref": "#/definitions/PolicyInformationPoints" - } - }, - "required": [ - "policyAdministrationPoint", - "policyDecisionPoint", - "policyEnforcementPoint" - ] - }, - "PolicyAdministrationPoint": { - "type": "object", - "properties": { - "localAccessControl": { - "$ref": "#/definitions/AccessControl" - }, - "externalAccessControl": { - "type": "boolean" - } - }, - "required": [ - "externalAccessControl" - ] - }, - "PolicyInformationPoints": { - "type": "object", - "properties": { - "internalInformationPoint": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - } - }, - "externalInformationPoint": { - "type": "boolean" - } - }, - "required": [ - "externalInformationPoint" - ] - }, - "PolicyEnforcementPoint": { - "type": "object", - "properties": { - "externalPolicyEnforcementPoint": { - "type": "boolean" - } - }, - "required": [ - "externalPolicyEnforcementPoint" - ] - }, - "PolicyDecisionPoint": { - "type": "object", - "properties": { - "externalPolicyDecisionPoints": { - "type": "boolean" - } - }, - "required": [ - "externalPolicyDecisionPoints" - ] - }, - "AccessControl": { - "type": "object", - "properties": { - "selectableSubjectAttributes": { - "$ref": "#/definitions/Reference" - }, - "defaultSubjectAttributes": { - "$ref": "#/definitions/Reference" - }, - "selectablePermissions": { - "$ref": "#/definitions/Reference" - }, - "defaultPermissions": { - "$ref": "#/definitions/Reference" - }, - "selectableEnvironmentAttributes": { - "$ref": "#/definitions/Reference" - }, - "defaultEnvironmentAttributes": { - "$ref": "#/definitions/Reference" - }, - "accessPermissionRule": { - "type": "array", - "items": { - "$ref": "#/definitions/AccessPermissionRule" - } - } - } - }, - "AccessPermissionRule": { - "allOf": [ - { - "$ref": "#/definitions/Referable" - }, - { - "$ref": "#/definitions/Qualifiable" - }, - { - "properties": { - "targetSubjectAttributes": { - "type": "array", - "items": { - "$ref": "#/definitions/SubjectAttributes" - }, - "minItems": 1 - }, - "permissionsPerObject": { - "type": "array", - "items": { - "$ref": "#/definitions/PermissionsPerObject" - } - } - }, - "required": [ - "targetSubjectAttributes" - ] - } - ] - }, - "SubjectAttributes": { - "type": "object", - "properties": { - "subjectAttributes": { - "type": "array", - "items": { - "$ref": "#/definitions/Reference" - }, - "minItems": 1 - } - } - }, - "PermissionsPerObject": { - "type": "object", - "properties": { - "object": { - "$ref": "#/definitions/Reference" - }, - "targetObjectAttributes": { - "$ref": "#/definitions/ObjectAttributes" - }, - "permission": { - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - } - } - }, - "ObjectAttributes": { - "type": "object", - "properties": { - "objectAttribute": { - "type": "array", - "items": { - "$ref": "#/definitions/Property" - }, - "minItems": 1 - } - } - }, - "Permission": { - "type": "object", - "properties": { - "permission": { - "$ref": "#/definitions/Reference" - }, - "kindOfPermission": { - "type": "string", - "enum": [ - "Allow", - "Deny", - "NotApplicable", - "Undefined" - ] - } - }, - "required": [ - "permission", - "kindOfPermission" - ] - } - } + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "AssetAdministrationShellEnvironment", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/Environment" + } + ], + "$id": "https://admin-shell.io/aas/3/0", + "definitions": { + "AasSubmodelElements": { + "type": "string", + "enum": [ + "AnnotatedRelationshipElement", + "BasicEventElement", + "Blob", + "Capability", + "DataElement", + "Entity", + "EventElement", + "File", + "MultiLanguageProperty", + "Operation", + "Property", + "Range", + "ReferenceElement", + "RelationshipElement", + "SubmodelElement", + "SubmodelElementCollection", + "SubmodelElementList" + ] + }, + "AbstractLangString": { + "type": "object", + "properties": { + "language": { + "type": "string", + "pattern": "^(([a-zA-Z]{2,3}(-[a-zA-Z]{3}(-[a-zA-Z]{3}){2})?|[a-zA-Z]{4}|[a-zA-Z]{5,8})(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-(([a-zA-Z0-9]){5,8}|[0-9]([a-zA-Z0-9]){3}))*(-[0-9A-WY-Za-wy-z](-([a-zA-Z0-9]){2,8})+)*(-[xX](-([a-zA-Z0-9]){1,8})+)?|[xX](-([a-zA-Z0-9]){1,8})+|((en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)))$" + }, + "text": { + "type": "string", + "minLength": 1, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + } + }, + "required": [ + "language", + "text" + ] + }, + "AdministrativeInformation": { + "allOf": [ + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "properties": { + "version": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 4 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^(0|[1-9][0-9]*)$" + } + ] + }, + "revision": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 4 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^(0|[1-9][0-9]*)$" + } + ] + }, + "creator": { + "$ref": "#/definitions/Reference" + }, + "templateId": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + } + } + } + ] + }, + "AnnotatedRelationshipElement": { + "allOf": [ + { + "$ref": "#/definitions/RelationshipElement_abstract" + }, + { + "properties": { + "annotations": { + "type": "array", + "items": { + "$ref": "#/definitions/DataElement_choice" + }, + "minItems": 1 + }, + "modelType": { + "const": "AnnotatedRelationshipElement" + } + } + } + ] + }, + "AssetAdministrationShell": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "properties": { + "derivedFrom": { + "$ref": "#/definitions/Reference" + }, + "assetInformation": { + "$ref": "#/definitions/AssetInformation" + }, + "submodels": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + }, + "minItems": 1 + }, + "modelType": { + "const": "AssetAdministrationShell" + } + }, + "required": [ + "assetInformation" + ] + } + ] + }, + "AssetInformation": { + "type": "object", + "properties": { + "assetKind": { + "$ref": "#/definitions/AssetKind" + }, + "globalAssetId": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "specificAssetIds": { + "type": "array", + "items": { + "$ref": "#/definitions/SpecificAssetId" + }, + "minItems": 1 + }, + "assetType": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "defaultThumbnail": { + "$ref": "#/definitions/Resource" + } + }, + "required": [ + "assetKind" + ] + }, + "AssetKind": { + "type": "string", + "enum": [ + "Instance", + "NotApplicable", + "Type" + ] + }, + "BasicEventElement": { + "allOf": [ + { + "$ref": "#/definitions/EventElement" + }, + { + "properties": { + "observed": { + "$ref": "#/definitions/Reference" + }, + "direction": { + "$ref": "#/definitions/Direction" + }, + "state": { + "$ref": "#/definitions/StateOfEvent" + }, + "messageTopic": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "messageBroker": { + "$ref": "#/definitions/Reference" + }, + "lastUpdate": { + "type": "string", + "pattern": "^-?(([1-9][0-9][0-9][0-9]+)|(0[0-9][0-9][0-9]))-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))T(((([01][0-9])|(2[0-3])):[0-5][0-9]:([0-5][0-9])(\\.[0-9]+)?)|24:00:00(\\.0+)?)(Z|\\+00:00|-00:00)$" + }, + "minInterval": { + "type": "string", + "pattern": "^-?P((([0-9]+Y([0-9]+M)?([0-9]+D)?|([0-9]+M)([0-9]+D)?|([0-9]+D))(T(([0-9]+H)([0-9]+M)?([0-9]+(\\.[0-9]+)?S)?|([0-9]+M)([0-9]+(\\.[0-9]+)?S)?|([0-9]+(\\.[0-9]+)?S)))?)|(T(([0-9]+H)([0-9]+M)?([0-9]+(\\.[0-9]+)?S)?|([0-9]+M)([0-9]+(\\.[0-9]+)?S)?|([0-9]+(\\.[0-9]+)?S))))$" + }, + "maxInterval": { + "type": "string", + "pattern": "^-?P((([0-9]+Y([0-9]+M)?([0-9]+D)?|([0-9]+M)([0-9]+D)?|([0-9]+D))(T(([0-9]+H)([0-9]+M)?([0-9]+(\\.[0-9]+)?S)?|([0-9]+M)([0-9]+(\\.[0-9]+)?S)?|([0-9]+(\\.[0-9]+)?S)))?)|(T(([0-9]+H)([0-9]+M)?([0-9]+(\\.[0-9]+)?S)?|([0-9]+M)([0-9]+(\\.[0-9]+)?S)?|([0-9]+(\\.[0-9]+)?S))))$" + }, + "modelType": { + "const": "BasicEventElement" + } + }, + "required": [ + "observed", + "direction", + "state" + ] + } + ] + }, + "Blob": { + "allOf": [ + { + "$ref": "#/definitions/DataElement" + }, + { + "properties": { + "value": { + "type": "string", + "contentEncoding": "base64" + }, + "contentType": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 100 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+/([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+([ \\t]*;[ \\t]*([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+=(([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+|\"(([\\t !#-\\[\\]-~]|[\u0080-\u00ff])|\\\\([\\t !-~]|[\u0080-\u00ff]))*\"))*$" + } + ] + }, + "modelType": { + "const": "Blob" + } + }, + "required": [ + "contentType" + ] + } + ] + }, + "Capability": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "modelType": { + "const": "Capability" + } + } + } + ] + }, + "ConceptDescription": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "properties": { + "isCaseOf": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + }, + "minItems": 1 + }, + "modelType": { + "const": "ConceptDescription" + } + } + } + ] + }, + "DataElement": { + "$ref": "#/definitions/SubmodelElement" + }, + "DataElement_choice": { + "oneOf": [ + { + "$ref": "#/definitions/Blob" + }, + { + "$ref": "#/definitions/File" + }, + { + "$ref": "#/definitions/MultiLanguageProperty" + }, + { + "$ref": "#/definitions/Property" + }, + { + "$ref": "#/definitions/Range" + }, + { + "$ref": "#/definitions/ReferenceElement" + } + ] + }, + "DataSpecificationContent": { + "type": "object", + "properties": { + "modelType": { + "$ref": "#/definitions/ModelType" + } + }, + "required": [ + "modelType" + ] + }, + "DataSpecificationContent_choice": { + "oneOf": [ + { + "$ref": "#/definitions/DataSpecificationIec61360" + } + ] + }, + "DataSpecificationIec61360": { + "allOf": [ + { + "$ref": "#/definitions/DataSpecificationContent" + }, + { + "properties": { + "preferredName": { + "type": "array", + "items": { + "$ref": "#/definitions/LangStringPreferredNameTypeIec61360" + }, + "minItems": 1 + }, + "shortName": { + "type": "array", + "items": { + "$ref": "#/definitions/LangStringShortNameTypeIec61360" + }, + "minItems": 1 + }, + "unit": { + "type": "string", + "minLength": 1, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "unitId": { + "$ref": "#/definitions/Reference" + }, + "sourceOfDefinition": { + "type": "string", + "minLength": 1, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "symbol": { + "type": "string", + "minLength": 1, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "dataType": { + "$ref": "#/definitions/DataTypeIec61360" + }, + "definition": { + "type": "array", + "items": { + "$ref": "#/definitions/LangStringDefinitionTypeIec61360" + }, + "minItems": 1 + }, + "valueFormat": { + "type": "string", + "minLength": 1, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "valueList": { + "$ref": "#/definitions/ValueList" + }, + "value": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "levelType": { + "$ref": "#/definitions/LevelType" + }, + "modelType": { + "const": "DataSpecificationIec61360" + } + }, + "required": [ + "preferredName" + ] + } + ] + }, + "DataTypeDefXsd": { + "type": "string", + "enum": [ + "xs:anyURI", + "xs:base64Binary", + "xs:boolean", + "xs:byte", + "xs:date", + "xs:dateTime", + "xs:decimal", + "xs:double", + "xs:duration", + "xs:float", + "xs:gDay", + "xs:gMonth", + "xs:gMonthDay", + "xs:gYear", + "xs:gYearMonth", + "xs:hexBinary", + "xs:int", + "xs:integer", + "xs:long", + "xs:negativeInteger", + "xs:nonNegativeInteger", + "xs:nonPositiveInteger", + "xs:positiveInteger", + "xs:short", + "xs:string", + "xs:time", + "xs:unsignedByte", + "xs:unsignedInt", + "xs:unsignedLong", + "xs:unsignedShort" + ] + }, + "DataTypeIec61360": { + "type": "string", + "enum": [ + "BLOB", + "BOOLEAN", + "DATE", + "FILE", + "HTML", + "INTEGER_COUNT", + "INTEGER_CURRENCY", + "INTEGER_MEASURE", + "IRDI", + "IRI", + "RATIONAL", + "RATIONAL_MEASURE", + "REAL_COUNT", + "REAL_CURRENCY", + "REAL_MEASURE", + "STRING", + "STRING_TRANSLATABLE", + "TIME", + "TIMESTAMP" + ] + }, + "Direction": { + "type": "string", + "enum": [ + "input", + "output" + ] + }, + "EmbeddedDataSpecification": { + "type": "object", + "properties": { + "dataSpecification": { + "$ref": "#/definitions/Reference" + }, + "dataSpecificationContent": { + "$ref": "#/definitions/DataSpecificationContent_choice" + } + }, + "required": [ + "dataSpecification", + "dataSpecificationContent" + ] + }, + "Entity": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "statements": { + "type": "array", + "items": { + "$ref": "#/definitions/SubmodelElement_choice" + }, + "minItems": 1 + }, + "entityType": { + "$ref": "#/definitions/EntityType" + }, + "globalAssetId": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "specificAssetIds": { + "type": "array", + "items": { + "$ref": "#/definitions/SpecificAssetId" + }, + "minItems": 1 + }, + "modelType": { + "const": "Entity" + } + }, + "required": [ + "entityType" + ] + } + ] + }, + "EntityType": { + "type": "string", + "enum": [ + "CoManagedEntity", + "SelfManagedEntity" + ] + }, + "Environment": { + "type": "object", + "properties": { + "assetAdministrationShells": { + "type": "array", + "items": { + "$ref": "#/definitions/AssetAdministrationShell" + }, + "minItems": 1 + }, + "submodels": { + "type": "array", + "items": { + "$ref": "#/definitions/Submodel" + }, + "minItems": 1 + }, + "conceptDescriptions": { + "type": "array", + "items": { + "$ref": "#/definitions/ConceptDescription" + }, + "minItems": 1 + } + } + }, + "EventElement": { + "$ref": "#/definitions/SubmodelElement" + }, + "EventPayload": { + "type": "object", + "properties": { + "source": { + "$ref": "#/definitions/Reference" + }, + "sourceSemanticId": { + "$ref": "#/definitions/Reference" + }, + "observableReference": { + "$ref": "#/definitions/Reference" + }, + "observableSemanticId": { + "$ref": "#/definitions/Reference" + }, + "topic": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "subjectId": { + "$ref": "#/definitions/Reference" + }, + "timeStamp": { + "type": "string", + "pattern": "^-?(([1-9][0-9][0-9][0-9]+)|(0[0-9][0-9][0-9]))-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))T(((([01][0-9])|(2[0-3])):[0-5][0-9]:([0-5][0-9])(\\.[0-9]+)?)|24:00:00(\\.0+)?)(Z|\\+00:00|-00:00)$" + }, + "payload": { + "type": "string", + "contentEncoding": "base64" + } + }, + "required": [ + "source", + "observableReference", + "timeStamp" + ] + }, + "Extension": { + "allOf": [ + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "valueType": { + "$ref": "#/definitions/DataTypeDefXsd" + }, + "value": { + "type": "string" + }, + "refersTo": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + }, + "minItems": 1 + } + }, + "required": [ + "name" + ] + } + ] + }, + "File": { + "allOf": [ + { + "$ref": "#/definitions/DataElement" + }, + { + "properties": { + "value": { + "type": "string" + }, + "contentType": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 100 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+/([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+([ \\t]*;[ \\t]*([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+=(([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+|\"(([\\t !#-\\[\\]-~]|[\u0080-\u00ff])|\\\\([\\t !-~]|[\u0080-\u00ff]))*\"))*$" + } + ] + }, + "modelType": { + "const": "File" + } + }, + "required": [ + "contentType" + ] + } + ] + }, + "HasDataSpecification": { + "type": "object", + "properties": { + "embeddedDataSpecifications": { + "type": "array", + "items": { + "$ref": "#/definitions/EmbeddedDataSpecification" + }, + "minItems": 1 + } + } + }, + "HasExtensions": { + "type": "object", + "properties": { + "extensions": { + "type": "array", + "items": { + "$ref": "#/definitions/Extension" + }, + "minItems": 1 + } + } + }, + "HasKind": { + "type": "object", + "properties": { + "kind": { + "$ref": "#/definitions/ModellingKind" + } + } + }, + "HasSemantics": { + "type": "object", + "properties": { + "semanticId": { + "$ref": "#/definitions/Reference" + }, + "supplementalSemanticIds": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + }, + "minItems": 1 + } + } + }, + "Identifiable": { + "allOf": [ + { + "$ref": "#/definitions/Referable" + }, + { + "properties": { + "administration": { + "$ref": "#/definitions/AdministrativeInformation" + }, + "id": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + } + }, + "required": [ + "id" + ] + } + ] + }, + "Key": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/KeyTypes" + }, + "value": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + } + }, + "required": [ + "type", + "value" + ] + }, + "KeyTypes": { + "type": "string", + "enum": [ + "AnnotatedRelationshipElement", + "AssetAdministrationShell", + "BasicEventElement", + "Blob", + "Capability", + "ConceptDescription", + "DataElement", + "Entity", + "EventElement", + "File", + "FragmentReference", + "GlobalReference", + "Identifiable", + "MultiLanguageProperty", + "Operation", + "Property", + "Range", + "Referable", + "ReferenceElement", + "RelationshipElement", + "Submodel", + "SubmodelElement", + "SubmodelElementCollection", + "SubmodelElementList" + ] + }, + "LangStringDefinitionTypeIec61360": { + "allOf": [ + { + "$ref": "#/definitions/AbstractLangString" + }, + { + "properties": { + "text": { + "maxLength": 1023 + } + } + } + ] + }, + "LangStringNameType": { + "allOf": [ + { + "$ref": "#/definitions/AbstractLangString" + }, + { + "properties": { + "text": { + "maxLength": 128 + } + } + } + ] + }, + "LangStringPreferredNameTypeIec61360": { + "allOf": [ + { + "$ref": "#/definitions/AbstractLangString" + }, + { + "properties": { + "text": { + "maxLength": 255 + } + } + } + ] + }, + "LangStringShortNameTypeIec61360": { + "allOf": [ + { + "$ref": "#/definitions/AbstractLangString" + }, + { + "properties": { + "text": { + "maxLength": 18 + } + } + } + ] + }, + "LangStringTextType": { + "allOf": [ + { + "$ref": "#/definitions/AbstractLangString" + }, + { + "properties": { + "text": { + "maxLength": 1023 + } + } + } + ] + }, + "LevelType": { + "type": "object", + "properties": { + "min": { + "type": "boolean" + }, + "nom": { + "type": "boolean" + }, + "typ": { + "type": "boolean" + }, + "max": { + "type": "boolean" + } + }, + "required": [ + "min", + "nom", + "typ", + "max" + ] + }, + "ModelType": { + "type": "string", + "enum": [ + "AnnotatedRelationshipElement", + "AssetAdministrationShell", + "BasicEventElement", + "Blob", + "Capability", + "ConceptDescription", + "DataSpecificationIec61360", + "Entity", + "File", + "MultiLanguageProperty", + "Operation", + "Property", + "Range", + "ReferenceElement", + "RelationshipElement", + "Submodel", + "SubmodelElementCollection", + "SubmodelElementList" + ] + }, + "ModellingKind": { + "type": "string", + "enum": [ + "Instance", + "Template" + ] + }, + "MultiLanguageProperty": { + "allOf": [ + { + "$ref": "#/definitions/DataElement" + }, + { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/LangStringTextType" + }, + "minItems": 1 + }, + "valueId": { + "$ref": "#/definitions/Reference" + }, + "modelType": { + "const": "MultiLanguageProperty" + } + } + } + ] + }, + "Operation": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "inputVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/OperationVariable" + }, + "minItems": 1 + }, + "outputVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/OperationVariable" + }, + "minItems": 1 + }, + "inoutputVariables": { + "type": "array", + "items": { + "$ref": "#/definitions/OperationVariable" + }, + "minItems": 1 + }, + "modelType": { + "const": "Operation" + } + } + } + ] + }, + "OperationVariable": { + "type": "object", + "properties": { + "value": { + "$ref": "#/definitions/SubmodelElement_choice" + } + }, + "required": [ + "value" + ] + }, + "Property": { + "allOf": [ + { + "$ref": "#/definitions/DataElement" + }, + { + "properties": { + "valueType": { + "$ref": "#/definitions/DataTypeDefXsd" + }, + "value": { + "type": "string" + }, + "valueId": { + "$ref": "#/definitions/Reference" + }, + "modelType": { + "const": "Property" + } + }, + "required": [ + "valueType" + ] + } + ] + }, + "Qualifiable": { + "type": "object", + "properties": { + "qualifiers": { + "type": "array", + "items": { + "$ref": "#/definitions/Qualifier" + }, + "minItems": 1 + }, + "modelType": { + "$ref": "#/definitions/ModelType" + } + }, + "required": [ + "modelType" + ] + }, + "Qualifier": { + "allOf": [ + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "kind": { + "$ref": "#/definitions/QualifierKind" + }, + "type": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "valueType": { + "$ref": "#/definitions/DataTypeDefXsd" + }, + "value": { + "type": "string" + }, + "valueId": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "type", + "valueType" + ] + } + ] + }, + "QualifierKind": { + "type": "string", + "enum": [ + "ConceptQualifier", + "TemplateQualifier", + "ValueQualifier" + ] + }, + "Range": { + "allOf": [ + { + "$ref": "#/definitions/DataElement" + }, + { + "properties": { + "valueType": { + "$ref": "#/definitions/DataTypeDefXsd" + }, + "min": { + "type": "string" + }, + "max": { + "type": "string" + }, + "modelType": { + "const": "Range" + } + }, + "required": [ + "valueType" + ] + } + ] + }, + "Referable": { + "allOf": [ + { + "$ref": "#/definitions/HasExtensions" + }, + { + "properties": { + "category": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "idShort": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 128 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$" + } + ] + }, + "displayName": { + "type": "array", + "items": { + "$ref": "#/definitions/LangStringNameType" + }, + "minItems": 1 + }, + "description": { + "type": "array", + "items": { + "$ref": "#/definitions/LangStringTextType" + }, + "minItems": 1 + }, + "modelType": { + "$ref": "#/definitions/ModelType" + } + }, + "required": [ + "modelType" + ] + } + ] + }, + "Reference": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/ReferenceTypes" + }, + "referredSemanticId": { + "$ref": "#/definitions/Reference" + }, + "keys": { + "type": "array", + "items": { + "$ref": "#/definitions/Key" + }, + "minItems": 1 + } + }, + "required": [ + "type", + "keys" + ] + }, + "ReferenceElement": { + "allOf": [ + { + "$ref": "#/definitions/DataElement" + }, + { + "properties": { + "value": { + "$ref": "#/definitions/Reference" + }, + "modelType": { + "const": "ReferenceElement" + } + } + } + ] + }, + "ReferenceTypes": { + "type": "string", + "enum": [ + "ExternalReference", + "ModelReference" + ] + }, + "RelationshipElement": { + "allOf": [ + { + "$ref": "#/definitions/RelationshipElement_abstract" + }, + { + "properties": { + "modelType": { + "const": "RelationshipElement" + } + } + } + ] + }, + "RelationshipElement_abstract": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "first": { + "$ref": "#/definitions/Reference" + }, + "second": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "first", + "second" + ] + } + ] + }, + "RelationshipElement_choice": { + "oneOf": [ + { + "$ref": "#/definitions/RelationshipElement" + }, + { + "$ref": "#/definitions/AnnotatedRelationshipElement" + } + ] + }, + "Resource": { + "type": "object", + "properties": { + "path": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 2000 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^file:(//((localhost|(\\[((([0-9A-Fa-f]{1,4}:){6}([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::([0-9A-Fa-f]{1,4}:){5}([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|([0-9A-Fa-f]{1,4})?::([0-9A-Fa-f]{1,4}:){4}([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})?::([0-9A-Fa-f]{1,4}:){3}([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(([0-9A-Fa-f]{1,4}:){2}[0-9A-Fa-f]{1,4})?::([0-9A-Fa-f]{1,4}:){2}([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(([0-9A-Fa-f]{1,4}:){3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(([0-9A-Fa-f]{1,4}:){4}[0-9A-Fa-f]{1,4})?::([0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(([0-9A-Fa-f]{1,4}:){5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(([0-9A-Fa-f]{1,4}:){6}[0-9A-Fa-f]{1,4})?::)|[vV][0-9A-Fa-f]+\\.([a-zA-Z0-9\\-._~]|[!$&'()*+,;=]|:)+)\\]|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|([a-zA-Z0-9\\-._~]|%[0-9A-Fa-f][0-9A-Fa-f]|[!$&'()*+,;=])*)))?/((([a-zA-Z0-9\\-._~]|%[0-9A-Fa-f][0-9A-Fa-f]|[!$&'()*+,;=]|[:@]))+(/(([a-zA-Z0-9\\-._~]|%[0-9A-Fa-f][0-9A-Fa-f]|[!$&'()*+,;=]|[:@]))*)*)?|/((([a-zA-Z0-9\\-._~]|%[0-9A-Fa-f][0-9A-Fa-f]|[!$&'()*+,;=]|[:@]))+(/(([a-zA-Z0-9\\-._~]|%[0-9A-Fa-f][0-9A-Fa-f]|[!$&'()*+,;=]|[:@]))*)*)?)$" + } + ] + }, + "contentType": { + "type": "string", + "allOf": [ + { + "minLength": 1, + "maxLength": 100 + }, + { + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + { + "pattern": "^([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+/([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+([ \\t]*;[ \\t]*([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+=(([!#$%&'*+\\-.^_`|~0-9a-zA-Z])+|\"(([\\t !#-\\[\\]-~]|[\u0080-\u00ff])|\\\\([\\t !-~]|[\u0080-\u00ff]))*\"))*$" + } + ] + } + }, + "required": [ + "path" + ] + }, + "SpecificAssetId": { + "allOf": [ + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "value": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "externalSubjectId": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "name", + "value" + ] + } + ] + }, + "StateOfEvent": { + "type": "string", + "enum": [ + "off", + "on" + ] + }, + "Submodel": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasKind" + }, + { + "$ref": "#/definitions/HasSemantics" + }, + { + "$ref": "#/definitions/Qualifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "properties": { + "submodelElements": { + "type": "array", + "items": { + "$ref": "#/definitions/SubmodelElement_choice" + }, + "minItems": 1 + }, + "modelType": { + "const": "Submodel" + } + } + } + ] + }, + "SubmodelElement": { + "allOf": [ + { + "$ref": "#/definitions/Referable" + }, + { + "$ref": "#/definitions/HasSemantics" + }, + { + "$ref": "#/definitions/Qualifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + } + ] + }, + "SubmodelElementCollection": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/SubmodelElement_choice" + }, + "minItems": 1 + }, + "modelType": { + "const": "SubmodelElementCollection" + } + } + } + ] + }, + "SubmodelElementList": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "orderRelevant": { + "type": "boolean" + }, + "semanticIdListElement": { + "$ref": "#/definitions/Reference" + }, + "typeValueListElement": { + "$ref": "#/definitions/AasSubmodelElements" + }, + "valueTypeListElement": { + "$ref": "#/definitions/DataTypeDefXsd" + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/SubmodelElement_choice" + }, + "minItems": 1 + }, + "modelType": { + "const": "SubmodelElementList" + } + }, + "required": [ + "typeValueListElement" + ] + } + ] + }, + "SubmodelElement_choice": { + "oneOf": [ + { + "$ref": "#/definitions/RelationshipElement" + }, + { + "$ref": "#/definitions/AnnotatedRelationshipElement" + }, + { + "$ref": "#/definitions/BasicEventElement" + }, + { + "$ref": "#/definitions/Blob" + }, + { + "$ref": "#/definitions/Capability" + }, + { + "$ref": "#/definitions/Entity" + }, + { + "$ref": "#/definitions/File" + }, + { + "$ref": "#/definitions/MultiLanguageProperty" + }, + { + "$ref": "#/definitions/Operation" + }, + { + "$ref": "#/definitions/Property" + }, + { + "$ref": "#/definitions/Range" + }, + { + "$ref": "#/definitions/ReferenceElement" + }, + { + "$ref": "#/definitions/SubmodelElementCollection" + }, + { + "$ref": "#/definitions/SubmodelElementList" + } + ] + }, + "ValueList": { + "type": "object", + "properties": { + "valueReferencePairs": { + "type": "array", + "items": { + "$ref": "#/definitions/ValueReferencePair" + }, + "minItems": 1 + } + }, + "required": [ + "valueReferencePairs" + ] + }, + "ValueReferencePair": { + "type": "object", + "properties": { + "value": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" + }, + "valueId": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "value", + "valueId" + ] + } + } } \ No newline at end of file diff --git a/basyx/aas/adapter/json/json_deserialization.py b/basyx/aas/adapter/json/json_deserialization.py index e5639e504..6524f4b4d 100644 --- a/basyx/aas/adapter/json/json_deserialization.py +++ b/basyx/aas/adapter/json/json_deserialization.py @@ -36,9 +36,9 @@ from typing import Dict, Callable, TypeVar, Type, List, IO, Optional, Set from basyx.aas import model -from .._generic import MODELING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_ELEMENTS_INVERSE, KEY_TYPES_INVERSE, \ - IDENTIFIER_TYPES_INVERSE, ENTITY_TYPES_INVERSE, IEC61360_DATA_TYPES_INVERSE, IEC61360_LEVEL_TYPES_INVERSE, \ - KEY_ELEMENTS_CLASSES_INVERSE +from .._generic import MODELLING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_TYPES_INVERSE, ENTITY_TYPES_INVERSE, \ + IEC61360_DATA_TYPES_INVERSE, IEC61360_LEVEL_TYPES_INVERSE, KEY_TYPES_CLASSES_INVERSE, REFERENCE_TYPES_INVERSE, \ + DIRECTION_INVERSE, STATE_OF_EVENT_INVERSE, QUALIFIER_KIND_INVERSE logger = logging.getLogger(__name__) @@ -48,6 +48,7 @@ # ############################################################################# T = TypeVar('T') +LSS = TypeVar('LSS', bound=model.LangStringSet) def _get_ts(dct: Dict[str, object], key: str, type_: Type[T]) -> T: @@ -127,13 +128,15 @@ class AASFromJsonDecoder(json.JSONDecoder): .. code-block:: python - class EnhancedAsset(model.Asset): + .. code-block:: python + + class EnhancedSubmodel(model.Submodel): pass - class EnhancedAASDecoder(AASFromJsonDecoder): + class EnhancedAASDecoder(StrictAASFromJsonDecoder): @classmethod - def _construct_asset(cls, dct): - return super()._construct_asset(dct, object_class=EnhancedAsset) + def _construct_submodel(cls, dct, object_class=EnhancedSubmodel): + return super()._construct_submodel(dct, object_class=object_class) :cvar failsafe: If `True` (the default), don't raise Exceptions for missing attributes and wrong types, but instead @@ -163,37 +166,37 @@ def object_hook(cls, dct: Dict[str, object]) -> object: # function takes a bool parameter `failsafe`, which indicates weather to log errors and skip defective objects # instead of raising an Exception. AAS_CLASS_PARSERS: Dict[str, Callable[[Dict[str, object]], object]] = { - 'Asset': cls._construct_asset, 'AssetAdministrationShell': cls._construct_asset_administration_shell, - 'View': cls._construct_view, + 'AssetInformation': cls._construct_asset_information, + 'SpecificAssetId': cls._construct_specific_asset_id, 'ConceptDescription': cls._construct_concept_description, - 'Qualifier': cls._construct_qualifier, - 'Formula': cls._construct_formula, + 'Extension': cls._construct_extension, 'Submodel': cls._construct_submodel, - 'ConceptDictionary': cls._construct_concept_dictionary, 'Capability': cls._construct_capability, 'Entity': cls._construct_entity, - 'BasicEvent': cls._construct_basic_event, + 'BasicEventElement': cls._construct_basic_event_element, 'Operation': cls._construct_operation, 'RelationshipElement': cls._construct_relationship_element, 'AnnotatedRelationshipElement': cls._construct_annotated_relationship_element, 'SubmodelElementCollection': cls._construct_submodel_element_collection, + 'SubmodelElementList': cls._construct_submodel_element_list, 'Blob': cls._construct_blob, 'File': cls._construct_file, 'MultiLanguageProperty': cls._construct_multi_language_property, 'Property': cls._construct_property, 'Range': cls._construct_range, 'ReferenceElement': cls._construct_reference_element, + 'DataSpecificationIec61360': cls._construct_data_specification_iec61360, } # Get modelType and constructor function - if not isinstance(dct['modelType'], dict) or 'name' not in dct['modelType']: + if not isinstance(dct['modelType'], str): logger.warning("JSON object has unexpected format of modelType: %s", dct['modelType']) # Even in strict mode, we consider 'modelType' attributes of wrong type as non-AAS objects instead of # raising an exception. However, the object's type will probably checked later by read_json_aas_file() or # _expect_type() return dct - model_type = dct['modelType']['name'] + model_type = dct['modelType'] if model_type not in AAS_CLASS_PARSERS: if not cls.failsafe: raise TypeError("Found JSON object with modelType=\"%s\", which is not a known AAS class" % model_type) @@ -203,7 +206,7 @@ def object_hook(cls, dct: Dict[str, object]) -> object: # Use constructor function to transform JSON representation into BaSyx Python SDK model object try: return AAS_CLASS_PARSERS[model_type](dct) - except (KeyError, TypeError) as e: + except (KeyError, TypeError, model.AASConstraintViolation) as e: error_message = "Error while trying to convert JSON object into {}: {} >>> {}".format( model_type, e, pprint.pformat(dct, depth=2, width=2**14, compact=True)) if cls.failsafe: @@ -213,7 +216,7 @@ def object_hook(cls, dct: Dict[str, object]) -> object: # constructors for complex objects will skip those items by using _expect_type(). return dct else: - raise type(e)(error_message) from e + raise (type(e) if isinstance(e, (KeyError, TypeError)) else TypeError)(error_message) from e # ################################################################################################## # Utility Methods used in constructor methods to add general attributes (from abstract base classes) @@ -229,35 +232,58 @@ def _amend_abstract_attributes(cls, obj: object, dct: Dict[str, object]) -> None :param dct: The object's dict representation from JSON """ if isinstance(obj, model.Referable): + if 'idShort' in dct: + obj.id_short = _get_ts(dct, 'idShort', str) if 'category' in dct: obj.category = _get_ts(dct, 'category', str) + if 'displayName' in dct: + obj.display_name = cls._construct_lang_string_set(_get_ts(dct, 'displayName', list), + model.MultiLanguageNameType) if 'description' in dct: - obj.description = cls._construct_lang_string_set(_get_ts(dct, 'description', list)) + obj.description = cls._construct_lang_string_set(_get_ts(dct, 'description', list), + model.MultiLanguageTextType) if isinstance(obj, model.Identifiable): - if 'idShort' in dct: - obj.id_short = _get_ts(dct, 'idShort', str) if 'administration' in dct: obj.administration = cls._construct_administrative_information(_get_ts(dct, 'administration', dict)) if isinstance(obj, model.HasSemantics): if 'semanticId' in dct: obj.semantic_id = cls._construct_reference(_get_ts(dct, 'semanticId', dict)) + if 'supplementalSemanticIds' in dct: + for ref in _get_ts(dct, 'supplementalSemanticIds', list): + obj.supplemental_semantic_id.append(cls._construct_reference(ref)) # `HasKind` provides only mandatory, immutable attributes; so we cannot do anything here, after object creation. # However, the `cls._get_kind()` function may assist by retrieving them from the JSON object if isinstance(obj, model.Qualifiable) and not cls.stripped: if 'qualifiers' in dct: - for constraint in _get_ts(dct, 'qualifiers', list): - if _expect_type(constraint, model.Constraint, str(obj), cls.failsafe): - obj.qualifier.add(constraint) - - @classmethod - def _get_kind(cls, dct: Dict[str, object]) -> model.ModelingKind: + for constraint_dct in _get_ts(dct, 'qualifiers', list): + constraint = cls._construct_qualifier(constraint_dct) + obj.qualifier.add(constraint) + if isinstance(obj, model.HasDataSpecification) and not cls.stripped: + if 'embeddedDataSpecifications' in dct: + for dspec in _get_ts(dct, 'embeddedDataSpecifications', list): + obj.embedded_data_specifications.append( + # TODO: remove the following type: ignore comment when mypy supports abstract types for Type[T] + # see https://github.com/python/mypy/issues/5374 + model.EmbeddedDataSpecification( + data_specification=cls._construct_reference(_get_ts(dspec, 'dataSpecification', dict)), + data_specification_content=_get_ts(dspec, 'dataSpecificationContent', + model.DataSpecificationContent) # type: ignore + ) + ) + if isinstance(obj, model.HasExtension) and not cls.stripped: + if 'extensions' in dct: + for extension in _get_ts(dct, 'extensions', list): + obj.extension.add(cls._construct_extension(extension)) + + @classmethod + def _get_kind(cls, dct: Dict[str, object]) -> model.ModellingKind: """ Utility method to get the kind of an HasKind object from its JSON representation. :param dct: The object's dict representation from JSON :return: The object's `kind` value """ - return MODELING_KIND_INVERSE[_get_ts(dct, "kind", str)] if 'kind' in dct else model.ModelingKind.INSTANCE + return MODELLING_KIND_INVERSE[_get_ts(dct, "kind", str)] if 'kind' in dct else model.ModellingKind.INSTANCE # ############################################################################# # Helper Constructor Methods starting from here @@ -269,74 +295,103 @@ def _get_kind(cls, dct: Dict[str, object]) -> model.ModelingKind: @classmethod def _construct_key(cls, dct: Dict[str, object], object_class=model.Key) -> model.Key: - return object_class(type_=KEY_ELEMENTS_INVERSE[_get_ts(dct, 'type', str)], - id_type=KEY_TYPES_INVERSE[_get_ts(dct, 'idType', str)], - value=_get_ts(dct, 'value', str), - local=_get_ts(dct, 'local', bool)) + return object_class(type_=KEY_TYPES_INVERSE[_get_ts(dct, 'type', str)], + value=_get_ts(dct, 'value', str)) @classmethod - def _construct_reference(cls, dct: Dict[str, object], object_class=model.Reference) -> model.Reference: + def _construct_specific_asset_id(cls, dct: Dict[str, object], object_class=model.SpecificAssetId) \ + -> model.SpecificAssetId: + # semantic_id can't be applied by _amend_abstract_attributes because specificAssetId is immutable + return object_class(name=_get_ts(dct, 'name', str), + value=_get_ts(dct, 'value', str), + external_subject_id=cls._construct_external_reference( + _get_ts(dct, 'externalSubjectId', dict)) if 'externalSubjectId' in dct else None, + semantic_id=cls._construct_reference(_get_ts(dct, 'semanticId', dict)) + if 'semanticId' in dct else None, + supplemental_semantic_id=[ + cls._construct_reference(ref) for ref in + _get_ts(dct, 'supplementalSemanticIds', list)] + if 'supplementalSemanticIds' in dct else ()) + + @classmethod + def _construct_reference(cls, dct: Dict[str, object]) -> model.Reference: + reference_type: Type[model.Reference] = REFERENCE_TYPES_INVERSE[_get_ts(dct, 'type', str)] + if reference_type is model.ModelReference: + return cls._construct_model_reference(dct, model.Referable) # type: ignore + elif reference_type is model.ExternalReference: + return cls._construct_external_reference(dct) + raise ValueError(f"Unsupported reference type {reference_type}!") + + @classmethod + def _construct_external_reference(cls, dct: Dict[str, object], object_class=model.ExternalReference)\ + -> model.ExternalReference: + reference_type: Type[model.Reference] = REFERENCE_TYPES_INVERSE[_get_ts(dct, 'type', str)] + if reference_type is not model.ExternalReference: + raise ValueError(f"Expected a reference of type {model.ExternalReference}, got {reference_type}!") keys = [cls._construct_key(key_data) for key_data in _get_ts(dct, "keys", list)] - return object_class(tuple(keys)) + return object_class(tuple(keys), cls._construct_reference(_get_ts(dct, 'referredSemanticId', dict)) + if 'referredSemanticId' in dct else None) @classmethod - def _construct_aas_reference(cls, dct: Dict[str, object], type_: Type[T], object_class=model.AASReference)\ - -> model.AASReference: + def _construct_model_reference(cls, dct: Dict[str, object], type_: Type[T], object_class=model.ModelReference)\ + -> model.ModelReference: + reference_type: Type[model.Reference] = REFERENCE_TYPES_INVERSE[_get_ts(dct, 'type', str)] + if reference_type is not model.ModelReference: + raise ValueError(f"Expected a reference of type {model.ModelReference}, got {reference_type}!") keys = [cls._construct_key(key_data) for key_data in _get_ts(dct, "keys", list)] - if keys and not issubclass(KEY_ELEMENTS_CLASSES_INVERSE.get(keys[-1].type, type(None)), type_): + if keys and not issubclass(KEY_TYPES_CLASSES_INVERSE.get(keys[-1].type, type(None)), type_): logger.warning("type %s of last key of reference to %s does not match reference type %s", keys[-1].type.name, " / ".join(str(k) for k in keys), type_.__name__) - return object_class(tuple(keys), type_) - - @classmethod - def _construct_identifier(cls, dct: Dict[str, object], object_class=model.Identifier) -> model.Identifier: - return object_class(_get_ts(dct, 'id', str), - IDENTIFIER_TYPES_INVERSE[_get_ts(dct, 'idType', str)]) + return object_class(tuple(keys), type_, cls._construct_reference(_get_ts(dct, 'referredSemanticId', dict)) + if 'referredSemanticId' in dct else None) @classmethod def _construct_administrative_information( cls, dct: Dict[str, object], object_class=model.AdministrativeInformation)\ -> model.AdministrativeInformation: ret = object_class() + cls._amend_abstract_attributes(ret, dct) if 'version' in dct: ret.version = _get_ts(dct, 'version', str) if 'revision' in dct: ret.revision = _get_ts(dct, 'revision', str) elif 'revision' in dct: logger.warning("Ignoring 'revision' attribute of AdministrativeInformation object due to missing 'version'") + if 'creator' in dct: + ret.creator = cls._construct_reference(_get_ts(dct, 'creator', dict)) + if 'templateId' in dct: + ret.template_id = _get_ts(dct, 'templateId', str) return ret @classmethod - def _construct_security(cls, _dct: Dict[str, object], object_class=model.Security) -> model.Security: - return object_class() - - @classmethod - def _construct_operation_variable( - cls, dct: Dict[str, object], object_class=model.OperationVariable) -> model.OperationVariable: + def _construct_operation_variable(cls, dct: Dict[str, object]) -> model.SubmodelElement: + """ + Since we don't implement `OperationVariable`, this constructor discards the wrapping `OperationVariable` object + and just returns the contained :class:`~aas.model.submodel.SubmodelElement`. + """ # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 - ret = object_class(value=_get_ts(dct, 'value', model.SubmodelElement)) # type: ignore - return ret + return _get_ts(dct, 'value', model.SubmodelElement) # type: ignore @classmethod - def _construct_lang_string_set(cls, lst: List[Dict[str, object]]) -> Optional[model.LangStringSet]: + def _construct_lang_string_set(cls, lst: List[Dict[str, object]], object_class: Type[LSS]) -> LSS: ret = {} for desc in lst: try: ret[_get_ts(desc, 'language', str)] = _get_ts(desc, 'text', str) except (KeyError, TypeError) as e: - error_message = "Error while trying to convert JSON object into LangString: {} >>> {}".format( - e, pprint.pformat(desc, depth=2, width=2 ** 14, compact=True)) + error_message = "Error while trying to convert JSON object into {}: {} >>> {}".format( + object_class.__name__, e, pprint.pformat(desc, depth=2, width=2 ** 14, compact=True)) if cls.failsafe: logger.error(error_message, exc_info=e) else: raise type(e)(error_message) from e - return ret + return object_class(ret) @classmethod def _construct_value_list(cls, dct: Dict[str, object]) -> model.ValueList: ret: model.ValueList = set() - for element in _get_ts(dct, 'valueReferencePairTypes', list): + for element in _get_ts(dct, 'valueReferencePairs', list): try: ret.add(cls._construct_value_reference_pair(element)) except (KeyError, TypeError) as e: @@ -349,11 +404,9 @@ def _construct_value_list(cls, dct: Dict[str, object]) -> model.ValueList: return ret @classmethod - def _construct_value_reference_pair(cls, dct: Dict[str, object], object_class=model.ValueReferencePair) -> \ - model.ValueReferencePair: - value_type = model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueType', str)] - return object_class(value_type=value_type, - value=model.datatypes.from_xsd(_get_ts(dct, 'value', str), value_type), + def _construct_value_reference_pair(cls, dct: Dict[str, object], + object_class=model.ValueReferencePair) -> model.ValueReferencePair: + return object_class(value=_get_ts(dct, 'value', str), value_id=cls._construct_reference(_get_ts(dct, 'valueId', dict))) # ############################################################################# @@ -364,68 +417,47 @@ def _construct_value_reference_pair(cls, dct: Dict[str, object], object_class=mo # be called from the object_hook() method directly. @classmethod - def _construct_asset(cls, dct: Dict[str, object], object_class=model.Asset) -> model.Asset: - ret = object_class(kind=ASSET_KIND_INVERSE[_get_ts(dct, 'kind', str)], - identification=cls._construct_identifier(_get_ts(dct, "identification", dict))) + def _construct_asset_information(cls, dct: Dict[str, object], object_class=model.AssetInformation)\ + -> model.AssetInformation: + global_asset_id = None + if 'globalAssetId' in dct: + global_asset_id = _get_ts(dct, 'globalAssetId', str) + specific_asset_id = set() + if 'specificAssetIds' in dct: + for desc_data in _get_ts(dct, "specificAssetIds", list): + specific_asset_id.add(cls._construct_specific_asset_id(desc_data, model.SpecificAssetId)) + + ret = object_class(asset_kind=ASSET_KIND_INVERSE[_get_ts(dct, 'assetKind', str)], + global_asset_id=global_asset_id, + specific_asset_id=specific_asset_id) cls._amend_abstract_attributes(ret, dct) - if 'assetIdentificationModel' in dct: - ret.asset_identification_model = cls._construct_aas_reference( - _get_ts(dct, 'assetIdentificationModel', dict), model.Submodel) - if 'billOfMaterial' in dct: - ret.bill_of_material = cls._construct_aas_reference(_get_ts(dct, 'billOfMaterial', dict), model.Submodel) + + if 'assetType' in dct: + ret.asset_type = _get_ts(dct, 'assetType', str) + if 'defaultThumbnail' in dct: + ret.default_thumbnail = cls._construct_resource(_get_ts(dct, 'defaultThumbnail', dict)) return ret @classmethod def _construct_asset_administration_shell( cls, dct: Dict[str, object], object_class=model.AssetAdministrationShell) -> model.AssetAdministrationShell: ret = object_class( - asset=cls._construct_aas_reference(_get_ts(dct, 'asset', dict), model.Asset), - identification=cls._construct_identifier(_get_ts(dct, 'identification', dict))) + asset_information=cls._construct_asset_information(_get_ts(dct, 'assetInformation', dict), + model.AssetInformation), + id_=_get_ts(dct, 'id', str)) cls._amend_abstract_attributes(ret, dct) if not cls.stripped and 'submodels' in dct: for sm_data in _get_ts(dct, 'submodels', list): - ret.submodel.add(cls._construct_aas_reference(sm_data, model.Submodel)) - if not cls.stripped and 'views' in dct: - for view in _get_ts(dct, 'views', list): - if _expect_type(view, model.View, str(ret), cls.failsafe): - ret.view.add(view) - if 'conceptDictionaries' in dct: - for concept_dictionary in _get_ts(dct, 'conceptDictionaries', list): - if _expect_type(concept_dictionary, model.ConceptDictionary, str(ret), cls.failsafe): - ret.concept_dictionary.add(concept_dictionary) - if 'security' in dct: - ret.security = cls._construct_security(_get_ts(dct, 'security', dict)) + ret.submodel.add(cls._construct_model_reference(sm_data, model.Submodel)) if 'derivedFrom' in dct: - ret.derived_from = cls._construct_aas_reference(_get_ts(dct, 'derivedFrom', dict), - model.AssetAdministrationShell) - return ret - - @classmethod - def _construct_view(cls, dct: Dict[str, object], object_class=model.View) -> model.View: - ret = object_class(_get_ts(dct, 'idShort', str)) - cls._amend_abstract_attributes(ret, dct) - if 'containedElements' in dct: - for element_data in _get_ts(dct, 'containedElements', list): - # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] - # see https://github.com/python/mypy/issues/5374 - ret.contained_element.add(cls._construct_aas_reference(element_data, model.Referable)) # type: ignore + ret.derived_from = cls._construct_model_reference(_get_ts(dct, 'derivedFrom', dict), + model.AssetAdministrationShell) return ret @classmethod def _construct_concept_description(cls, dct: Dict[str, object], object_class=model.ConceptDescription)\ -> model.ConceptDescription: - # Hack to detect IEC61360ConceptDescriptions, which are represented using dataSpecification according to DotAAS - ret = None - if 'embeddedDataSpecifications' in dct: - for dspec in _get_ts(dct, 'embeddedDataSpecifications', list): - dspec_ref = cls._construct_reference(_get_ts(dspec, 'dataSpecification', dict)) - if dspec_ref.key and (dspec_ref.key[0].value == - "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0"): - ret = cls._construct_iec61360_concept_description( - dct, _get_ts(dspec, 'dataSpecificationContent', dict)) - # If this is not a special ConceptDescription, just construct one of the default object_class - if ret is None: - ret = object_class(identification=cls._construct_identifier(_get_ts(dct, 'identification', dict))) + ret = object_class(id_=_get_ts(dct, 'id', str)) cls._amend_abstract_attributes(ret, dct) if 'isCaseOf' in dct: for case_data in _get_ts(dct, "isCaseOf", list): @@ -433,55 +465,55 @@ def _construct_concept_description(cls, dct: Dict[str, object], object_class=mod return ret @classmethod - def _construct_iec61360_concept_description(cls, dct: Dict[str, object], data_spec: Dict[str, object], - object_class=model.concept.IEC61360ConceptDescription)\ - -> model.concept.IEC61360ConceptDescription: - ret = object_class(identification=cls._construct_identifier(_get_ts(dct, 'identification', dict)), - preferred_name=cls._construct_lang_string_set(_get_ts(data_spec, 'preferredName', list))) - if 'dataType' in data_spec: - ret.data_type = IEC61360_DATA_TYPES_INVERSE[_get_ts(data_spec, 'dataType', str)] - if 'definition' in data_spec: - ret.definition = cls._construct_lang_string_set(_get_ts(data_spec, 'definition', list)) - if 'shortName' in data_spec: - ret.short_name = cls._construct_lang_string_set(_get_ts(data_spec, 'shortName', list)) - if 'unit' in data_spec: - ret.unit = _get_ts(data_spec, 'unit', str) - if 'unitId' in data_spec: - ret.unit_id = cls._construct_reference(_get_ts(data_spec, 'unitId', dict)) - if 'sourceOfDefinition' in data_spec: - ret.source_of_definition = _get_ts(data_spec, 'sourceOfDefinition', str) - if 'symbol' in data_spec: - ret.symbol = _get_ts(data_spec, 'symbol', str) - if 'valueFormat' in data_spec: - ret.value_format = model.datatypes.XSD_TYPE_CLASSES[_get_ts(data_spec, 'valueFormat', str)] - if 'valueList' in data_spec: - ret.value_list = cls._construct_value_list(_get_ts(data_spec, 'valueList', dict)) - if 'value' in data_spec: - ret.value = model.datatypes.from_xsd(_get_ts(data_spec, 'value', str), ret.value_format) - if 'valueId' in data_spec: - ret.value_id = cls._construct_reference(_get_ts(data_spec, 'valueId', dict)) - if 'levelType' in data_spec: - ret.level_types = set(IEC61360_LEVEL_TYPES_INVERSE[level_type] - for level_type in _get_ts(data_spec, 'levelType', list)) - return ret - - @classmethod - def _construct_concept_dictionary(cls, dct: Dict[str, object], object_class=model.ConceptDictionary)\ - -> model.ConceptDictionary: - ret = object_class(_get_ts(dct, "idShort", str)) - cls._amend_abstract_attributes(ret, dct) - if 'conceptDescriptions' in dct: - for desc_data in _get_ts(dct, "conceptDescriptions", list): - ret.concept_description.add(cls._construct_aas_reference(desc_data, model.ConceptDescription)) + def _construct_data_specification_iec61360(cls, dct: Dict[str, object], + object_class=model.base.DataSpecificationIEC61360)\ + -> model.base.DataSpecificationIEC61360: + ret = object_class(preferred_name=cls._construct_lang_string_set(_get_ts(dct, 'preferredName', list), + model.PreferredNameTypeIEC61360)) + if 'dataType' in dct: + ret.data_type = IEC61360_DATA_TYPES_INVERSE[_get_ts(dct, 'dataType', str)] + if 'definition' in dct: + ret.definition = cls._construct_lang_string_set(_get_ts(dct, 'definition', list), + model.DefinitionTypeIEC61360) + if 'shortName' in dct: + ret.short_name = cls._construct_lang_string_set(_get_ts(dct, 'shortName', list), + model.ShortNameTypeIEC61360) + if 'unit' in dct: + ret.unit = _get_ts(dct, 'unit', str) + if 'unitId' in dct: + ret.unit_id = cls._construct_reference(_get_ts(dct, 'unitId', dict)) + if 'sourceOfDefinition' in dct: + ret.source_of_definition = _get_ts(dct, 'sourceOfDefinition', str) + if 'symbol' in dct: + ret.symbol = _get_ts(dct, 'symbol', str) + if 'valueFormat' in dct: + ret.value_format = _get_ts(dct, 'valueFormat', str) + if 'valueList' in dct: + ret.value_list = cls._construct_value_list(_get_ts(dct, 'valueList', dict)) + if 'value' in dct: + ret.value = _get_ts(dct, 'value', str) + if 'valueId' in dct: + ret.value_id = cls._construct_reference(_get_ts(dct, 'valueId', dict)) + if 'levelType' in dct: + for k, v in _get_ts(dct, 'levelType', dict).items(): + if v: + ret.level_types.add(IEC61360_LEVEL_TYPES_INVERSE[k]) return ret @classmethod def _construct_entity(cls, dct: Dict[str, object], object_class=model.Entity) -> model.Entity: - ret = object_class(id_short=_get_ts(dct, "idShort", str), + global_asset_id = None + if 'globalAssetId' in dct: + global_asset_id = _get_ts(dct, 'globalAssetId', str) + specific_asset_id = set() + if 'specificAssetIds' in dct: + for desc_data in _get_ts(dct, "specificAssetIds", list): + specific_asset_id.add(cls._construct_specific_asset_id(desc_data, model.SpecificAssetId)) + + ret = object_class(id_short=None, entity_type=ENTITY_TYPES_INVERSE[_get_ts(dct, "entityType", str)], - asset=(cls._construct_aas_reference(_get_ts(dct, 'asset', dict), model.Asset) - if 'asset' in dct else None), - kind=cls._get_kind(dct)) + global_asset_id=global_asset_id, + specific_asset_id=specific_asset_id) cls._amend_abstract_attributes(ret, dct) if not cls.stripped and 'statements' in dct: for element in _get_ts(dct, "statements", list): @@ -498,29 +530,26 @@ def _construct_qualifier(cls, dct: Dict[str, object], object_class=model.Qualifi ret.value = model.datatypes.from_xsd(_get_ts(dct, 'value', str), ret.value_type) if 'valueId' in dct: ret.value_id = cls._construct_reference(_get_ts(dct, 'valueId', dict)) + if 'kind' in dct: + ret.kind = QUALIFIER_KIND_INVERSE[_get_ts(dct, 'kind', str)] return ret @classmethod - def _construct_formula(cls, dct: Dict[str, object], object_class=model.Formula) -> model.Formula: - ret = object_class() + def _construct_extension(cls, dct: Dict[str, object], object_class=model.Extension) -> model.Extension: + ret = object_class(name=_get_ts(dct, 'name', str)) cls._amend_abstract_attributes(ret, dct) - if 'dependsOn' in dct: - for dependency_data in _get_ts(dct, 'dependsOn', list): - try: - ret.depends_on.add(cls._construct_reference(dependency_data)) - except (KeyError, TypeError) as e: - error_message = \ - "Error while trying to convert JSON object into dependency Reference for {}: {} >>> {}".format( - ret, e, pprint.pformat(dct, depth=2, width=2 ** 14, compact=True)) - if cls.failsafe: - logger.error(error_message, exc_info=e) - else: - raise type(e)(error_message) from e + if 'valueType' in dct: + ret.value_type = model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueType', str)] + if 'value' in dct: + ret.value = model.datatypes.from_xsd(_get_ts(dct, 'value', str), ret.value_type) + if 'refersTo' in dct: + ret.refers_to = {cls._construct_model_reference(refers_to, model.Referable) # type: ignore + for refers_to in _get_ts(dct, 'refersTo', list)} return ret @classmethod def _construct_submodel(cls, dct: Dict[str, object], object_class=model.Submodel) -> model.Submodel: - ret = object_class(identification=cls._construct_identifier(_get_ts(dct, 'identification', dict)), + ret = object_class(id_=_get_ts(dct, 'id', str), kind=cls._get_kind(dct)) cls._amend_abstract_attributes(ret, dct) if not cls.stripped and 'submodelElements' in dct: @@ -531,34 +560,46 @@ def _construct_submodel(cls, dct: Dict[str, object], object_class=model.Submodel @classmethod def _construct_capability(cls, dct: Dict[str, object], object_class=model.Capability) -> model.Capability: - ret = object_class(id_short=_get_ts(dct, "idShort", str), kind=cls._get_kind(dct)) + ret = object_class(id_short=None) cls._amend_abstract_attributes(ret, dct) return ret @classmethod - def _construct_basic_event(cls, dct: Dict[str, object], object_class=model.BasicEvent) -> model.BasicEvent: + def _construct_basic_event_element(cls, dct: Dict[str, object], object_class=model.BasicEventElement) \ + -> model.BasicEventElement: # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 - ret = object_class(id_short=_get_ts(dct, "idShort", str), - observed=cls._construct_aas_reference(_get_ts(dct, 'observed', dict), - model.Referable), # type: ignore - kind=cls._get_kind(dct)) + ret = object_class(id_short=None, + observed=cls._construct_model_reference(_get_ts(dct, 'observed', dict), + model.Referable), # type: ignore + direction=DIRECTION_INVERSE[_get_ts(dct, "direction", str)], + state=STATE_OF_EVENT_INVERSE[_get_ts(dct, "state", str)]) cls._amend_abstract_attributes(ret, dct) + if 'messageTopic' in dct: + ret.message_topic = _get_ts(dct, 'messageTopic', str) + if 'messageBroker' in dct: + ret.message_broker = cls._construct_reference(_get_ts(dct, 'messageBroker', dict)) + if 'lastUpdate' in dct: + ret.last_update = model.datatypes.from_xsd(_get_ts(dct, 'lastUpdate', str), model.datatypes.DateTime) + if 'minInterval' in dct: + ret.min_interval = model.datatypes.from_xsd(_get_ts(dct, 'minInterval', str), model.datatypes.Duration) + if 'maxInterval' in dct: + ret.max_interval = model.datatypes.from_xsd(_get_ts(dct, 'maxInterval', str), model.datatypes.Duration) return ret @classmethod def _construct_operation(cls, dct: Dict[str, object], object_class=model.Operation) -> model.Operation: - ret = object_class(_get_ts(dct, "idShort", str), kind=cls._get_kind(dct)) + ret = object_class(None) cls._amend_abstract_attributes(ret, dct) # Deserialize variables (they are not Referable, thus we don't - for json_name, target in (('inputVariable', ret.input_variable), - ('outputVariable', ret.output_variable), - ('inoutputVariable', ret.in_output_variable)): + for json_name, target in (('inputVariables', ret.input_variable), + ('outputVariables', ret.output_variable), + ('inoutputVariables', ret.in_output_variable)): if json_name in dct: for variable_data in _get_ts(dct, json_name, list): try: - target.append(cls._construct_operation_variable(variable_data)) + target.add(cls._construct_operation_variable(variable_data)) except (KeyError, TypeError) as e: error_message = "Error while trying to convert JSON object into {} of {}: {}".format( json_name, ret, pprint.pformat(variable_data, depth=2, width=2 ** 14, compact=True)) @@ -573,12 +614,9 @@ def _construct_relationship_element( cls, dct: Dict[str, object], object_class=model.RelationshipElement) -> model.RelationshipElement: # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 - ret = object_class(id_short=_get_ts(dct, "idShort", str), - first=cls._construct_aas_reference(_get_ts(dct, 'first', dict), - model.Referable), # type: ignore - second=cls._construct_aas_reference(_get_ts(dct, 'second', dict), - model.Referable), # type: ignore - kind=cls._get_kind(dct)) + ret = object_class(id_short=None, + first=cls._construct_reference(_get_ts(dct, 'first', dict)), + second=cls._construct_reference(_get_ts(dct, 'second', dict))) cls._amend_abstract_attributes(ret, dct) return ret @@ -589,31 +627,21 @@ def _construct_annotated_relationship_element( # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 ret = object_class( - id_short=_get_ts(dct, "idShort", str), - first=cls._construct_aas_reference(_get_ts(dct, 'first', dict), model.Referable), # type: ignore - second=cls._construct_aas_reference(_get_ts(dct, 'second', dict), model.Referable), # type: ignore - kind=cls._get_kind(dct)) + id_short=None, + first=cls._construct_reference(_get_ts(dct, 'first', dict)), + second=cls._construct_reference(_get_ts(dct, 'second', dict))) cls._amend_abstract_attributes(ret, dct) - if not cls.stripped and 'annotation' in dct: - for element in _get_ts(dct, "annotation", list): + if not cls.stripped and 'annotations' in dct: + for element in _get_ts(dct, 'annotations', list): if _expect_type(element, model.DataElement, str(ret), cls.failsafe): ret.annotation.add(element) return ret @classmethod - def _construct_submodel_element_collection( - cls, - dct: Dict[str, object], - object_class_ordered=model.SubmodelElementCollectionOrdered, - object_class_unordered=model.SubmodelElementCollectionUnordered)\ + def _construct_submodel_element_collection(cls, dct: Dict[str, object], + object_class=model.SubmodelElementCollection)\ -> model.SubmodelElementCollection: - ret: model.SubmodelElementCollection - if 'ordered' in dct and _get_ts(dct, 'ordered', bool): - ret = object_class_ordered( - id_short=_get_ts(dct, "idShort", str), kind=cls._get_kind(dct)) - else: - ret = object_class_unordered( - id_short=_get_ts(dct, "idShort", str), kind=cls._get_kind(dct)) + ret = object_class(id_short=None) cls._amend_abstract_attributes(ret, dct) if not cls.stripped and 'value' in dct: for element in _get_ts(dct, "value", list): @@ -621,11 +649,35 @@ def _construct_submodel_element_collection( ret.value.add(element) return ret + @classmethod + def _construct_submodel_element_list(cls, dct: Dict[str, object], object_class=model.SubmodelElementList)\ + -> model.SubmodelElementList: + type_value_list_element = KEY_TYPES_CLASSES_INVERSE[ + KEY_TYPES_INVERSE[_get_ts(dct, 'typeValueListElement', str)]] + if not issubclass(type_value_list_element, model.SubmodelElement): + raise ValueError("Expected a SubmodelElementList with a typeValueListElement that is a subclass of" + f"{model.SubmodelElement}, got {type_value_list_element}!") + order_relevant = _get_ts(dct, 'orderRelevant', bool) if 'orderRelevant' in dct else True + semantic_id_list_element = cls._construct_reference(_get_ts(dct, 'semanticIdListElement', dict))\ + if 'semanticIdListElement' in dct else None + value_type_list_element = model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueTypeListElement', str)]\ + if 'valueTypeListElement' in dct else None + ret = object_class(id_short=None, + type_value_list_element=type_value_list_element, + order_relevant=order_relevant, + semantic_id_list_element=semantic_id_list_element, + value_type_list_element=value_type_list_element) + cls._amend_abstract_attributes(ret, dct) + if not cls.stripped and 'value' in dct: + for element in _get_ts(dct, 'value', list): + if _expect_type(element, type_value_list_element, str(ret), cls.failsafe): + ret.value.add(element) + return ret + @classmethod def _construct_blob(cls, dct: Dict[str, object], object_class=model.Blob) -> model.Blob: - ret = object_class(id_short=_get_ts(dct, "idShort", str), - mime_type=_get_ts(dct, "mimeType", str), - kind=cls._get_kind(dct)) + ret = object_class(id_short=None, + content_type=_get_ts(dct, "contentType", str)) cls._amend_abstract_attributes(ret, dct) if 'value' in dct: ret.value = base64.b64decode(_get_ts(dct, 'value', str)) @@ -633,31 +685,37 @@ def _construct_blob(cls, dct: Dict[str, object], object_class=model.Blob) -> mod @classmethod def _construct_file(cls, dct: Dict[str, object], object_class=model.File) -> model.File: - ret = object_class(id_short=_get_ts(dct, "idShort", str), + ret = object_class(id_short=None, value=None, - mime_type=_get_ts(dct, "mimeType", str), - kind=cls._get_kind(dct)) + content_type=_get_ts(dct, "contentType", str)) cls._amend_abstract_attributes(ret, dct) if 'value' in dct and dct['value'] is not None: ret.value = _get_ts(dct, 'value', str) return ret + @classmethod + def _construct_resource(cls, dct: Dict[str, object], object_class=model.Resource) -> model.Resource: + ret = object_class(path=_get_ts(dct, "path", str)) + cls._amend_abstract_attributes(ret, dct) + if 'contentType' in dct and dct['contentType'] is not None: + ret.content_type = _get_ts(dct, 'contentType', str) + return ret + @classmethod def _construct_multi_language_property( cls, dct: Dict[str, object], object_class=model.MultiLanguageProperty) -> model.MultiLanguageProperty: - ret = object_class(id_short=_get_ts(dct, "idShort", str), kind=cls._get_kind(dct)) + ret = object_class(id_short=None) cls._amend_abstract_attributes(ret, dct) if 'value' in dct and dct['value'] is not None: - ret.value = cls._construct_lang_string_set(_get_ts(dct, 'value', list)) + ret.value = cls._construct_lang_string_set(_get_ts(dct, 'value', list), model.MultiLanguageTextType) if 'valueId' in dct: ret.value_id = cls._construct_reference(_get_ts(dct, 'valueId', dict)) return ret @classmethod def _construct_property(cls, dct: Dict[str, object], object_class=model.Property) -> model.Property: - ret = object_class(id_short=_get_ts(dct, "idShort", str), - value_type=model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueType', str)], - kind=cls._get_kind(dct)) + ret = object_class(id_short=None, + value_type=model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueType', str)],) cls._amend_abstract_attributes(ret, dct) if 'value' in dct and dct['value'] is not None: ret.value = model.datatypes.from_xsd(_get_ts(dct, 'value', str), ret.value_type) @@ -667,9 +725,8 @@ def _construct_property(cls, dct: Dict[str, object], object_class=model.Property @classmethod def _construct_range(cls, dct: Dict[str, object], object_class=model.Range) -> model.Range: - ret = object_class(id_short=_get_ts(dct, "idShort", str), - value_type=model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueType', str)], - kind=cls._get_kind(dct)) + ret = object_class(id_short=None, + value_type=model.datatypes.XSD_TYPE_CLASSES[_get_ts(dct, 'valueType', str)],) cls._amend_abstract_attributes(ret, dct) if 'min' in dct and dct['min'] is not None: ret.min = model.datatypes.from_xsd(_get_ts(dct, 'min', str), ret.value_type) @@ -680,9 +737,8 @@ def _construct_range(cls, dct: Dict[str, object], object_class=model.Range) -> m @classmethod def _construct_reference_element( cls, dct: Dict[str, object], object_class=model.ReferenceElement) -> model.ReferenceElement: - ret = object_class(id_short=_get_ts(dct, "idShort", str), - value=None, - kind=cls._get_kind(dct)) + ret = object_class(id_short=None, + value=None) cls._amend_abstract_attributes(ret, dct) if 'value' in dct and dct['value'] is not None: ret.value = cls._construct_reference(_get_ts(dct, 'value', dict)) @@ -767,18 +823,12 @@ def read_aas_json_file_into(object_store: model.AbstractObjectStore, file: IO, r data = json.load(file, cls=decoder_) for name, expected_type in (('assetAdministrationShells', model.AssetAdministrationShell), - ('assets', model.Asset), ('submodels', model.Submodel), ('conceptDescriptions', model.ConceptDescription)): try: lst = _get_ts(data, name, list) - except (KeyError, TypeError) as e: - error_message = "Could not find list '{}' in AAS JSON file".format(name) - if decoder_.failsafe: - logger.warning(error_message) - continue - else: - raise type(e)(error_message) from e + except (KeyError, TypeError): + continue for item in lst: error_message = "Expected a {} in list '{}', but found {}".format( @@ -789,16 +839,16 @@ def read_aas_json_file_into(object_store: model.AbstractObjectStore, file: IO, r logger.warning("{} was in wrong list '{}'; nevertheless, we'll use it".format(item, name)) else: raise TypeError(error_message) - if item.identification in ret: + if item.id in ret: error_message = f"{item} has a duplicate identifier already parsed in the document!" if not decoder_.failsafe: raise KeyError(error_message) logger.error(error_message + " skipping it...") continue - existing_element = object_store.get(item.identification) + existing_element = object_store.get(item.id) if existing_element is not None: if not replace_existing: - error_message = f"object with identifier {item.identification} already exists " \ + error_message = f"object with identifier {item.id} already exists " \ f"in the object store: {existing_element}!" if not ignore_existing: raise KeyError(error_message + f" failed to insert {item}!") @@ -806,7 +856,7 @@ def read_aas_json_file_into(object_store: model.AbstractObjectStore, file: IO, r continue object_store.discard(existing_element) object_store.add(item) - ret.add(item.identification) + ret.add(item.id) elif decoder_.failsafe: logger.error(error_message) else: diff --git a/basyx/aas/adapter/json/json_serialization.py b/basyx/aas/adapter/json/json_serialization.py index a2ec13053..17fff2680 100644 --- a/basyx/aas/adapter/json/json_serialization.py +++ b/basyx/aas/adapter/json/json_serialization.py @@ -9,14 +9,13 @@ Module for serializing Asset Administration Shell objects to the official JSON format -The module provides an custom JSONEncoder classes :class:`~.AASToJsonEncoder` and :class:`~.StrippedAASToJsonEncoder` +The module provides an custom JSONEncoder classes :class:`~.AASToJsonEncoder` and :class:`~.AASToJsonEncoderStripped` to be used with the Python standard `json` module. While the former serializes objects as defined in the specification, the latter serializes stripped objects, excluding some attributes (see https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91). Each class contains a custom :meth:`~.AASToJsonEncoder.default` function which converts BaSyx Python SDK objects to simple python types for an automatic JSON serialization. -To simplify the usage of this module, the :meth:`~aas.adapter.json.json_serialization.write_aas_json_file` and -:meth:`~aas.adapter.json.json_serialization.object_store_to_json` are provided. +To simplify the usage of this module, the :meth:`~.write_aas_json_file` and :meth:`~.object_store_to_json` are provided. The former is used to serialize a given :class:`~aas.model.provider.AbstractObjectStore` to a file, while the latter serializes the object store to a string and returns it. @@ -29,7 +28,7 @@ """ import base64 import inspect -from typing import List, Dict, IO, Optional, Type +from typing import List, Dict, IO, Optional, Type, Callable import json from basyx.aas import model @@ -38,7 +37,7 @@ class AASToJsonEncoder(json.JSONEncoder): """ - Custom JSONDecoder class to use the `json` module for serializing Asset Administration Shell data into the + Custom JSON Encoder class to use the `json` module for serializing Asset Administration Shell data into the official JSON format The class overrides the `default()` method to transform BaSyx Python SDK objects into dicts that may be serialized @@ -63,60 +62,40 @@ def default(self, obj: object) -> object: :param obj: The object to serialize to json :return: The serialized object """ - if isinstance(obj, model.AssetAdministrationShell): - return self._asset_administration_shell_to_json(obj) - if isinstance(obj, model.Identifier): - return self._identifier_to_json(obj) - if isinstance(obj, model.AdministrativeInformation): - return self._administrative_information_to_json(obj) - if isinstance(obj, model.Reference): - return self._reference_to_json(obj) - if isinstance(obj, model.Key): - return self._key_to_json(obj) - if isinstance(obj, model.ValueReferencePair): - return self._value_reference_pair_to_json(obj) - if isinstance(obj, model.Asset): - return self._asset_to_json(obj) - if isinstance(obj, model.Submodel): - return self._submodel_to_json(obj) - if isinstance(obj, model.Operation): - return self._operation_to_json(obj) - if isinstance(obj, model.OperationVariable): - return self._operation_variable_to_json(obj) - if isinstance(obj, model.Capability): - return self._capability_to_json(obj) - if isinstance(obj, model.BasicEvent): - return self._basic_event_to_json(obj) - if isinstance(obj, model.Entity): - return self._entity_to_json(obj) - if isinstance(obj, model.View): - return self._view_to_json(obj) - if isinstance(obj, model.ConceptDictionary): - return self._concept_dictionary_to_json(obj) - if isinstance(obj, model.ConceptDescription): - return self._concept_description_to_json(obj) - if isinstance(obj, model.Property): - return self._property_to_json(obj) - if isinstance(obj, model.Range): - return self._range_to_json(obj) - if isinstance(obj, model.MultiLanguageProperty): - return self._multi_language_property_to_json(obj) - if isinstance(obj, model.File): - return self._file_to_json(obj) - if isinstance(obj, model.Blob): - return self._blob_to_json(obj) - if isinstance(obj, model.ReferenceElement): - return self._reference_element_to_json(obj) - if isinstance(obj, model.SubmodelElementCollection): - return self._submodel_element_collection_to_json(obj) - if isinstance(obj, model.AnnotatedRelationshipElement): - return self._annotated_relationship_element_to_json(obj) - if isinstance(obj, model.RelationshipElement): - return self._relationship_element_to_json(obj) - if isinstance(obj, model.Qualifier): - return self._qualifier_to_json(obj) - if isinstance(obj, model.Formula): - return self._formula_to_json(obj) + mapping: Dict[Type, Callable] = { + model.AdministrativeInformation: self._administrative_information_to_json, + model.AnnotatedRelationshipElement: self._annotated_relationship_element_to_json, + model.AssetAdministrationShell: self._asset_administration_shell_to_json, + model.AssetInformation: self._asset_information_to_json, + model.BasicEventElement: self._basic_event_element_to_json, + model.Blob: self._blob_to_json, + model.Capability: self._capability_to_json, + model.ConceptDescription: self._concept_description_to_json, + model.DataSpecificationIEC61360: self._data_specification_iec61360_to_json, + model.Entity: self._entity_to_json, + model.Extension: self._extension_to_json, + model.File: self._file_to_json, + model.Key: self._key_to_json, + model.LangStringSet: self._lang_string_set_to_json, + model.MultiLanguageProperty: self._multi_language_property_to_json, + model.Operation: self._operation_to_json, + model.Property: self._property_to_json, + model.Qualifier: self._qualifier_to_json, + model.Range: self._range_to_json, + model.Reference: self._reference_to_json, + model.ReferenceElement: self._reference_element_to_json, + model.RelationshipElement: self._relationship_element_to_json, + model.Resource: self._resource_to_json, + model.SpecificAssetId: self._specific_asset_id_to_json, + model.Submodel: self._submodel_to_json, + model.SubmodelElementCollection: self._submodel_element_collection_to_json, + model.SubmodelElementList: self._submodel_element_list_to_json, + model.ValueReferencePair: self._value_reference_pair_to_json, + } + for typ in mapping: + if isinstance(obj, typ): + mapping_method = mapping[typ] + return mapping_method(obj) return super().default(obj) @classmethod @@ -127,29 +106,45 @@ def _abstract_classes_to_json(cls, obj: object) -> Dict[str, object]: :param obj: object which must be serialized :return: dict with the serialized attributes of the abstract classes this object inherits from """ - data = {} + data: Dict[str, object] = {} + if isinstance(obj, model.HasExtension) and not cls.stripped: + if obj.extension: + data['extensions'] = list(obj.extension) + if isinstance(obj, model.HasDataSpecification) and not cls.stripped: + if obj.embedded_data_specifications: + data['embeddedDataSpecifications'] = [ + {'dataSpecification': spec.data_specification, + 'dataSpecificationContent': spec.data_specification_content} + for spec in obj.embedded_data_specifications + ] + if isinstance(obj, model.Referable): - data['idShort'] = obj.id_short + if obj.id_short and not isinstance(obj.parent, model.SubmodelElementList): + data['idShort'] = obj.id_short + if obj.display_name: + data['displayName'] = obj.display_name if obj.category: data['category'] = obj.category if obj.description: - data['description'] = cls._lang_string_set_to_json(obj.description) + data['description'] = obj.description try: - ref_type = next(iter(t for t in inspect.getmro(type(obj)) if t in model.KEY_ELEMENTS_CLASSES)) + ref_type = next(iter(t for t in inspect.getmro(type(obj)) if t in model.KEY_TYPES_CLASSES)) except StopIteration as e: raise TypeError("Object of type {} is Referable but does not inherit from a known AAS type" .format(obj.__class__.__name__)) from e - data['modelType'] = {'name': ref_type.__name__} + data['modelType'] = ref_type.__name__ if isinstance(obj, model.Identifiable): - data['identification'] = obj.identification + data['id'] = obj.id if obj.administration: data['administration'] = obj.administration if isinstance(obj, model.HasSemantics): if obj.semantic_id: data['semanticId'] = obj.semantic_id + if obj.supplemental_semantic_id: + data['supplementalSemanticIds'] = list(obj.supplemental_semantic_id) if isinstance(obj, model.HasKind): - if obj.kind is model.ModelingKind.TEMPLATE: - data['kind'] = _generic.MODELING_KIND[obj.kind] + if obj.kind is model.ModellingKind.TEMPLATE: + data['kind'] = _generic.MODELLING_KIND[obj.kind] if isinstance(obj, model.Qualifiable) and not cls.stripped: if obj.qualifier: data['qualifiers'] = list(obj.qualifier) @@ -173,10 +168,8 @@ def _key_to_json(cls, obj: model.Key) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data.update({'type': _generic.KEY_ELEMENTS[obj.type], - 'idType': _generic.KEY_TYPES[obj.id_type], - 'value': obj.value, - 'local': obj.local}) + data.update({'type': _generic.KEY_TYPES[obj.type], + 'value': obj.value}) return data @classmethod @@ -192,19 +185,10 @@ def _administrative_information_to_json(cls, obj: model.AdministrativeInformatio data['version'] = obj.version if obj.revision: data['revision'] = obj.revision - return data - - @classmethod - def _identifier_to_json(cls, obj: model.Identifier) -> Dict[str, object]: - """ - serialization of an object from class Identifier to json - - :param obj: object of class Identifier - :return: dict with the serialized attributes of this object - """ - data = cls._abstract_classes_to_json(obj) - data['id'] = obj.id - data['idType'] = _generic.IDENTIFIER_TYPES[obj.id_type] + if obj.creator: + data['creator'] = obj.creator + if obj.template_id: + data['templateId'] = obj.template_id return data @classmethod @@ -216,25 +200,12 @@ def _reference_to_json(cls, obj: model.Reference) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) + data['type'] = _generic.REFERENCE_TYPES[obj.__class__] data['keys'] = list(obj.key) + if obj.referred_semantic_id is not None: + data['referredSemanticId'] = cls._reference_to_json(obj.referred_semantic_id) return data - @classmethod - def _constraint_to_json(cls, obj: model.Constraint) -> Dict[str, object]: # TODO check if correct for each class - """ - serialization of an object from class Constraint to json - - :param obj: object of class Constraint - :return: dict with the serialized attributes of this object - """ - CONSTRAINT_CLASSES = [model.Qualifier, model.Formula] - try: - const_type = next(iter(t for t in inspect.getmro(type(obj)) if t in CONSTRAINT_CLASSES)) - except StopIteration as e: - raise TypeError("Object of type {} is a Constraint but does not inherit from a known AAS Constraint type" - .format(obj.__class__.__name__)) from e - return {'modelType': {'name': const_type.__name__}} - @classmethod def _namespace_to_json(cls, obj): # not in specification yet """ @@ -247,35 +218,41 @@ def _namespace_to_json(cls, obj): # not in specification yet return data @classmethod - def _formula_to_json(cls, obj: model.Formula) -> Dict[str, object]: + def _qualifier_to_json(cls, obj: model.Qualifier) -> Dict[str, object]: """ - serialization of an object from class Formula to json + serialization of an object from class Qualifier to json - :param obj: object of class Formula + :param obj: object of class Qualifier :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data.update(cls._constraint_to_json(obj)) - if obj.depends_on: - data['dependsOn'] = list(obj.depends_on) + if obj.value: + data['value'] = model.datatypes.xsd_repr(obj.value) if obj.value is not None else None + if obj.value_id: + data['valueId'] = obj.value_id + # Even though kind is optional in the schema, it's better to always serialize it instead of specifying + # the default value in multiple locations. + data['kind'] = _generic.QUALIFIER_KIND[obj.kind] + data['valueType'] = model.datatypes.XSD_TYPE_NAMES[obj.value_type] + data['type'] = obj.type return data @classmethod - def _qualifier_to_json(cls, obj: model.Qualifier) -> Dict[str, object]: + def _extension_to_json(cls, obj: model.Extension) -> Dict[str, object]: """ - serialization of an object from class Qualifier to json + serialization of an object from class Extension to json - :param obj: object of class Qualifier + :param obj: object of class Extension :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data.update(cls._constraint_to_json(obj)) if obj.value: data['value'] = model.datatypes.xsd_repr(obj.value) if obj.value is not None else None - if obj.value_id: - data['valueId'] = obj.value_id - data['valueType'] = model.datatypes.XSD_TYPE_NAMES[obj.value_type] - data['type'] = obj.type + if obj.refers_to: + data['refersTo'] = list(obj.refers_to) + if obj.value_type: + data['valueType'] = model.datatypes.XSD_TYPE_NAMES[obj.value_type] + data['name'] = obj.name return data @classmethod @@ -288,8 +265,7 @@ def _value_reference_pair_to_json(cls, obj: model.ValueReferencePair) -> Dict[st """ data = cls._abstract_classes_to_json(obj) data.update({'value': model.datatypes.xsd_repr(obj.value), - 'valueId': obj.value_id, - 'valueType': model.datatypes.XSD_TYPE_NAMES[obj.value_type]}) + 'valueId': obj.value_id}) return data @classmethod @@ -300,39 +276,45 @@ def _value_list_to_json(cls, obj: model.ValueList) -> Dict[str, object]: :param obj: object of class ValueList :return: dict with the serialized attributes of this object """ - return {'valueReferencePairTypes': list(obj)} + return {'valueReferencePairs': list(obj)} # ############################################################ # transformation functions to serialize classes from model.aas # ############################################################ @classmethod - def _view_to_json(cls, obj: model.View) -> Dict[str, object]: + def _specific_asset_id_to_json(cls, obj: model.SpecificAssetId) -> Dict[str, object]: """ - serialization of an object from class View to json + serialization of an object from class SpecificAssetId to json - :param obj: object of class View + :param obj: object of class SpecificAssetId :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - if obj.contained_element: - data['containedElements'] = list(obj.contained_element) + data['name'] = obj.name + data['value'] = obj.value + if obj.external_subject_id: + data['externalSubjectId'] = obj.external_subject_id return data @classmethod - def _asset_to_json(cls, obj: model.Asset) -> Dict[str, object]: + def _asset_information_to_json(cls, obj: model.AssetInformation) -> Dict[str, object]: """ - serialization of an object from class Asset to json + serialization of an object from class AssetInformation to json - :param obj: object of class Asset + :param obj: object of class AssetInformation :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data['kind'] = _generic.ASSET_KIND[obj.kind] - if obj.asset_identification_model: - data['assetIdentificationModel'] = obj.asset_identification_model - if obj.bill_of_material: - data['billOfMaterial'] = obj.bill_of_material + data['assetKind'] = _generic.ASSET_KIND[obj.asset_kind] + if obj.global_asset_id: + data['globalAssetId'] = obj.global_asset_id + if obj.specific_asset_id: + data['specificAssetIds'] = list(obj.specific_asset_id) + if obj.asset_type: + data['assetType'] = obj.asset_type + if obj.default_thumbnail: + data['defaultThumbnail'] = obj.default_thumbnail return data @classmethod @@ -346,32 +328,27 @@ def _concept_description_to_json(cls, obj: model.ConceptDescription) -> Dict[str data = cls._abstract_classes_to_json(obj) if obj.is_case_of: data['isCaseOf'] = list(obj.is_case_of) - - if isinstance(obj, model.concept.IEC61360ConceptDescription): - cls._append_iec61360_concept_description_attrs(obj, data) - return data @classmethod - def _append_iec61360_concept_description_attrs(cls, obj: model.concept.IEC61360ConceptDescription, - data: Dict[str, object]) -> None: + def _data_specification_iec61360_to_json( + cls, obj: model.base.DataSpecificationIEC61360) -> Dict[str, object]: """ - Add the 'embeddedDataSpecifications' attribute to IEC61360ConceptDescription's JSON representation. + serialization of an object from class DataSpecificationIEC61360 to json - `IEC61360ConceptDescription` is not a distinct class according DotAAS, but instead is built by referencing - "DataSpecificationIEC61360" as dataSpecification. However, we implemented it as an explicit class, inheriting - from ConceptDescription, but we want to generate compliant JSON documents. So, we fake the JSON structure of an - object with dataSpecifications. + :param obj: object of class DataSpecificationIEC61360 + :return: dict with the serialized attributes of this object """ data_spec: Dict[str, object] = { - 'preferredName': cls._lang_string_set_to_json(obj.preferred_name) + 'modelType': 'DataSpecificationIec61360', + 'preferredName': obj.preferred_name } if obj.data_type is not None: data_spec['dataType'] = _generic.IEC61360_DATA_TYPES[obj.data_type] if obj.definition is not None: - data_spec['definition'] = cls._lang_string_set_to_json(obj.definition) + data_spec['definition'] = obj.definition if obj.short_name is not None: - data_spec['shortName'] = cls._lang_string_set_to_json(obj.short_name) + data_spec['shortName'] = obj.short_name if obj.unit is not None: data_spec['unit'] = obj.unit if obj.unit_id is not None: @@ -381,35 +358,14 @@ def _append_iec61360_concept_description_attrs(cls, obj: model.concept.IEC61360C if obj.symbol is not None: data_spec['symbol'] = obj.symbol if obj.value_format is not None: - data_spec['valueFormat'] = model.datatypes.XSD_TYPE_NAMES[obj.value_format] + data_spec['valueFormat'] = obj.value_format if obj.value_list is not None: data_spec['valueList'] = cls._value_list_to_json(obj.value_list) if obj.value is not None: - data_spec['value'] = model.datatypes.xsd_repr(obj.value) if obj.value is not None else None - if obj.value_id is not None: - data_spec['valueId'] = obj.value_id + data_spec['value'] = obj.value if obj.level_types: - data_spec['levelType'] = [_generic.IEC61360_LEVEL_TYPES[lt] for lt in obj.level_types] - data['embeddedDataSpecifications'] = [ - {'dataSpecification': model.Reference(( - model.Key(model.KeyElements.GLOBAL_REFERENCE, False, - "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0", - model.KeyType.IRI),)), - 'dataSpecificationContent': data_spec} - ] - - @classmethod - def _concept_dictionary_to_json(cls, obj: model.ConceptDictionary) -> Dict[str, object]: - """ - serialization of an object from class ConceptDictionary to json - - :param obj: object of class ConceptDictionary - :return: dict with the serialized attributes of this object - """ - data = cls._abstract_classes_to_json(obj) - if obj.concept_description: - data['conceptDescriptions'] = list(obj.concept_description) - return data + data_spec['levelType'] = {v: k in obj.level_types for k, v in _generic.IEC61360_LEVEL_TYPES.items()} + return data_spec @classmethod def _asset_administration_shell_to_json(cls, obj: model.AssetAdministrationShell) -> Dict[str, object]: @@ -423,30 +379,10 @@ def _asset_administration_shell_to_json(cls, obj: model.AssetAdministrationShell data.update(cls._namespace_to_json(obj)) if obj.derived_from: data["derivedFrom"] = obj.derived_from - data["asset"] = obj.asset + if obj.asset_information: + data["assetInformation"] = obj.asset_information if not cls.stripped and obj.submodel: data["submodels"] = list(obj.submodel) - if not cls.stripped and obj.view: - data["views"] = list(obj.view) - if obj.concept_dictionary: - data["conceptDictionaries"] = list(obj.concept_dictionary) - if obj.security: - data["security"] = obj.security - return data - - # ################################################################# - # transformation functions to serialize classes from model.security - # ################################################################# - - @classmethod - def _security_to_json(cls, obj: model.Security) -> Dict[str, object]: # has no attributes in our implementation - """ - serialization of an object from class Security to json - - :param obj: object of class Security - :return: dict with the serialized attributes of this object - """ - data = cls._abstract_classes_to_json(obj) return data # ################################################################# @@ -485,7 +421,8 @@ def _property_to_json(cls, obj: model.Property) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data['value'] = model.datatypes.xsd_repr(obj.value) if obj.value is not None else None + if obj.value is not None: + data['value'] = model.datatypes.xsd_repr(obj.value) if obj.value_id: data['valueId'] = obj.value_id data['valueType'] = model.datatypes.XSD_TYPE_NAMES[obj.value_type] @@ -501,7 +438,7 @@ def _multi_language_property_to_json(cls, obj: model.MultiLanguageProperty) -> D """ data = cls._abstract_classes_to_json(obj) if obj.value: - data['value'] = cls._lang_string_set_to_json(obj.value) + data['value'] = obj.value if obj.value_id: data['valueId'] = obj.value_id return data @@ -515,9 +452,11 @@ def _range_to_json(cls, obj: model.Range) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data.update({'valueType': model.datatypes.XSD_TYPE_NAMES[obj.value_type], - 'min': model.datatypes.xsd_repr(obj.min) if obj.min is not None else None, - 'max': model.datatypes.xsd_repr(obj.max) if obj.max is not None else None}) + data['valueType'] = model.datatypes.XSD_TYPE_NAMES[obj.value_type] + if obj.min is not None: + data['min'] = model.datatypes.xsd_repr(obj.min) + if obj.max is not None: + data['max'] = model.datatypes.xsd_repr(obj.max) return data @classmethod @@ -529,7 +468,7 @@ def _blob_to_json(cls, obj: model.Blob) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data['mimeType'] = obj.mime_type + data['contentType'] = obj.content_type if obj.value is not None: data['value'] = base64.b64encode(obj.value).decode() return data @@ -543,11 +482,25 @@ def _file_to_json(cls, obj: model.File) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data['mimeType'] = obj.mime_type + data['contentType'] = obj.content_type if obj.value is not None: data['value'] = obj.value return data + @classmethod + def _resource_to_json(cls, obj: model.Resource) -> Dict[str, object]: + """ + serialization of an object from class Resource to json + + :param obj: object of class Resource + :return: dict with the serialized attributes of this object + """ + data = cls._abstract_classes_to_json(obj) + data['path'] = obj.path + if obj.content_type is not None: + data['contentType'] = obj.content_type + return data + @classmethod def _reference_element_to_json(cls, obj: model.ReferenceElement) -> Dict[str, object]: """ @@ -564,16 +517,35 @@ def _reference_element_to_json(cls, obj: model.ReferenceElement) -> Dict[str, ob @classmethod def _submodel_element_collection_to_json(cls, obj: model.SubmodelElementCollection) -> Dict[str, object]: """ - serialization of an object from class SubmodelElementCollectionOrdered and SubmodelElementCollectionUnordered to - json + serialization of an object from class SubmodelElementCollection to json + + :param obj: object of class SubmodelElementCollection + :return: dict with the serialized attributes of this object + """ + data = cls._abstract_classes_to_json(obj) + if not cls.stripped and len(obj.value) > 0: + data['value'] = list(obj.value) + return data + + @classmethod + def _submodel_element_list_to_json(cls, obj: model.SubmodelElementList) -> Dict[str, object]: + """ + serialization of an object from class SubmodelElementList to json - :param obj: object of class SubmodelElementCollectionOrdered and SubmodelElementCollectionUnordered + :param obj: object of class SubmodelElementList :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - if not cls.stripped and obj.value: + # Even though orderRelevant is optional in the schema, it's better to always serialize it instead of specifying + # the default value in multiple locations. + data['orderRelevant'] = obj.order_relevant + data['typeValueListElement'] = _generic.KEY_TYPES[model.KEY_TYPES_CLASSES[obj.type_value_list_element]] + if obj.semantic_id_list_element is not None: + data['semanticIdListElement'] = obj.semantic_id_list_element + if obj.value_type_list_element is not None: + data['valueTypeListElement'] = model.datatypes.XSD_TYPE_NAMES[obj.value_type_list_element] + if not cls.stripped and len(obj.value) > 0: data['value'] = list(obj.value) - data['ordered'] = obj.ordered return data @classmethod @@ -599,20 +571,21 @@ def _annotated_relationship_element_to_json(cls, obj: model.AnnotatedRelationshi data = cls._abstract_classes_to_json(obj) data.update({'first': obj.first, 'second': obj.second}) if not cls.stripped and obj.annotation: - data['annotation'] = list(obj.annotation) + data['annotations'] = list(obj.annotation) return data @classmethod - def _operation_variable_to_json(cls, obj: model.OperationVariable) -> Dict[str, object]: + def _operation_variable_to_json(cls, obj: model.SubmodelElement) -> Dict[str, object]: """ - serialization of an object from class OperationVariable to json + serialization of an object from class SubmodelElement to a json OperationVariable representation + Since we don't implement the `OperationVariable` class, which is just a wrapper for a single + :class:`~aas.model.submodel.SubmodelElement`, elements are serialized as the `value` attribute of an + `operationVariable` object. - :param obj: object of class OperationVariable - :return: dict with the serialized attributes of this object + :param obj: object of class `SubmodelElement` + :return: `OperationVariable` wrapper containing the serialized `SubmodelElement` """ - data = cls._abstract_classes_to_json(obj) - data['value'] = obj.value - return data + return {'value': obj} @classmethod def _operation_to_json(cls, obj: model.Operation) -> Dict[str, object]: @@ -623,12 +596,11 @@ def _operation_to_json(cls, obj: model.Operation) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - if obj.input_variable: - data['inputVariable'] = list(obj.input_variable) - if obj.output_variable: - data['outputVariable'] = list(obj.output_variable) - if obj.in_output_variable: - data['inoutputVariable'] = list(obj.in_output_variable) + for tag, nss in (('inputVariables', obj.input_variable), + ('outputVariables', obj.output_variable), + ('inoutputVariables', obj.in_output_variable)): + if nss: + data[tag] = [cls._operation_variable_to_json(obj) for obj in nss] return data @classmethod @@ -655,30 +627,44 @@ def _entity_to_json(cls, obj: model.Entity) -> Dict[str, object]: if not cls.stripped and obj.statement: data['statements'] = list(obj.statement) data['entityType'] = _generic.ENTITY_TYPES[obj.entity_type] - if obj.asset: - data['asset'] = obj.asset + if obj.global_asset_id: + data['globalAssetId'] = obj.global_asset_id + if obj.specific_asset_id: + data['specificAssetIds'] = list(obj.specific_asset_id) return data @classmethod - def _event_to_json(cls, obj: model.Event) -> Dict[str, object]: # no attributes in specification yet + def _event_element_to_json(cls, obj: model.EventElement) -> Dict[str, object]: # no attributes in specification yet """ - serialization of an object from class Event to json + serialization of an object from class EventElement to json - :param obj: object of class Event + :param obj: object of class EventElement :return: dict with the serialized attributes of this object """ return {} @classmethod - def _basic_event_to_json(cls, obj: model.BasicEvent) -> Dict[str, object]: + def _basic_event_element_to_json(cls, obj: model.BasicEventElement) -> Dict[str, object]: """ - serialization of an object from class BasicEvent to json + serialization of an object from class BasicEventElement to json - :param obj: object of class BasicEvent + :param obj: object of class BasicEventElement :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) data['observed'] = obj.observed + data['direction'] = _generic.DIRECTION[obj.direction] + data['state'] = _generic.STATE_OF_EVENT[obj.state] + if obj.message_topic is not None: + data['messageTopic'] = obj.message_topic + if obj.message_broker is not None: + data['messageBroker'] = cls._reference_to_json(obj.message_broker) + if obj.last_update is not None: + data['lastUpdate'] = model.datatypes.xsd_repr(obj.last_update) + if obj.min_interval is not None: + data['minInterval'] = model.datatypes.xsd_repr(obj.min_interval) + if obj.max_interval is not None: + data['maxInterval'] = model.datatypes.xsd_repr(obj.max_interval) return data @@ -706,25 +692,23 @@ def _select_encoder(stripped: bool, encoder: Optional[Type[AASToJsonEncoder]] = def _create_dict(data: model.AbstractObjectStore) -> dict: # separate different kind of objects - assets = [] - asset_administration_shells = [] - submodels = [] - concept_descriptions = [] + asset_administration_shells: List[model.AssetAdministrationShell] = [] + submodels: List[model.Submodel] = [] + concept_descriptions: List[model.ConceptDescription] = [] for obj in data: - if isinstance(obj, model.Asset): - assets.append(obj) - elif isinstance(obj, model.AssetAdministrationShell): + if isinstance(obj, model.AssetAdministrationShell): asset_administration_shells.append(obj) elif isinstance(obj, model.Submodel): submodels.append(obj) elif isinstance(obj, model.ConceptDescription): concept_descriptions.append(obj) - dict_ = { - 'assetAdministrationShells': asset_administration_shells, - 'submodels': submodels, - 'assets': assets, - 'conceptDescriptions': concept_descriptions, - } + dict_: Dict[str, List] = {} + if asset_administration_shells: + dict_['assetAdministrationShells'] = asset_administration_shells + if submodels: + dict_['submodels'] = submodels + if concept_descriptions: + dict_['conceptDescriptions'] = concept_descriptions return dict_ @@ -735,12 +719,11 @@ def object_store_to_json(data: model.AbstractObjectStore, stripped: bool = False chapter 5.5 :param data: :class:`ObjectStore ` which contains different objects of the - AAS meta model which should be serialized to a - JSON file - :param stripped: If true, objects are serialized to stripped json objects.. + AAS meta model which should be serialized to a JSON file + :param stripped: If true, objects are serialized to stripped json objects. See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91 This parameter is ignored if an encoder class is specified. - :param encoder: The encoder class used to encoder the JSON objects + :param encoder: The encoder class used to encode the JSON objects :param kwargs: Additional keyword arguments to be passed to `json.dumps()` """ encoder_ = _select_encoder(stripped, encoder) @@ -756,13 +739,12 @@ def write_aas_json_file(file: IO, data: model.AbstractObjectStore, stripped: boo :param file: A file-like object to write the JSON-serialized data to :param data: :class:`ObjectStore ` which contains different objects of the - AAS meta model which should be serialized to a - JSON file - :param stripped: If true, objects are serialized to stripped json objects.. + AAS meta model which should be serialized to a JSON file + :param stripped: If `True`, objects are serialized to stripped json objects. See https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/91 This parameter is ignored if an encoder class is specified. - :param encoder: The encoder class used to encoder the JSON objects - :param kwargs: Additional keyword arguments to be passed to json.dumps() + :param encoder: The encoder class used to encode the JSON objects + :param kwargs: Additional keyword arguments to be passed to `json.dump()` """ encoder_ = _select_encoder(stripped, encoder) # serialize object to json diff --git a/basyx/aas/adapter/xml/AAS.xsd b/basyx/aas/adapter/xml/AAS.xsd index 0e2fbcace..25d7a52b9 100644 --- a/basyx/aas/adapter/xml/AAS.xsd +++ b/basyx/aas/adapter/xml/AAS.xsd @@ -1,550 +1,1344 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/basyx/aas/adapter/xml/AAS_ABAC.xsd b/basyx/aas/adapter/xml/AAS_ABAC.xsd deleted file mode 100644 index a735cced3..000000000 --- a/basyx/aas/adapter/xml/AAS_ABAC.xsd +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/basyx/aas/adapter/xml/IEC61360.xsd b/basyx/aas/adapter/xml/IEC61360.xsd deleted file mode 100644 index bdaee9ddb..000000000 --- a/basyx/aas/adapter/xml/IEC61360.xsd +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/basyx/aas/adapter/xml/xml_deserialization.py b/basyx/aas/adapter/xml/xml_deserialization.py index 5d4030698..e42a9a6f6 100644 --- a/basyx/aas/adapter/xml/xml_deserialization.py +++ b/basyx/aas/adapter/xml/xml_deserialization.py @@ -31,8 +31,8 @@ .. code-block:: - KeyError: aas:identification on line 252 has no attribute with name idType! - -> Failed to construct aas:identification on line 252 using construct_identifier! + KeyError: aas:id on line 252 has no attribute with name idType! + -> Failed to construct aas:id on line 252 using construct_identifier! -> Failed to construct aas:conceptDescription on line 247 using construct_concept_description! @@ -49,15 +49,17 @@ import enum from typing import Any, Callable, Dict, IO, Iterable, Optional, Set, Tuple, Type, TypeVar -from .xml_serialization import NS_AAS, NS_ABAC, NS_IEC -from .._generic import MODELING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_ELEMENTS_INVERSE, KEY_TYPES_INVERSE, \ - IDENTIFIER_TYPES_INVERSE, ENTITY_TYPES_INVERSE, IEC61360_DATA_TYPES_INVERSE, IEC61360_LEVEL_TYPES_INVERSE, \ - KEY_ELEMENTS_CLASSES_INVERSE +from .._generic import XML_NS_AAS, MODELLING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_TYPES_INVERSE, \ + ENTITY_TYPES_INVERSE, IEC61360_DATA_TYPES_INVERSE, IEC61360_LEVEL_TYPES_INVERSE, KEY_TYPES_CLASSES_INVERSE, \ + REFERENCE_TYPES_INVERSE, DIRECTION_INVERSE, STATE_OF_EVENT_INVERSE, QUALIFIER_KIND_INVERSE + +NS_AAS = XML_NS_AAS logger = logging.getLogger(__name__) T = TypeVar("T") RE = TypeVar("RE", bound=model.RelationshipElement) +LSS = TypeVar("LSS", bound=model.LangStringSet) def _str_to_bool(string: str) -> bool: @@ -96,7 +98,7 @@ def _element_pretty_identifier(element: etree.Element) -> str: If the prefix is known, the namespace in the element tag is replaced by the prefix. If additionally also the sourceline is known, is is added as a suffix to name. - For example, instead of "{http://www.admin-shell.io/aas/2/0}assetAdministrationShell" this function would return + For example, instead of "{https://admin-shell.io/aas/3/0}assetAdministrationShell" this function would return "aas:assetAdministrationShell on line $line", if both, prefix and sourceline, are known. :param element: The xml element. @@ -283,10 +285,10 @@ def _failsafe_construct(element: Optional[etree.Element], constructor: Callable[ return None try: return constructor(element, **kwargs) - except (KeyError, ValueError) as e: + except (KeyError, ValueError, model.AASConstraintViolation) as e: error_message = f"Failed to construct {_element_pretty_identifier(element)} using {constructor.__name__}!" if not failsafe: - raise type(e)(error_message) from e + raise (type(e) if isinstance(e, (KeyError, ValueError)) else ValueError)(error_message) from e error_type = type(e).__name__ cause: Optional[BaseException] = e while cause is not None: @@ -387,15 +389,28 @@ def _child_text_mandatory_mapped(parent: etree.Element, child_tag: str, dct: Dic return _get_text_mandatory_mapped(_get_child_mandatory(parent, child_tag), dct) -def _get_modeling_kind(element: etree.Element) -> model.ModelingKind: +def _get_kind(element: etree.Element) -> model.ModellingKind: + """ + Returns the modelling kind of an element with the default value INSTANCE, if none specified. + + :param element: The xml element. + :return: The modelling kind of the element. + """ + modelling_kind = _get_text_mapped_or_none(element.find(NS_AAS + "kind"), MODELLING_KIND_INVERSE) + return modelling_kind if modelling_kind is not None else model.ModellingKind.INSTANCE + + +def _expect_reference_type(element: etree.Element, expected_type: Type[model.Reference]) -> None: """ - Returns the modeling kind of an element with the default value INSTANCE, if none specified. + Validates the type attribute of a Reference. :param element: The xml element. - :return: The modeling kind of the element. + :param expected_type: The expected type of the Reference. + :return: None """ - modeling_kind = _get_text_mapped_or_none(element.find(NS_AAS + "kind"), MODELING_KIND_INVERSE) - return modeling_kind if modeling_kind is not None else model.ModelingKind.INSTANCE + actual_type = _child_text_mandatory_mapped(element, NS_AAS + "type", REFERENCE_TYPES_INVERSE) + if actual_type is not expected_type: + raise ValueError(f"{_element_pretty_identifier(element)} is of type {actual_type}, expected {expected_type}!") class AASFromXmlDecoder: @@ -421,17 +436,21 @@ def _amend_abstract_attributes(cls, obj: object, element: etree.Element) -> None :return: None """ if isinstance(obj, model.Referable): + id_short = _get_text_or_none(element.find(NS_AAS + "idShort")) + if id_short is not None: + obj.id_short = id_short category = _get_text_or_none(element.find(NS_AAS + "category")) + display_name = _failsafe_construct(element.find(NS_AAS + "displayName"), + cls.construct_multi_language_name_type, cls.failsafe) + if display_name is not None: + obj.display_name = display_name if category is not None: obj.category = category - description = _failsafe_construct(element.find(NS_AAS + "description"), cls.construct_lang_string_set, - cls.failsafe) + description = _failsafe_construct(element.find(NS_AAS + "description"), + cls.construct_multi_language_text_type, cls.failsafe) if description is not None: obj.description = description if isinstance(obj, model.Identifiable): - id_short = _get_text_or_none(element.find(NS_AAS + "idShort")) - if id_short is not None: - obj.id_short = id_short administration = _failsafe_construct(element.find(NS_AAS + "administration"), cls.construct_administrative_information, cls.failsafe) if administration: @@ -441,17 +460,29 @@ def _amend_abstract_attributes(cls, obj: object, element: etree.Element) -> None cls.failsafe) if semantic_id is not None: obj.semantic_id = semantic_id + supplemental_semantic_ids = element.find(NS_AAS + "supplementalSemanticIds") + if supplemental_semantic_ids is not None: + for supplemental_semantic_id in _child_construct_multiple(supplemental_semantic_ids, + NS_AAS + "reference", cls.construct_reference, + cls.failsafe): + obj.supplemental_semantic_id.append(supplemental_semantic_id) if isinstance(obj, model.Qualifiable) and not cls.stripped: - # TODO: simplify this should our suggestion regarding the XML schema get accepted - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 - for constraint in element.findall(NS_AAS + "qualifier"): - if len(constraint) == 0: - continue - if len(constraint) > 1: - logger.warning(f"{_element_pretty_identifier(constraint)} has more than one constraint, " - "which is invalid! Deserializing all constraints anyways...") - for constructed in _failsafe_construct_multiple(constraint, cls.construct_constraint, cls.failsafe): - obj.qualifier.add(constructed) + qualifiers_elem = element.find(NS_AAS + "qualifiers") + if qualifiers_elem is not None and len(qualifiers_elem) > 0: + for qualifier in _failsafe_construct_multiple(qualifiers_elem, cls.construct_qualifier, cls.failsafe): + obj.qualifier.add(qualifier) + if isinstance(obj, model.HasDataSpecification) and not cls.stripped: + embedded_data_specifications_elem = element.find(NS_AAS + "embeddedDataSpecifications") + if embedded_data_specifications_elem is not None: + for eds in _failsafe_construct_multiple(embedded_data_specifications_elem, + cls.construct_embedded_data_specification, cls.failsafe): + obj.embedded_data_specifications.append(eds) + if isinstance(obj, model.HasExtension) and not cls.stripped: + extension_elem = element.find(NS_AAS + "extensions") + if extension_elem is not None: + for extension in _child_construct_multiple(extension_elem, NS_AAS + "extension", + cls.construct_extension, cls.failsafe): + obj.extension.add(extension) @classmethod def _construct_relationship_element_internal(cls, element: etree.Element, object_class: Type[RE], **_kwargs: Any) \ @@ -461,10 +492,9 @@ def _construct_relationship_element_internal(cls, element: etree.Element, object to reduce duplicate code """ relationship_element = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - _child_construct_mandatory(element, NS_AAS + "first", cls._construct_referable_reference), - _child_construct_mandatory(element, NS_AAS + "second", cls._construct_referable_reference), - kind=_get_modeling_kind(element) + None, + _child_construct_mandatory(element, NS_AAS + "first", cls.construct_reference), + _child_construct_mandatory(element, NS_AAS + "second", cls.construct_reference) ) cls._amend_abstract_attributes(relationship_element, element) return relationship_element @@ -479,109 +509,159 @@ def _construct_key_tuple(cls, element: etree.Element, namespace: str = NS_AAS, * return tuple(_child_construct_multiple(keys, namespace + "key", cls.construct_key, cls.failsafe)) @classmethod - def _construct_submodel_reference(cls, element: etree.Element, **kwargs: Any) -> model.AASReference[model.Submodel]: - """ - Helper function. Doesn't support the object_class parameter. Overwrite construct_aas_reference instead. - """ - return cls.construct_aas_reference_expect_type(element, model.Submodel, **kwargs) - - @classmethod - def _construct_asset_reference(cls, element: etree.Element, **kwargs: Any) \ - -> model.AASReference[model.Asset]: + def _construct_submodel_reference(cls, element: etree.Element, **kwargs: Any) \ + -> model.ModelReference[model.Submodel]: """ Helper function. Doesn't support the object_class parameter. Overwrite construct_aas_reference instead. """ - return cls.construct_aas_reference_expect_type(element, model.Asset, **kwargs) + return cls.construct_model_reference_expect_type(element, model.Submodel, **kwargs) @classmethod def _construct_asset_administration_shell_reference(cls, element: etree.Element, **kwargs: Any) \ - -> model.AASReference[model.AssetAdministrationShell]: + -> model.ModelReference[model.AssetAdministrationShell]: """ Helper function. Doesn't support the object_class parameter. Overwrite construct_aas_reference instead. """ - return cls.construct_aas_reference_expect_type(element, model.AssetAdministrationShell, **kwargs) + return cls.construct_model_reference_expect_type(element, model.AssetAdministrationShell, **kwargs) @classmethod def _construct_referable_reference(cls, element: etree.Element, **kwargs: Any) \ - -> model.AASReference[model.Referable]: + -> model.ModelReference[model.Referable]: """ Helper function. Doesn't support the object_class parameter. Overwrite construct_aas_reference instead. """ # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 - return cls.construct_aas_reference_expect_type(element, model.Referable, **kwargs) # type: ignore + return cls.construct_model_reference_expect_type(element, model.Referable, **kwargs) # type: ignore @classmethod - def _construct_concept_description_reference(cls, element: etree.Element, **kwargs: Any) \ - -> model.AASReference[model.ConceptDescription]: + def _construct_operation_variable(cls, element: etree.Element, **kwargs: Any) -> model.SubmodelElement: """ - Helper function. Doesn't support the object_class parameter. Overwrite construct_aas_reference instead. + Since we don't implement `OperationVariable`, this constructor discards the wrapping `aas:operationVariable` + and `aas:value` and just returns the contained :class:`~aas.model.submodel.SubmodelElement`. """ - return cls.construct_aas_reference_expect_type(element, model.ConceptDescription, **kwargs) + value = _get_child_mandatory(element, NS_AAS + "value") + if len(value) == 0: + raise KeyError(f"{_element_pretty_identifier(value)} has no submodel element!") + if len(value) > 1: + logger.warning(f"{_element_pretty_identifier(value)} has more than one submodel element, " + "using the first one...") + return cls.construct_submodel_element(value[0], **kwargs) @classmethod def construct_key(cls, element: etree.Element, object_class=model.Key, **_kwargs: Any) \ -> model.Key: return object_class( - _get_attrib_mandatory_mapped(element, "type", KEY_ELEMENTS_INVERSE), - _str_to_bool(_get_attrib_mandatory(element, "local")), - _get_text_mandatory(element), - _get_attrib_mandatory_mapped(element, "idType", KEY_TYPES_INVERSE) + _child_text_mandatory_mapped(element, NS_AAS + "type", KEY_TYPES_INVERSE), + _child_text_mandatory(element, NS_AAS + "value") ) @classmethod - def construct_reference(cls, element: etree.Element, namespace: str = NS_AAS, object_class=model.Reference, - **_kwargs: Any) -> model.Reference: - return object_class(cls._construct_key_tuple(element, namespace=namespace)) + def construct_reference(cls, element: etree.Element, namespace: str = NS_AAS, **kwargs: Any) -> model.Reference: + reference_type: Type[model.Reference] = _child_text_mandatory_mapped(element, NS_AAS + "type", + REFERENCE_TYPES_INVERSE) + references: Dict[Type[model.Reference], Callable[..., model.Reference]] = { + model.ExternalReference: cls.construct_external_reference, + model.ModelReference: cls.construct_model_reference + } + if reference_type not in references: + raise KeyError(_element_pretty_identifier(element) + f" is of unsupported Reference type {reference_type}!") + return references[reference_type](element, namespace=namespace, **kwargs) + + @classmethod + def construct_external_reference(cls, element: etree.Element, namespace: str = NS_AAS, + object_class=model.ExternalReference, **_kwargs: Any) \ + -> model.ExternalReference: + _expect_reference_type(element, model.ExternalReference) + return object_class(cls._construct_key_tuple(element, namespace=namespace), + _failsafe_construct(element.find(NS_AAS + "referredSemanticId"), cls.construct_reference, + cls.failsafe, namespace=namespace)) @classmethod - def construct_aas_reference(cls, element: etree.Element, object_class=model.AASReference, **_kwargs: Any) \ - -> model.AASReference: + def construct_model_reference(cls, element: etree.Element, object_class=model.ModelReference, **_kwargs: Any) \ + -> model.ModelReference: """ - This constructor for AASReference determines the type of the AASReference by its keys. If no keys are present, - it will default to the type Referable. This behaviour is wanted in read_aas_xml_element(). + This constructor for ModelReference determines the type of the ModelReference by its keys. If no keys are + present, it will default to the type Referable. This behaviour is wanted in read_aas_xml_element(). """ + _expect_reference_type(element, model.ModelReference) keys = cls._construct_key_tuple(element) # TODO: remove the following type: ignore comments when mypy supports abstract types for Type[T] # see https://github.com/python/mypy/issues/5374 type_: Type[model.Referable] = model.Referable # type: ignore if len(keys) > 0: - type_ = KEY_ELEMENTS_CLASSES_INVERSE.get(keys[-1].type, model.Referable) # type: ignore - return object_class(keys, type_) + type_ = KEY_TYPES_CLASSES_INVERSE.get(keys[-1].type, model.Referable) # type: ignore + return object_class(keys, type_, _failsafe_construct(element.find(NS_AAS + "referredSemanticId"), + cls.construct_reference, cls.failsafe)) @classmethod - def construct_aas_reference_expect_type(cls, element: etree.Element, type_: Type[model.base._RT], - object_class=model.AASReference, **_kwargs: Any) \ - -> model.AASReference[model.base._RT]: + def construct_model_reference_expect_type(cls, element: etree.Element, type_: Type[model.base._RT], + object_class=model.ModelReference, **_kwargs: Any) \ + -> model.ModelReference[model.base._RT]: """ - This constructor for AASReference allows passing an expected type, which is checked against the type of the last - key of the reference. This constructor function is used by other constructor functions, since all expect a + This constructor for ModelReference allows passing an expected type, which is checked against the type of the + last key of the reference. This constructor function is used by other constructor functions, since all expect a specific target type. """ + _expect_reference_type(element, model.ModelReference) keys = cls._construct_key_tuple(element) - if keys and not issubclass(KEY_ELEMENTS_CLASSES_INVERSE.get(keys[-1].type, type(None)), type_): + if keys and not issubclass(KEY_TYPES_CLASSES_INVERSE.get(keys[-1].type, type(None)), type_): logger.warning("type %s of last key of reference to %s does not match reference type %s", keys[-1].type.name, " / ".join(str(k) for k in keys), type_.__name__) - return object_class(keys, type_) + return object_class(keys, type_, _failsafe_construct(element.find(NS_AAS + "referredSemanticId"), + cls.construct_reference, cls.failsafe)) @classmethod def construct_administrative_information(cls, element: etree.Element, object_class=model.AdministrativeInformation, **_kwargs: Any) -> model.AdministrativeInformation: - return object_class( - _get_text_or_none(element.find(NS_AAS + "version")), - _get_text_or_none(element.find(NS_AAS + "revision")) + administrative_information = object_class( + revision=_get_text_or_none(element.find(NS_AAS + "revision")), + version=_get_text_or_none(element.find(NS_AAS + "version")), + template_id=_get_text_or_none(element.find(NS_AAS + "templateId")) ) + creator = _failsafe_construct(element.find(NS_AAS + "creator"), cls.construct_reference, cls.failsafe) + if creator is not None: + administrative_information.creator = creator + cls._amend_abstract_attributes(administrative_information, element) + return administrative_information @classmethod - def construct_lang_string_set(cls, element: etree.Element, namespace: str = NS_AAS, **_kwargs: Any) \ - -> model.LangStringSet: - """ - This function doesn't support the object_class parameter, because LangStringSet is just a generic type alias. - """ - lss: model.LangStringSet = {} - for lang_string in _get_all_children_expect_tag(element, namespace + "langString", cls.failsafe): - lss[_get_attrib_mandatory(lang_string, "lang")] = _get_text_mandatory(lang_string) - return lss + def construct_lang_string_set(cls, element: etree.Element, expected_tag: str, object_class: Type[LSS], + **_kwargs: Any) -> LSS: + collected_lang_strings: Dict[str, str] = {} + for lang_string_elem in _get_all_children_expect_tag(element, expected_tag, cls.failsafe): + collected_lang_strings[_child_text_mandatory(lang_string_elem, NS_AAS + "language")] = \ + _child_text_mandatory(lang_string_elem, NS_AAS + "text") + return object_class(collected_lang_strings) + + @classmethod + def construct_multi_language_name_type(cls, element: etree.Element, object_class=model.MultiLanguageNameType, + **kwargs: Any) -> model.MultiLanguageNameType: + return cls.construct_lang_string_set(element, NS_AAS + "langStringNameType", object_class, **kwargs) + + @classmethod + def construct_multi_language_text_type(cls, element: etree.Element, object_class=model.MultiLanguageTextType, + **kwargs: Any) -> model.MultiLanguageTextType: + return cls.construct_lang_string_set(element, NS_AAS + "langStringTextType", object_class, **kwargs) + + @classmethod + def construct_definition_type_iec61360(cls, element: etree.Element, object_class=model.DefinitionTypeIEC61360, + **kwargs: Any) -> model.DefinitionTypeIEC61360: + return cls.construct_lang_string_set(element, NS_AAS + "langStringDefinitionTypeIec61360", object_class, + **kwargs) + + @classmethod + def construct_preferred_name_type_iec61360(cls, element: etree.Element, + object_class=model.PreferredNameTypeIEC61360, + **kwargs: Any) -> model.PreferredNameTypeIEC61360: + return cls.construct_lang_string_set(element, NS_AAS + "langStringPreferredNameTypeIec61360", object_class, + **kwargs) + + @classmethod + def construct_short_name_type_iec61360(cls, element: etree.Element, object_class=model.ShortNameTypeIEC61360, + **kwargs: Any) -> model.ShortNameTypeIEC61360: + return cls.construct_lang_string_set(element, NS_AAS + "langStringShortNameTypeIec61360", object_class, + **kwargs) @classmethod def construct_qualifier(cls, element: etree.Element, object_class=model.Qualifier, **_kwargs: Any) \ @@ -590,6 +670,9 @@ def construct_qualifier(cls, element: etree.Element, object_class=model.Qualifie _child_text_mandatory(element, NS_AAS + "type"), _child_text_mandatory_mapped(element, NS_AAS + "valueType", model.datatypes.XSD_TYPE_CLASSES) ) + kind = _get_text_mapped_or_none(element.find(NS_AAS + "kind"), QUALIFIER_KIND_INVERSE) + if kind is not None: + qualifier.kind = kind value = _get_text_or_none(element.find(NS_AAS + "value")) if value is not None: qualifier.value = model.datatypes.from_xsd(value, qualifier.value_type) @@ -600,52 +683,23 @@ def construct_qualifier(cls, element: etree.Element, object_class=model.Qualifie return qualifier @classmethod - def construct_formula(cls, element: etree.Element, object_class=model.Formula, **_kwargs: Any) -> model.Formula: - formula = object_class() - depends_on_refs = element.find(NS_AAS + "dependsOnRefs") - if depends_on_refs is not None: - for ref in _failsafe_construct_multiple(depends_on_refs.findall(NS_AAS + "reference"), - cls.construct_reference, cls.failsafe): - formula.depends_on.add(ref) - return formula - - @classmethod - def construct_identifier(cls, element: etree.Element, object_class=model.Identifier, **_kwargs: Any) \ - -> model.Identifier: - return object_class( - _get_text_mandatory(element), - _get_attrib_mandatory_mapped(element, "idType", IDENTIFIER_TYPES_INVERSE) - ) - - @classmethod - def construct_security(cls, _element: etree.Element, object_class=model.Security, **_kwargs: Any) -> model.Security: - """ - TODO: this is just a stub implementation - """ - return object_class() - - @classmethod - def construct_view(cls, element: etree.Element, object_class=model.View, **_kwargs: Any) -> model.View: - view = object_class(_child_text_mandatory(element, NS_AAS + "idShort")) - contained_elements = element.find(NS_AAS + "containedElements") - if contained_elements is not None: - for ref in _failsafe_construct_multiple(contained_elements.findall(NS_AAS + "containedElementRef"), - cls._construct_referable_reference, cls.failsafe): - view.contained_element.add(ref) - cls._amend_abstract_attributes(view, element) - return view - - @classmethod - def construct_concept_dictionary(cls, element: etree.Element, object_class=model.ConceptDictionary, - **_kwargs: Any) -> model.ConceptDictionary: - concept_dictionary = object_class(_child_text_mandatory(element, NS_AAS + "idShort")) - concept_description = element.find(NS_AAS + "conceptDescriptionRefs") - if concept_description is not None: - for ref in _failsafe_construct_multiple(concept_description.findall(NS_AAS + "conceptDescriptionRef"), - cls._construct_concept_description_reference, cls.failsafe): - concept_dictionary.concept_description.add(ref) - cls._amend_abstract_attributes(concept_dictionary, element) - return concept_dictionary + def construct_extension(cls, element: etree.Element, object_class=model.Extension, **_kwargs: Any) \ + -> model.Extension: + extension = object_class( + _child_text_mandatory(element, NS_AAS + "name")) + value_type = _get_text_or_none(element.find(NS_AAS + "valueType")) + if value_type is not None: + extension.value_type = model.datatypes.XSD_TYPE_CLASSES[value_type] + value = _get_text_or_none(element.find(NS_AAS + "value")) + if value is not None: + extension.value = model.datatypes.from_xsd(value, extension.value_type) + refers_to = element.find(NS_AAS + "refersTo") + if refers_to is not None: + for ref in _child_construct_multiple(refers_to, NS_AAS + "reference", cls._construct_referable_reference, + cls.failsafe): + extension.refers_to.add(ref) + cls._amend_abstract_attributes(extension, element) + return extension @classmethod def construct_submodel_element(cls, element: etree.Element, **kwargs: Any) -> model.SubmodelElement: @@ -653,20 +707,16 @@ def construct_submodel_element(cls, element: etree.Element, **kwargs: Any) -> mo This function doesn't support the object_class parameter. Overwrite each individual SubmodelElement/DataElement constructor function instead. """ - # unlike in construct_data_elements, we have to declare a submodel_elements dict without namespace here first - # because mypy doesn't automatically infer Callable[..., model.SubmodelElement] for the functions, because - # construct_submodel_element_collection doesn't have the object_class parameter, but object_class_ordered and - # object_class_unordered - submodel_elements: Dict[str, Callable[..., model.SubmodelElement]] = { + submodel_elements: Dict[str, Callable[..., model.SubmodelElement]] = {NS_AAS + k: v for k, v in { "annotatedRelationshipElement": cls.construct_annotated_relationship_element, - "basicEvent": cls.construct_basic_event, + "basicEventElement": cls.construct_basic_event_element, "capability": cls.construct_capability, "entity": cls.construct_entity, "operation": cls.construct_operation, "relationshipElement": cls.construct_relationship_element, - "submodelElementCollection": cls.construct_submodel_element_collection - } - submodel_elements = {NS_AAS + k: v for k, v in submodel_elements.items()} + "submodelElementCollection": cls.construct_submodel_element_collection, + "submodelElementList": cls.construct_submodel_element_list + }.items()} if element.tag not in submodel_elements: return cls.construct_data_element(element, abstract_class_name="SubmodelElement", **kwargs) return submodel_elements[element.tag](element, **kwargs) @@ -690,66 +740,52 @@ def construct_data_element(cls, element: etree.Element, abstract_class_name: str raise KeyError(_element_pretty_identifier(element) + f" is not a valid {abstract_class_name}!") return data_elements[element.tag](element, **kwargs) - @classmethod - def construct_constraint(cls, element: etree.Element, **kwargs: Any) -> model.Constraint: - """ - This function does not support the object_class parameter. - Overwrite construct_formula or construct_qualifier instead. - """ - constraints: Dict[str, Callable[..., model.Constraint]] = {NS_AAS + k: v for k, v in { - "formula": cls.construct_formula, - "qualifier": cls.construct_qualifier - }.items()} - if element.tag not in constraints: - raise KeyError(_element_pretty_identifier(element) + " is not a valid Constraint!") - return constraints[element.tag](element, **kwargs) - - @classmethod - def construct_operation_variable(cls, element: etree.Element, object_class=model.OperationVariable, - **_kwargs: Any) -> model.OperationVariable: - value = _get_child_mandatory(element, NS_AAS + "value") - if len(value) == 0: - raise KeyError(f"{_element_pretty_identifier(value)} has no submodel element!") - if len(value) > 1: - logger.warning(f"{_element_pretty_identifier(value)} has more than one submodel element, " - "using the first one...") - return object_class( - _failsafe_construct_mandatory(value[0], cls.construct_submodel_element) - ) - @classmethod def construct_annotated_relationship_element(cls, element: etree.Element, object_class=model.AnnotatedRelationshipElement, **_kwargs: Any) \ -> model.AnnotatedRelationshipElement: annotated_relationship_element = cls._construct_relationship_element_internal(element, object_class) if not cls.stripped: - for data_element in _get_child_mandatory(element, NS_AAS + "annotations"): - if len(data_element) == 0: - raise KeyError(f"{_element_pretty_identifier(data_element)} has no data element!") - if len(data_element) > 1: - logger.warning(f"{_element_pretty_identifier(data_element)} has more than one data element, " - "which is invalid! Deserializing all data elements anyways...") - for constructed in _failsafe_construct_multiple(data_element, cls.construct_data_element, cls.failsafe): - annotated_relationship_element.annotation.add(constructed) + annotations = element.find(NS_AAS + "annotations") + if annotations is not None: + for data_element in _failsafe_construct_multiple(annotations, cls.construct_data_element, + cls.failsafe): + annotated_relationship_element.annotation.add(data_element) return annotated_relationship_element @classmethod - def construct_basic_event(cls, element: etree.Element, object_class=model.BasicEvent, **_kwargs: Any) \ - -> model.BasicEvent: - basic_event = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), + def construct_basic_event_element(cls, element: etree.Element, object_class=model.BasicEventElement, + **_kwargs: Any) -> model.BasicEventElement: + basic_event_element = object_class( + None, _child_construct_mandatory(element, NS_AAS + "observed", cls._construct_referable_reference), - kind=_get_modeling_kind(element) + _child_text_mandatory_mapped(element, NS_AAS + "direction", DIRECTION_INVERSE), + _child_text_mandatory_mapped(element, NS_AAS + "state", STATE_OF_EVENT_INVERSE) ) - cls._amend_abstract_attributes(basic_event, element) - return basic_event + message_topic = _get_text_or_none(element.find(NS_AAS + "messageTopic")) + if message_topic is not None: + basic_event_element.message_topic = message_topic + message_broker = element.find(NS_AAS + "messageBroker") + if message_broker is not None: + basic_event_element.message_broker = _failsafe_construct(message_broker, cls.construct_reference, + cls.failsafe) + last_update = _get_text_or_none(element.find(NS_AAS + "lastUpdate")) + if last_update is not None: + basic_event_element.last_update = model.datatypes.from_xsd(last_update, model.datatypes.DateTime) + min_interval = _get_text_or_none(element.find(NS_AAS + "minInterval")) + if min_interval is not None: + basic_event_element.min_interval = model.datatypes.from_xsd(min_interval, model.datatypes.Duration) + max_interval = _get_text_or_none(element.find(NS_AAS + "maxInterval")) + if max_interval is not None: + basic_event_element.max_interval = model.datatypes.from_xsd(max_interval, model.datatypes.Duration) + cls._amend_abstract_attributes(basic_event_element, element) + return basic_event_element @classmethod def construct_blob(cls, element: etree.Element, object_class=model.Blob, **_kwargs: Any) -> model.Blob: blob = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - _child_text_mandatory(element, NS_AAS + "mimeType"), - kind=_get_modeling_kind(element) + None, + _child_text_mandatory(element, NS_AAS + "contentType") ) value = _get_text_or_none(element.find(NS_AAS + "value")) if value is not None: @@ -760,44 +796,39 @@ def construct_blob(cls, element: etree.Element, object_class=model.Blob, **_kwar @classmethod def construct_capability(cls, element: etree.Element, object_class=model.Capability, **_kwargs: Any) \ -> model.Capability: - capability = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - kind=_get_modeling_kind(element) - ) + capability = object_class(None) cls._amend_abstract_attributes(capability, element) return capability @classmethod def construct_entity(cls, element: etree.Element, object_class=model.Entity, **_kwargs: Any) -> model.Entity: + specific_asset_id = set() + specific_assset_ids = element.find(NS_AAS + "specificAssetIds") + if specific_assset_ids is not None: + for id in _child_construct_multiple(specific_assset_ids, NS_AAS + "specificAssetId", + cls.construct_specific_asset_id, cls.failsafe): + specific_asset_id.add(id) + entity = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - _child_text_mandatory_mapped(element, NS_AAS + "entityType", ENTITY_TYPES_INVERSE), - # pass the asset to the constructor, because self managed entities need asset references - asset=_failsafe_construct(element.find(NS_AAS + "assetRef"), cls._construct_asset_reference, cls.failsafe), - kind=_get_modeling_kind(element) - ) + id_short=None, + entity_type=_child_text_mandatory_mapped(element, NS_AAS + "entityType", ENTITY_TYPES_INVERSE), + global_asset_id=_get_text_or_none(element.find(NS_AAS + "globalAssetId")), + specific_asset_id=specific_asset_id) + if not cls.stripped: - # TODO: remove wrapping submodelElement, in accordance to future schemas - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 - statements = _get_child_mandatory(element, NS_AAS + "statements") - for submodel_element in _get_all_children_expect_tag(statements, NS_AAS + "submodelElement", cls.failsafe): - if len(submodel_element) == 0: - raise KeyError(f"{_element_pretty_identifier(submodel_element)} has no submodel element!") - if len(submodel_element) > 1: - logger.warning(f"{_element_pretty_identifier(submodel_element)} has more than one submodel element," - " which is invalid! Deserializing all submodel elements anyways...") - for constructed in _failsafe_construct_multiple(submodel_element, cls.construct_submodel_element, - cls.failsafe): - entity.statement.add(constructed) + statements = element.find(NS_AAS + "statements") + if statements is not None: + for submodel_element in _failsafe_construct_multiple(statements, cls.construct_submodel_element, + cls.failsafe): + entity.statement.add(submodel_element) cls._amend_abstract_attributes(entity, element) return entity @classmethod def construct_file(cls, element: etree.Element, object_class=model.File, **_kwargs: Any) -> model.File: file = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - _child_text_mandatory(element, NS_AAS + "mimeType"), - kind=_get_modeling_kind(element) + None, + _child_text_mandatory(element, NS_AAS + "contentType") ) value = _get_text_or_none(element.find(NS_AAS + "value")) if value is not None: @@ -805,14 +836,23 @@ def construct_file(cls, element: etree.Element, object_class=model.File, **_kwar cls._amend_abstract_attributes(file, element) return file + @classmethod + def construct_resource(cls, element: etree.Element, object_class=model.Resource, **_kwargs: Any) -> model.Resource: + resource = object_class( + _child_text_mandatory(element, NS_AAS + "path") + ) + content_type = _get_text_or_none(element.find(NS_AAS + "contentType")) + if content_type is not None: + resource.content_type = content_type + cls._amend_abstract_attributes(resource, element) + return resource + @classmethod def construct_multi_language_property(cls, element: etree.Element, object_class=model.MultiLanguageProperty, **_kwargs: Any) -> model.MultiLanguageProperty: - multi_language_property = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - kind=_get_modeling_kind(element) - ) - value = _failsafe_construct(element.find(NS_AAS + "value"), cls.construct_lang_string_set, cls.failsafe) + multi_language_property = object_class(None) + value = _failsafe_construct(element.find(NS_AAS + "value"), cls.construct_multi_language_text_type, + cls.failsafe) if value is not None: multi_language_property.value = value value_id = _failsafe_construct(element.find(NS_AAS + "valueId"), cls.construct_reference, cls.failsafe) @@ -824,28 +864,23 @@ def construct_multi_language_property(cls, element: etree.Element, object_class= @classmethod def construct_operation(cls, element: etree.Element, object_class=model.Operation, **_kwargs: Any) \ -> model.Operation: - operation = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - kind=_get_modeling_kind(element) - ) - for input_variable in _failsafe_construct_multiple(element.findall(NS_AAS + "inputVariable"), - cls.construct_operation_variable, cls.failsafe): - operation.input_variable.append(input_variable) - for output_variable in _failsafe_construct_multiple(element.findall(NS_AAS + "outputVariable"), - cls.construct_operation_variable, cls.failsafe): - operation.output_variable.append(output_variable) - for in_output_variable in _failsafe_construct_multiple(element.findall(NS_AAS + "inoutputVariable"), - cls.construct_operation_variable, cls.failsafe): - operation.in_output_variable.append(in_output_variable) + operation = object_class(None) + for tag, target in ((NS_AAS + "inputVariables", operation.input_variable), + (NS_AAS + "outputVariables", operation.output_variable), + (NS_AAS + "inoutputVariables", operation.in_output_variable)): + variables = element.find(tag) + if variables is not None: + for var in _child_construct_multiple(variables, NS_AAS + "operationVariable", + cls._construct_operation_variable, cls.failsafe): + target.add(var) cls._amend_abstract_attributes(operation, element) return operation @classmethod def construct_property(cls, element: etree.Element, object_class=model.Property, **_kwargs: Any) -> model.Property: property_ = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - value_type=_child_text_mandatory_mapped(element, NS_AAS + "valueType", model.datatypes.XSD_TYPE_CLASSES), - kind=_get_modeling_kind(element) + None, + value_type=_child_text_mandatory_mapped(element, NS_AAS + "valueType", model.datatypes.XSD_TYPE_CLASSES) ) value = _get_text_or_none(element.find(NS_AAS + "value")) if value is not None: @@ -859,9 +894,8 @@ def construct_property(cls, element: etree.Element, object_class=model.Property, @classmethod def construct_range(cls, element: etree.Element, object_class=model.Range, **_kwargs: Any) -> model.Range: range_ = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - value_type=_child_text_mandatory_mapped(element, NS_AAS + "valueType", model.datatypes.XSD_TYPE_CLASSES), - kind=_get_modeling_kind(element) + None, + value_type=_child_text_mandatory_mapped(element, NS_AAS + "valueType", model.datatypes.XSD_TYPE_CLASSES) ) max_ = _get_text_or_none(element.find(NS_AAS + "max")) if max_ is not None: @@ -875,10 +909,7 @@ def construct_range(cls, element: etree.Element, object_class=model.Range, **_kw @classmethod def construct_reference_element(cls, element: etree.Element, object_class=model.ReferenceElement, **_kwargs: Any) \ -> model.ReferenceElement: - reference_element = object_class( - _child_text_mandatory(element, NS_AAS + "idShort"), - kind=_get_modeling_kind(element) - ) + reference_element = object_class(None) value = _failsafe_construct(element.find(NS_AAS + "value"), cls.construct_reference, cls.failsafe) if value is not None: reference_element.value = value @@ -891,57 +922,58 @@ def construct_relationship_element(cls, element: etree.Element, object_class=mod return cls._construct_relationship_element_internal(element, object_class=object_class, **_kwargs) @classmethod - def construct_submodel_element_collection(cls, element: etree.Element, - object_class_ordered=model.SubmodelElementCollectionOrdered, - object_class_unordered=model.SubmodelElementCollectionUnordered, + def construct_submodel_element_collection(cls, element: etree.Element, object_class=model.SubmodelElementCollection, **_kwargs: Any) -> model.SubmodelElementCollection: - ordered = _str_to_bool(_child_text_mandatory(element, NS_AAS + "ordered")) - collection_type = object_class_ordered if ordered else object_class_unordered - collection = collection_type( - _child_text_mandatory(element, NS_AAS + "idShort"), - kind=_get_modeling_kind(element) - ) + collection = object_class(None) if not cls.stripped: - value = _get_child_mandatory(element, NS_AAS + "value") - # TODO: simplify this should our suggestion regarding the XML schema get accepted - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 - for submodel_element in _get_all_children_expect_tag(value, NS_AAS + "submodelElement", cls.failsafe): - if len(submodel_element) == 0: - raise KeyError(f"{_element_pretty_identifier(submodel_element)} has no submodel element!") - if len(submodel_element) > 1: - logger.warning(f"{_element_pretty_identifier(submodel_element)} has more than one submodel element," - " which is invalid! Deserializing all submodel elements anyways...") - for constructed in _failsafe_construct_multiple(submodel_element, cls.construct_submodel_element, - cls.failsafe): - collection.value.add(constructed) + value = element.find(NS_AAS + "value") + if value is not None: + for submodel_element in _failsafe_construct_multiple(value, cls.construct_submodel_element, + cls.failsafe): + collection.value.add(submodel_element) cls._amend_abstract_attributes(collection, element) return collection + @classmethod + def construct_submodel_element_list(cls, element: etree.Element, object_class=model.SubmodelElementList, + **_kwargs: Any) -> model.SubmodelElementList: + type_value_list_element = KEY_TYPES_CLASSES_INVERSE[ + _child_text_mandatory_mapped(element, NS_AAS + "typeValueListElement", KEY_TYPES_INVERSE)] + if not issubclass(type_value_list_element, model.SubmodelElement): + raise ValueError("Expected a SubmodelElementList with a typeValueListElement that is a subclass of" + f"{model.SubmodelElement}, got {type_value_list_element}!") + order_relevant = element.find(NS_AAS + "orderRelevant") + list_ = object_class( + None, + type_value_list_element, + semantic_id_list_element=_failsafe_construct(element.find(NS_AAS + "semanticIdListElement"), + cls.construct_reference, cls.failsafe), + value_type_list_element=_get_text_mapped_or_none(element.find(NS_AAS + "valueTypeListElement"), + model.datatypes.XSD_TYPE_CLASSES), + order_relevant=_str_to_bool(_get_text_mandatory(order_relevant)) + if order_relevant is not None else True + ) + if not cls.stripped: + value = element.find(NS_AAS + "value") + if value is not None: + list_.value.extend(_failsafe_construct_multiple(value, cls.construct_submodel_element, cls.failsafe)) + cls._amend_abstract_attributes(list_, element) + return list_ + @classmethod def construct_asset_administration_shell(cls, element: etree.Element, object_class=model.AssetAdministrationShell, **_kwargs: Any) -> model.AssetAdministrationShell: aas = object_class( - _child_construct_mandatory(element, NS_AAS + "assetRef", cls._construct_asset_reference), - _child_construct_mandatory(element, NS_AAS + "identification", cls.construct_identifier) + id_=_child_text_mandatory(element, NS_AAS + "id"), + asset_information=_child_construct_mandatory(element, NS_AAS + "assetInformation", + cls.construct_asset_information) ) - security = _failsafe_construct(element.find(NS_ABAC + "security"), cls.construct_security, cls.failsafe) - if security is not None: - aas.security = security if not cls.stripped: - submodels = element.find(NS_AAS + "submodelRefs") + submodels = element.find(NS_AAS + "submodels") if submodels is not None: - for ref in _child_construct_multiple(submodels, NS_AAS + "submodelRef", + for ref in _child_construct_multiple(submodels, NS_AAS + "reference", cls._construct_submodel_reference, cls.failsafe): aas.submodel.add(ref) - views = element.find(NS_AAS + "views") - if views is not None: - for view in _child_construct_multiple(views, NS_AAS + "view", cls.construct_view, cls.failsafe): - aas.view.add(view) - concept_dictionaries = element.find(NS_AAS + "conceptDictionaries") - if concept_dictionaries is not None: - for cd in _child_construct_multiple(concept_dictionaries, NS_AAS + "conceptDictionary", - cls.construct_concept_dictionary, cls.failsafe): - aas.concept_dictionary.add(cd) derived_from = _failsafe_construct(element.find(NS_AAS + "derivedFrom"), cls._construct_asset_administration_shell_reference, cls.failsafe) if derived_from is not None: @@ -950,162 +982,183 @@ def construct_asset_administration_shell(cls, element: etree.Element, object_cla return aas @classmethod - def construct_asset(cls, element: etree.Element, object_class=model.Asset, **_kwargs: Any) -> model.Asset: - asset = object_class( - _child_text_mandatory_mapped(element, NS_AAS + "kind", ASSET_KIND_INVERSE), - _child_construct_mandatory(element, NS_AAS + "identification", cls.construct_identifier) + def construct_specific_asset_id(cls, element: etree.Element, object_class=model.SpecificAssetId, + **_kwargs: Any) -> model.SpecificAssetId: + # semantic_id can't be applied by _amend_abstract_attributes because specificAssetId is immutable + return object_class( + name=_get_text_or_none(element.find(NS_AAS + "name")), + value=_get_text_or_none(element.find(NS_AAS + "value")), + external_subject_id=_failsafe_construct(element.find(NS_AAS + "externalSubjectId"), + cls.construct_external_reference, cls.failsafe), + semantic_id=_failsafe_construct(element.find(NS_AAS + "semanticId"), cls.construct_reference, cls.failsafe) + ) + + @classmethod + def construct_asset_information(cls, element: etree.Element, object_class=model.AssetInformation, **_kwargs: Any) \ + -> model.AssetInformation: + specific_asset_id = set() + specific_assset_ids = element.find(NS_AAS + "specificAssetIds") + if specific_assset_ids is not None: + for id in _child_construct_multiple(specific_assset_ids, NS_AAS + "specificAssetId", + cls.construct_specific_asset_id, cls.failsafe): + specific_asset_id.add(id) + + asset_information = object_class( + _child_text_mandatory_mapped(element, NS_AAS + "assetKind", ASSET_KIND_INVERSE), + global_asset_id=_get_text_or_none(element.find(NS_AAS + "globalAssetId")), + specific_asset_id=specific_asset_id, ) - asset_identification_model = _failsafe_construct(element.find(NS_AAS + "assetIdentificationModelRef"), - cls._construct_submodel_reference, cls.failsafe) - if asset_identification_model is not None: - asset.asset_identification_model = asset_identification_model - bill_of_material = _failsafe_construct(element.find(NS_AAS + "billOfMaterialRef"), - cls._construct_submodel_reference, cls.failsafe) - if bill_of_material is not None: - asset.bill_of_material = bill_of_material - cls._amend_abstract_attributes(asset, element) - return asset + + asset_type = _get_text_or_none(element.find(NS_AAS + "assetType")) + if asset_type is not None: + asset_information.asset_type = asset_type + thumbnail = _failsafe_construct(element.find(NS_AAS + "defaultThumbnail"), + cls.construct_resource, cls.failsafe) + if thumbnail is not None: + asset_information.default_thumbnail = thumbnail + + cls._amend_abstract_attributes(asset_information, element) + return asset_information @classmethod def construct_submodel(cls, element: etree.Element, object_class=model.Submodel, **_kwargs: Any) \ -> model.Submodel: submodel = object_class( - _child_construct_mandatory(element, NS_AAS + "identification", cls.construct_identifier), - kind=_get_modeling_kind(element) + _child_text_mandatory(element, NS_AAS + "id"), + kind=_get_kind(element) ) if not cls.stripped: - # TODO: simplify this should our suggestion regarding the XML schema get accepted - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 - for submodel_element in _get_all_children_expect_tag( - _get_child_mandatory(element, NS_AAS + "submodelElements"), NS_AAS + "submodelElement", - cls.failsafe): - if len(submodel_element) == 0: - raise KeyError(f"{_element_pretty_identifier(submodel_element)} has no submodel element!") - if len(submodel_element) > 1: - logger.warning(f"{_element_pretty_identifier(submodel_element)} has more than one submodel element," - " which is invalid! Deserializing all submodel elements anyways...") - for constructed in _failsafe_construct_multiple(submodel_element, cls.construct_submodel_element, - cls.failsafe): - submodel.submodel_element.add(constructed) + submodel_elements = element.find(NS_AAS + "submodelElements") + if submodel_elements is not None: + for submodel_element in _failsafe_construct_multiple(submodel_elements, cls.construct_submodel_element, + cls.failsafe): + submodel.submodel_element.add(submodel_element) cls._amend_abstract_attributes(submodel, element) return submodel @classmethod - def construct_value_reference_pair(cls, element: etree.Element, value_format: Optional[model.DataTypeDef] = None, - object_class=model.ValueReferencePair, **_kwargs: Any) \ - -> model.ValueReferencePair: - if value_format is None: - raise ValueError("No value format given!") - return object_class( - value_format, - model.datatypes.from_xsd(_child_text_mandatory(element, NS_IEC + "value"), value_format), - _child_construct_mandatory(element, NS_IEC + "valueId", cls.construct_reference, namespace=NS_IEC) - ) + def construct_value_reference_pair(cls, element: etree.Element, object_class=model.ValueReferencePair, + **_kwargs: Any) -> model.ValueReferencePair: + return object_class(_child_text_mandatory(element, NS_AAS + "value"), + _child_construct_mandatory(element, NS_AAS + "valueId", cls.construct_reference)) @classmethod - def construct_value_list(cls, element: etree.Element, value_format: Optional[model.DataTypeDef] = None, - **_kwargs: Any) -> model.ValueList: + def construct_value_list(cls, element: etree.Element, **_kwargs: Any) -> model.ValueList: """ This function doesn't support the object_class parameter, because ValueList is just a generic type alias. """ + return set( - _child_construct_multiple(element, NS_IEC + "valueReferencePair", cls.construct_value_reference_pair, - cls.failsafe, value_format=value_format) + _child_construct_multiple(_get_child_mandatory(element, NS_AAS + "valueReferencePairs"), + NS_AAS + "valueReferencePair", cls.construct_value_reference_pair, + cls.failsafe) ) @classmethod - def construct_iec61360_concept_description(cls, element: etree.Element, - identifier: Optional[model.Identifier] = None, - object_class=model.IEC61360ConceptDescription, **_kwargs: Any) \ - -> model.IEC61360ConceptDescription: - if identifier is None: - raise ValueError("No identifier given!") - cd = object_class( - identifier, - _child_construct_mandatory(element, NS_IEC + "preferredName", cls.construct_lang_string_set, - namespace=NS_IEC) + def construct_concept_description(cls, element: etree.Element, object_class=model.ConceptDescription, + **_kwargs: Any) -> model.ConceptDescription: + cd = object_class(_child_text_mandatory(element, NS_AAS + "id")) + is_case_of = element.find(NS_AAS + "isCaseOf") + if is_case_of is not None: + for ref in _child_construct_multiple(is_case_of, NS_AAS + "reference", cls.construct_reference, + cls.failsafe): + cd.is_case_of.add(ref) + cls._amend_abstract_attributes(cd, element) + return cd + + @classmethod + def construct_embedded_data_specification(cls, element: etree.Element, object_class=model.EmbeddedDataSpecification, + **_kwargs: Any) -> model.EmbeddedDataSpecification: + data_specification_content = _get_child_mandatory(element, NS_AAS + "dataSpecificationContent") + if len(data_specification_content) == 0: + raise KeyError(f"{_element_pretty_identifier(data_specification_content)} has no data specification!") + if len(data_specification_content) > 1: + logger.warning(f"{_element_pretty_identifier(data_specification_content)} has more than one " + "data specification, using the first one...") + embedded_data_specification = object_class( + _child_construct_mandatory(element, NS_AAS + "dataSpecification", cls.construct_external_reference), + _failsafe_construct_mandatory(data_specification_content[0], cls.construct_data_specification_content) ) - data_type = _get_text_mapped_or_none(element.find(NS_IEC + "dataType"), IEC61360_DATA_TYPES_INVERSE) - if data_type is not None: - cd.data_type = data_type - definition = _failsafe_construct(element.find(NS_IEC + "definition"), cls.construct_lang_string_set, - cls.failsafe, namespace=NS_IEC) - if definition is not None: - cd.definition = definition - short_name = _failsafe_construct(element.find(NS_IEC + "shortName"), cls.construct_lang_string_set, - cls.failsafe, namespace=NS_IEC) + cls._amend_abstract_attributes(embedded_data_specification, element) + return embedded_data_specification + + @classmethod + def construct_data_specification_content(cls, element: etree.Element, **kwargs: Any) \ + -> model.DataSpecificationContent: + """ + This function doesn't support the object_class parameter. + Overwrite each individual DataSpecificationContent constructor function instead. + """ + data_specification_contents: Dict[str, Callable[..., model.DataSpecificationContent]] = \ + {NS_AAS + k: v for k, v in { + "dataSpecificationIec61360": cls.construct_data_specification_iec61360, + }.items()} + if element.tag not in data_specification_contents: + raise KeyError(f"{_element_pretty_identifier(element)} is not a valid DataSpecificationContent!") + return data_specification_contents[element.tag](element, **kwargs) + + @classmethod + def construct_data_specification_iec61360(cls, element: etree.Element, object_class=model.DataSpecificationIEC61360, + **_kwargs: Any) -> model.DataSpecificationIEC61360: + ds_iec = object_class(_child_construct_mandatory(element, NS_AAS + "preferredName", + cls.construct_preferred_name_type_iec61360)) + short_name = _failsafe_construct(element.find(NS_AAS + "shortName"), cls.construct_short_name_type_iec61360, + cls.failsafe) if short_name is not None: - cd.short_name = short_name - unit = _get_text_or_none(element.find(NS_IEC + "unit")) + ds_iec.short_name = short_name + unit = _get_text_or_none(element.find(NS_AAS + "unit")) if unit is not None: - cd.unit = unit - unit_id = _failsafe_construct(element.find(NS_IEC + "unitId"), cls.construct_reference, cls.failsafe, - namespace=NS_IEC) + ds_iec.unit = unit + unit_id = _failsafe_construct(element.find(NS_AAS + "unitId"), cls.construct_reference, cls.failsafe) if unit_id is not None: - cd.unit_id = unit_id - source_of_definition = _get_text_or_none(element.find(NS_IEC + "sourceOfDefinition")) - if source_of_definition is not None: - cd.source_of_definition = source_of_definition - symbol = _get_text_or_none(element.find(NS_IEC + "symbol")) + ds_iec.unit_id = unit_id + source_of_definiion = _get_text_or_none(element.find(NS_AAS + "sourceOfDefinition")) + if source_of_definiion is not None: + ds_iec.source_of_definition = source_of_definiion + symbol = _get_text_or_none(element.find(NS_AAS + "symbol")) if symbol is not None: - cd.symbol = symbol - value_format = _get_text_mapped_or_none(element.find(NS_IEC + "valueFormat"), - model.datatypes.XSD_TYPE_CLASSES) + ds_iec.symbol = symbol + data_type = _get_text_mapped_or_none(element.find(NS_AAS + "dataType"), IEC61360_DATA_TYPES_INVERSE) + if data_type is not None: + ds_iec.data_type = data_type + definition = _failsafe_construct(element.find(NS_AAS + "definition"), cls.construct_definition_type_iec61360, + cls.failsafe) + if definition is not None: + ds_iec.definition = definition + value_format = _get_text_or_none(element.find(NS_AAS + "valueFormat")) if value_format is not None: - cd.value_format = value_format - value_list = _failsafe_construct(element.find(NS_IEC + "valueList"), cls.construct_value_list, cls.failsafe, - value_format=value_format) + ds_iec.value_format = value_format + value_list = _failsafe_construct(element.find(NS_AAS + "valueList"), cls.construct_value_list, cls.failsafe) if value_list is not None: - cd.value_list = value_list - value = _get_text_or_none(element.find(NS_IEC + "value")) + ds_iec.value_list = value_list + value = _get_text_or_none(element.find(NS_AAS + "value")) if value is not None and value_format is not None: - cd.value = model.datatypes.from_xsd(value, value_format) - value_id = _failsafe_construct(element.find(NS_IEC + "valueId"), cls.construct_reference, cls.failsafe, - namespace=NS_IEC) - if value_id is not None: - cd.value_id = value_id - for level_type_element in element.findall(NS_IEC + "levelType"): - level_type = _get_text_mapped_or_none(level_type_element, IEC61360_LEVEL_TYPES_INVERSE) - if level_type is None: - error_message = f"{_element_pretty_identifier(level_type_element)} has invalid value: " \ - + str(level_type_element.text) - if not cls.failsafe: - raise ValueError(error_message) - logger.warning(error_message) - continue - cd.level_types.add(level_type) - return cd - - @classmethod - def construct_concept_description(cls, element: etree.Element, object_class=model.ConceptDescription, - **_kwargs: Any) -> model.ConceptDescription: - cd: Optional[model.ConceptDescription] = None - identifier = _child_construct_mandatory(element, NS_AAS + "identification", cls.construct_identifier) - # Hack to detect IEC61360ConceptDescriptions, which are represented using dataSpecification according to DotAAS - dspec_tag = NS_AAS + "embeddedDataSpecification" - dspecs = element.findall(dspec_tag) - if len(dspecs) > 1: - logger.warning(f"{_element_pretty_identifier(element)} has more than one " - f"{_tag_replace_namespace(dspec_tag, element.nsmap)}. This model currently supports only one" - f" per {_tag_replace_namespace(element.tag, element.nsmap)}!") - if len(dspecs) > 0: - dspec = dspecs[0] - dspec_content = dspec.find(NS_AAS + "dataSpecificationContent") - if dspec_content is not None: - dspec_ref = _failsafe_construct(dspec.find(NS_AAS + "dataSpecification"), cls.construct_reference, - cls.failsafe) - if dspec_ref is not None and len(dspec_ref.key) > 0 and dspec_ref.key[0].value == \ - "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0": - cd = _failsafe_construct(dspec_content.find(NS_AAS + "dataSpecificationIEC61360"), - cls.construct_iec61360_concept_description, cls.failsafe, - identifier=identifier) - if cd is None: - cd = object_class(identifier) - for ref in _failsafe_construct_multiple(element.findall(NS_AAS + "isCaseOf"), cls.construct_reference, - cls.failsafe): - cd.is_case_of.add(ref) - cls._amend_abstract_attributes(cd, element) - return cd + ds_iec.value = value + level_type = element.find(NS_AAS + "levelType") + if level_type is not None: + for child in level_type: + tag = child.tag.split(NS_AAS, 1)[-1] + if tag not in IEC61360_LEVEL_TYPES_INVERSE: + error_message = f"{_element_pretty_identifier(element)} has invalid levelType: {tag}" + if not cls.failsafe: + raise ValueError(error_message) + logger.warning(error_message) + continue + try: + if child.text is None: + raise ValueError + level_type_value = _str_to_bool(child.text) + except ValueError: + error_message = f"levelType {tag} of {_element_pretty_identifier(element)} has invalid boolean: " \ + + str(child.text) + if not cls.failsafe: + raise ValueError(error_message) + logger.warning(error_message) + continue + if level_type_value: + ds_iec.level_types.add(IEC61360_LEVEL_TYPES_INVERSE[tag]) + cls._amend_abstract_attributes(ds_iec, element) + return ds_iec class StrictAASFromXmlDecoder(AASFromXmlDecoder): @@ -1182,21 +1235,19 @@ class XMLConstructables(enum.Enum): """ KEY = enum.auto() REFERENCE = enum.auto() - AAS_REFERENCE = enum.auto() + MODEL_REFERENCE = enum.auto() + GLOBAL_REFERENCE = enum.auto() ADMINISTRATIVE_INFORMATION = enum.auto() QUALIFIER = enum.auto() - FORMULA = enum.auto() - IDENTIFIER = enum.auto() SECURITY = enum.auto() - VIEW = enum.auto() - CONCEPT_DICTIONARY = enum.auto() - OPERATION_VARIABLE = enum.auto() ANNOTATED_RELATIONSHIP_ELEMENT = enum.auto() - BASIC_EVENT = enum.auto() + BASIC_EVENT_ELEMENT = enum.auto() BLOB = enum.auto() CAPABILITY = enum.auto() ENTITY = enum.auto() + EXTENSION = enum.auto() FILE = enum.auto() + RESOURCE = enum.auto() MULTI_LANGUAGE_PROPERTY = enum.auto() OPERATION = enum.auto() PROPERTY = enum.auto() @@ -1204,17 +1255,25 @@ class XMLConstructables(enum.Enum): REFERENCE_ELEMENT = enum.auto() RELATIONSHIP_ELEMENT = enum.auto() SUBMODEL_ELEMENT_COLLECTION = enum.auto() + SUBMODEL_ELEMENT_LIST = enum.auto() ASSET_ADMINISTRATION_SHELL = enum.auto() - ASSET = enum.auto() + ASSET_INFORMATION = enum.auto() + SPECIFIC_ASSET_ID = enum.auto() SUBMODEL = enum.auto() VALUE_REFERENCE_PAIR = enum.auto() IEC61360_CONCEPT_DESCRIPTION = enum.auto() CONCEPT_DESCRIPTION = enum.auto() - CONSTRAINT = enum.auto() DATA_ELEMENT = enum.auto() SUBMODEL_ELEMENT = enum.auto() VALUE_LIST = enum.auto() - LANG_STRING_SET = enum.auto() + MULTI_LANGUAGE_NAME_TYPE = enum.auto() + MULTI_LANGUAGE_TEXT_TYPE = enum.auto() + DEFINITION_TYPE_IEC61360 = enum.auto() + PREFERRED_NAME_TYPE_IEC61360 = enum.auto() + SHORT_NAME_TYPE_IEC61360 = enum.auto() + EMBEDDED_DATA_SPECIFICATION = enum.auto() + DATA_SPECIFICATION_CONTENT = enum.auto() + DATA_SPECIFICATION_IEC61360 = enum.auto() def read_aas_xml_element(file: IO, construct: XMLConstructables, failsafe: bool = True, stripped: bool = False, @@ -1242,36 +1301,30 @@ def read_aas_xml_element(file: IO, construct: XMLConstructables, failsafe: bool constructor = decoder_.construct_key elif construct == XMLConstructables.REFERENCE: constructor = decoder_.construct_reference - elif construct == XMLConstructables.AAS_REFERENCE: - constructor = decoder_.construct_aas_reference + elif construct == XMLConstructables.MODEL_REFERENCE: + constructor = decoder_.construct_model_reference + elif construct == XMLConstructables.GLOBAL_REFERENCE: + constructor = decoder_.construct_external_reference elif construct == XMLConstructables.ADMINISTRATIVE_INFORMATION: constructor = decoder_.construct_administrative_information elif construct == XMLConstructables.QUALIFIER: constructor = decoder_.construct_qualifier - elif construct == XMLConstructables.FORMULA: - constructor = decoder_.construct_formula - elif construct == XMLConstructables.IDENTIFIER: - constructor = decoder_.construct_identifier - elif construct == XMLConstructables.SECURITY: - constructor = decoder_.construct_security - elif construct == XMLConstructables.VIEW: - constructor = decoder_.construct_view - elif construct == XMLConstructables.CONCEPT_DICTIONARY: - constructor = decoder_.construct_concept_dictionary - elif construct == XMLConstructables.OPERATION_VARIABLE: - constructor = decoder_.construct_operation_variable elif construct == XMLConstructables.ANNOTATED_RELATIONSHIP_ELEMENT: constructor = decoder_.construct_annotated_relationship_element - elif construct == XMLConstructables.BASIC_EVENT: - constructor = decoder_.construct_basic_event + elif construct == XMLConstructables.BASIC_EVENT_ELEMENT: + constructor = decoder_.construct_basic_event_element elif construct == XMLConstructables.BLOB: constructor = decoder_.construct_blob elif construct == XMLConstructables.CAPABILITY: constructor = decoder_.construct_capability elif construct == XMLConstructables.ENTITY: constructor = decoder_.construct_entity + elif construct == XMLConstructables.EXTENSION: + constructor = decoder_.construct_extension elif construct == XMLConstructables.FILE: constructor = decoder_.construct_file + elif construct == XMLConstructables.RESOURCE: + constructor = decoder_.construct_resource elif construct == XMLConstructables.MULTI_LANGUAGE_PROPERTY: constructor = decoder_.construct_multi_language_property elif construct == XMLConstructables.OPERATION: @@ -1286,30 +1339,44 @@ def read_aas_xml_element(file: IO, construct: XMLConstructables, failsafe: bool constructor = decoder_.construct_relationship_element elif construct == XMLConstructables.SUBMODEL_ELEMENT_COLLECTION: constructor = decoder_.construct_submodel_element_collection + elif construct == XMLConstructables.SUBMODEL_ELEMENT_LIST: + constructor = decoder_.construct_submodel_element_list elif construct == XMLConstructables.ASSET_ADMINISTRATION_SHELL: constructor = decoder_.construct_asset_administration_shell - elif construct == XMLConstructables.ASSET: - constructor = decoder_.construct_asset + elif construct == XMLConstructables.ASSET_INFORMATION: + constructor = decoder_.construct_asset_information + elif construct == XMLConstructables.SPECIFIC_ASSET_ID: + constructor = decoder_.construct_specific_asset_id elif construct == XMLConstructables.SUBMODEL: constructor = decoder_.construct_submodel elif construct == XMLConstructables.VALUE_REFERENCE_PAIR: constructor = decoder_.construct_value_reference_pair - elif construct == XMLConstructables.IEC61360_CONCEPT_DESCRIPTION: - constructor = decoder_.construct_iec61360_concept_description elif construct == XMLConstructables.CONCEPT_DESCRIPTION: constructor = decoder_.construct_concept_description + elif construct == XMLConstructables.MULTI_LANGUAGE_NAME_TYPE: + constructor = decoder_.construct_multi_language_name_type + elif construct == XMLConstructables.MULTI_LANGUAGE_TEXT_TYPE: + constructor = decoder_.construct_multi_language_text_type + elif construct == XMLConstructables.DEFINITION_TYPE_IEC61360: + constructor = decoder_.construct_definition_type_iec61360 + elif construct == XMLConstructables.PREFERRED_NAME_TYPE_IEC61360: + constructor = decoder_.construct_preferred_name_type_iec61360 + elif construct == XMLConstructables.SHORT_NAME_TYPE_IEC61360: + constructor = decoder_.construct_short_name_type_iec61360 + elif construct == XMLConstructables.EMBEDDED_DATA_SPECIFICATION: + constructor = decoder_.construct_embedded_data_specification + elif construct == XMLConstructables.DATA_SPECIFICATION_IEC61360: + constructor = decoder_.construct_data_specification_iec61360 # the following constructors decide which constructor to call based on the elements tag - elif construct == XMLConstructables.CONSTRAINT: - constructor = decoder_.construct_constraint elif construct == XMLConstructables.DATA_ELEMENT: constructor = decoder_.construct_data_element elif construct == XMLConstructables.SUBMODEL_ELEMENT: constructor = decoder_.construct_submodel_element + elif construct == XMLConstructables.DATA_SPECIFICATION_CONTENT: + constructor = decoder_.construct_data_specification_content # type aliases elif construct == XMLConstructables.VALUE_LIST: constructor = decoder_.construct_value_list - elif construct == XMLConstructables.LANG_STRING_SET: - constructor = decoder_.construct_lang_string_set else: raise ValueError(f"{construct.name} cannot be constructed!") @@ -1347,9 +1414,8 @@ def read_aas_xml_file_into(object_store: model.AbstractObjectStore[model.Identif element_constructors: Dict[str, Callable[..., model.Identifiable]] = { "assetAdministrationShell": decoder_.construct_asset_administration_shell, - "asset": decoder_.construct_asset, - "submodel": decoder_.construct_submodel, - "conceptDescription": decoder_.construct_concept_description + "conceptDescription": decoder_.construct_concept_description, + "submodel": decoder_.construct_submodel } element_constructors = {NS_AAS + k: v for k, v in element_constructors.items()} @@ -1370,16 +1436,16 @@ def read_aas_xml_file_into(object_store: model.AbstractObjectStore[model.Identif continue constructor = element_constructors[element_tag] for element in _child_construct_multiple(list_, element_tag, constructor, decoder_.failsafe): - if element.identification in ret: + if element.id in ret: error_message = f"{element} has a duplicate identifier already parsed in the document!" if not decoder_.failsafe: raise KeyError(error_message) logger.error(error_message + " skipping it...") continue - existing_element = object_store.get(element.identification) + existing_element = object_store.get(element.id) if existing_element is not None: if not replace_existing: - error_message = f"object with identifier {element.identification} already exists " \ + error_message = f"object with identifier {element.id} already exists " \ f"in the object store: {existing_element}!" if not ignore_existing: raise KeyError(error_message + f" failed to insert {element}!") @@ -1387,7 +1453,7 @@ def read_aas_xml_file_into(object_store: model.AbstractObjectStore[model.Identif continue object_store.discard(existing_element) object_store.add(element) - ret.add(element.identification) + ret.add(element.id) return ret diff --git a/basyx/aas/adapter/xml/xml_serialization.py b/basyx/aas/adapter/xml/xml_serialization.py index d734fb9c0..106535ae1 100644 --- a/basyx/aas/adapter/xml/xml_serialization.py +++ b/basyx/aas/adapter/xml/xml_serialization.py @@ -19,32 +19,19 @@ """ from lxml import etree # type: ignore -from typing import Dict, IO, Optional +from typing import Dict, IO, Optional, Type import base64 from basyx.aas import model from .. import _generic +NS_AAS = _generic.XML_NS_AAS + # ############################################################## # functions to manipulate etree.Elements more effectively # ############################################################## -# Namespace definition -NS_AAS = "{http://www.admin-shell.io/aas/2/0}" -NS_ABAC = "{http://www.admin-shell.io/aas/abac/2/0}" -NS_AAS_COMMON = "{http://www.admin-shell.io/aas_common/2/0}" -NS_XSI = "{http://www.w3.org/2001/XMLSchema-instance}" -NS_XS = "{http://www.w3.org/2001/XMLSchema}" -NS_IEC = "{http://www.admin-shell.io/IEC61360/2/0}" -NS_MAP = {"aas": "http://www.admin-shell.io/aas/2/0", - "abac": "http://www.admin-shell.io/aas/abac/2/0", - "aas_common": "http://www.admin-shell.io/aas_common/2/0", - "xsi": "http://www.w3.org/2001/XMLSchema-instance", - "IEC": "http://www.admin-shell.io/IEC61360/2/0", - "xs": "http://www.w3.org/2001/XMLSchema"} - - def _generate_element(name: str, text: Optional[str] = None, attributes: Optional[Dict] = None) -> etree.Element: @@ -67,10 +54,10 @@ def _generate_element(name: str, def boolean_to_xml(obj: bool) -> str: """ - serialize a boolean to XML + Serialize a boolean to XML - :param obj: boolean - :return: string in the XML accepted form + :param obj: Boolean (`True`, `False`) + :return: String in the XML accepted form (`'true'`, `'false'`) """ if obj: return "true" @@ -90,41 +77,57 @@ def abstract_classes_to_xml(tag: str, obj: object) -> etree.Element: If the object obj is inheriting from any abstract AAS class, this function adds all the serialized information of those abstract classes to the generated element. - :param tag: tag of the element - :param obj: an object of the AAS - :return: parent element with the serialized information from the abstract classes + :param tag: Tag of the element + :param obj: An object of the AAS + :return: Parent element with the serialized information from the abstract classes """ elm = _generate_element(tag) + if isinstance(obj, model.HasExtension): + if obj.extension: + et_extension = _generate_element(NS_AAS + "extensions") + for extension in obj.extension: + if isinstance(extension, model.Extension): + et_extension.append(extension_to_xml(extension, tag=NS_AAS + "extension")) + elm.append(et_extension) if isinstance(obj, model.Referable): - elm.append(_generate_element(name=NS_AAS + "idShort", text=obj.id_short)) if obj.category: elm.append(_generate_element(name=NS_AAS + "category", text=obj.category)) + if obj.id_short and not isinstance(obj.parent, model.SubmodelElementList): + elm.append(_generate_element(name=NS_AAS + "idShort", text=obj.id_short)) + if obj.display_name: + elm.append(lang_string_set_to_xml(obj.display_name, tag=NS_AAS + "displayName")) if obj.description: elm.append(lang_string_set_to_xml(obj.description, tag=NS_AAS + "description")) if isinstance(obj, model.Identifiable): - elm.append(_generate_element(name=NS_AAS + "identification", - text=obj.identification.id, - attributes={"idType": _generic.IDENTIFIER_TYPES[obj.identification.id_type]})) if obj.administration: elm.append(administrative_information_to_xml(obj.administration)) + elm.append(_generate_element(name=NS_AAS + "id", text=obj.id)) if isinstance(obj, model.HasKind): - if obj.kind is model.ModelingKind.TEMPLATE: + if obj.kind is model.ModellingKind.TEMPLATE: elm.append(_generate_element(name=NS_AAS + "kind", text="Template")) else: - # then modeling-kind is Instance + # then modelling-kind is Instance elm.append(_generate_element(name=NS_AAS + "kind", text="Instance")) if isinstance(obj, model.HasSemantics): if obj.semantic_id: elm.append(reference_to_xml(obj.semantic_id, tag=NS_AAS+"semanticId")) + if obj.supplemental_semantic_id: + et_supplemental_semantic_ids = _generate_element(NS_AAS + "supplementalSemanticIds") + for supplemental_semantic_id in obj.supplemental_semantic_id: + et_supplemental_semantic_ids.append(reference_to_xml(supplemental_semantic_id, NS_AAS+"reference")) + elm.append(et_supplemental_semantic_ids) if isinstance(obj, model.Qualifiable): if obj.qualifier: + et_qualifier = _generate_element(NS_AAS + "qualifiers") for qualifier in obj.qualifier: - et_qualifier = _generate_element(NS_AAS+"qualifier") - if isinstance(qualifier, model.Qualifier): - et_qualifier.append(qualifier_to_xml(qualifier, tag=NS_AAS+"qualifier")) - if isinstance(qualifier, model.Formula): - et_qualifier.append(formula_to_xml(qualifier, tag=NS_AAS+"formula")) - elm.append(et_qualifier) + et_qualifier.append(qualifier_to_xml(qualifier, tag=NS_AAS+"qualifier")) + elm.append(et_qualifier) + if isinstance(obj, model.HasDataSpecification): + if obj.embedded_data_specifications: + et_embedded_data_specifications = _generate_element(NS_AAS + "embeddedDataSpecifications") + for eds in obj.embedded_data_specifications: + et_embedded_data_specifications.append(embedded_data_specification_to_xml(eds)) + elm.append(et_embedded_data_specifications) return elm @@ -134,61 +137,74 @@ def abstract_classes_to_xml(tag: str, obj: object) -> etree.Element: def _value_to_xml(value: model.ValueDataType, - value_type: model.DataTypeDef, + value_type: model.DataTypeDefXsd, tag: str = NS_AAS+"value") -> etree.Element: """ Serialization of objects of class ValueDataType to XML :param value: model.ValueDataType object - :param value_type: Corresponding model.DataTypeDef + :param value_type: Corresponding model.DataTypeDefXsd :param tag: tag of the serialized ValueDataType object :return: Serialized ElementTree.Element object """ # todo: add "{NS_XSI+"type": "xs:"+model.datatypes.XSD_TYPE_NAMES[value_type]}" as attribute, if the schema allows # it + # TODO: if this is ever changed, check value_reference_pair_to_xml() return _generate_element(tag, text=model.datatypes.xsd_repr(value)) def lang_string_set_to_xml(obj: model.LangStringSet, tag: str) -> etree.Element: """ - serialization of objects of class LangStringSet to XML + Serialization of objects of class :class:`~aas.model.base.LangStringSet` to XML - :param obj: object of class LangStringSet - :param tag: tag name of the returned XML element (incl. namespace) - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.base.LangStringSet` + :param tag: Namespace+Tag name of the returned XML element. + :return: Serialized ElementTree object """ + LANG_STRING_SET_TAGS: Dict[Type[model.LangStringSet], str] = {k: NS_AAS + v for k, v in { + model.MultiLanguageNameType: "langStringNameType", + model.MultiLanguageTextType: "langStringTextType", + model.DefinitionTypeIEC61360: "langStringDefinitionTypeIec61360", + model.PreferredNameTypeIEC61360: "langStringPreferredNameTypeIec61360", + model.ShortNameTypeIEC61360: "langStringShortNameTypeIec61360" + }.items()} et_lss = _generate_element(name=tag) - for language in obj: - et_lss.append(_generate_element(name=NS_AAS + "langString", - text=obj[language], - attributes={"lang": language})) + for language, text in obj.items(): + et_ls = _generate_element(name=LANG_STRING_SET_TAGS[type(obj)]) + et_ls.append(_generate_element(name=NS_AAS + "language", text=language)) + et_ls.append(_generate_element(name=NS_AAS + "text", text=text)) + et_lss.append(et_ls) return et_lss def administrative_information_to_xml(obj: model.AdministrativeInformation, tag: str = NS_AAS+"administration") -> etree.Element: """ - serialization of objects of class AdministrativeInformation to XML + Serialization of objects of class :class:`~aas.model.base.AdministrativeInformation` to XML - :param obj: object of class AdministrativeInformation - :param tag: tag of the serialized element. default is "administration" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.base.AdministrativeInformation` + :param tag: Namespace+Tag of the serialized element. Default is "aas:administration" + :return: Serialized ElementTree object """ - et_administration = _generate_element(tag) + et_administration = abstract_classes_to_xml(tag, obj) if obj.version: et_administration.append(_generate_element(name=NS_AAS + "version", text=obj.version)) - if obj.revision: - et_administration.append(_generate_element(name=NS_AAS + "revision", text=obj.revision)) + if obj.revision: + et_administration.append(_generate_element(name=NS_AAS + "revision", text=obj.revision)) + if obj.creator: + et_administration.append(reference_to_xml(obj.creator, tag=NS_AAS + "creator")) + if obj.template_id: + et_administration.append(_generate_element(name=NS_AAS + "templateId", text=obj.template_id)) return et_administration def data_element_to_xml(obj: model.DataElement) -> etree.Element: """ - serialization of objects of class DataElement to XML + Serialization of objects of class :class:`~aas.model.submodel.DataElement` to XML - :param obj: Object of class DataElement - :return: serialized ElementTree element + :param obj: Object of class :class:`~aas.model.submodel.DataElement` + :return: Serialized ElementTree element """ if isinstance(obj, model.MultiLanguageProperty): return multi_language_property_to_xml(obj) @@ -206,91 +222,104 @@ def data_element_to_xml(obj: model.DataElement) -> etree.Element: def reference_to_xml(obj: model.Reference, tag: str = NS_AAS+"reference") -> etree.Element: """ - serialization of objects of class Reference to XML + Serialization of objects of class :class:`~aas.model.base.Reference` to XML - :param obj: object of class Reference - :param tag: tag of the returned element - :return: serialized ElementTree + :param obj: Object of class :class:`~aas.model.base.Reference` + :param tag: Namespace+Tag of the returned element. Default is "aas:reference" + :return: Serialized ElementTree """ et_reference = _generate_element(tag) + et_reference.append(_generate_element(NS_AAS + "type", text=_generic.REFERENCE_TYPES[obj.__class__])) + if obj.referred_semantic_id is not None: + et_reference.append(reference_to_xml(obj.referred_semantic_id, NS_AAS + "referredSemanticId")) et_keys = _generate_element(name=NS_AAS + "keys") for aas_key in obj.key: - et_keys.append(_generate_element(name=NS_AAS + "key", - text=aas_key.value, - attributes={"idType": _generic.KEY_TYPES[aas_key.id_type], - "local": boolean_to_xml(aas_key.local), - "type": _generic.KEY_ELEMENTS[aas_key.type]})) + et_key = _generate_element(name=NS_AAS + "key") + et_key.append(_generate_element(name=NS_AAS + "type", text=_generic.KEY_TYPES[aas_key.type])) + et_key.append(_generate_element(name=NS_AAS + "value", text=aas_key.value)) + et_keys.append(et_key) et_reference.append(et_keys) - return et_reference - - -def formula_to_xml(obj: model.Formula, tag: str = NS_AAS+"formula") -> etree.Element: - """ - serialization of objects of class Formula to XML - :param obj: object of class Formula - :param tag: tag of the ElementTree object, default is "formula" - :return: serialized ElementTree object - """ - et_formula = abstract_classes_to_xml(tag, obj) - if obj.depends_on: - et_depends_on = _generate_element(name=NS_AAS + "dependsOnRefs", text=None) - for aas_reference in obj.depends_on: - et_depends_on.append(reference_to_xml(aas_reference, NS_AAS+"reference")) - et_formula.append(et_depends_on) - return et_formula + return et_reference def qualifier_to_xml(obj: model.Qualifier, tag: str = NS_AAS+"qualifier") -> etree.Element: """ - serialization of objects of class Qualifier to XML + Serialization of objects of class :class:`~aas.model.base.Qualifier` to XML - :param obj: object of class Qualifier - :param tag: tag of the serialized ElementTree object, default is "qualifier" - :return: serialized ElementTreeObject + :param obj: Object of class :class:`~aas.model.base.Qualifier` + :param tag: Namespace+Tag of the serialized ElementTree object. Default is "aas:qualifier" + :return: Serialized ElementTreeObject """ et_qualifier = abstract_classes_to_xml(tag, obj) + et_qualifier.append(_generate_element(NS_AAS + "kind", text=_generic.QUALIFIER_KIND[obj.kind])) et_qualifier.append(_generate_element(NS_AAS + "type", text=obj.type)) et_qualifier.append(_generate_element(NS_AAS + "valueType", text=model.datatypes.XSD_TYPE_NAMES[obj.value_type])) - if obj.value_id: - et_qualifier.append(reference_to_xml(obj.value_id, NS_AAS+"valueId")) if obj.value: et_qualifier.append(_value_to_xml(obj.value, obj.value_type)) + if obj.value_id: + et_qualifier.append(reference_to_xml(obj.value_id, NS_AAS+"valueId")) return et_qualifier +def extension_to_xml(obj: model.Extension, tag: str = NS_AAS+"extension") -> etree.Element: + """ + Serialization of objects of class :class:`~aas.model.base.Extension` to XML + + :param obj: Object of class :class:`~aas.model.base.Extension` + :param tag: Namespace+Tag of the serialized ElementTree object. Default is "aas:extension" + :return: Serialized ElementTreeObject + """ + et_extension = abstract_classes_to_xml(tag, obj) + et_extension.append(_generate_element(NS_AAS + "name", text=obj.name)) + if obj.value_type: + et_extension.append(_generate_element(NS_AAS + "valueType", + text=model.datatypes.XSD_TYPE_NAMES[obj.value_type])) + if obj.value: + et_extension.append(_value_to_xml(obj.value, obj.value_type)) # type: ignore # (value_type could be None) + if len(obj.refers_to) > 0: + refers_to = _generate_element(NS_AAS+"refersTo") + for reference in obj.refers_to: + refers_to.append(reference_to_xml(reference, NS_AAS+"reference")) + et_extension.append(refers_to) + return et_extension + + def value_reference_pair_to_xml(obj: model.ValueReferencePair, tag: str = NS_AAS+"valueReferencePair") -> etree.Element: """ - serialization of objects of class ValueReferencePair to XML + Serialization of objects of class :class:`~aas.model.base.ValueReferencePair` to XML todo: couldn't find it in the official schema, so guessing how to implement serialization check namespace, tag and correct serialization - :param obj: object of class ValueReferencePair - :param tag: tag of the serialized element, default is "valueReferencePair" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.base.ValueReferencePair` + :param tag: Namespace+Tag of the serialized element. Default is "aas:valueReferencePair" + :return: Serialized ElementTree object """ et_vrp = _generate_element(tag) - et_vrp.append(_value_to_xml(obj.value, obj.value_type)) - et_vrp.append(reference_to_xml(obj.value_id, "valueId")) + # TODO: value_type isn't used at all by _value_to_xml(), thus we can ignore the type here for now + et_vrp.append(_generate_element(NS_AAS+"value", text=obj.value)) # type: ignore + et_vrp.append(reference_to_xml(obj.value_id, NS_AAS+"valueId")) return et_vrp def value_list_to_xml(obj: model.ValueList, tag: str = NS_AAS+"valueList") -> etree.Element: """ - serialization of objects of class ValueList to XML + Serialization of objects of class :class:`~aas.model.base.ValueList` to XML todo: couldn't find it in the official schema, so guessing how to implement serialization - :param obj: object of class ValueList - :param tag: tag of the serialized element, default is "valueList" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.base.ValueList` + :param tag: Namespace+Tag of the serialized element. Default is "aas:valueList" + :return: Serialized ElementTree object """ et_value_list = _generate_element(tag) + et_value_reference_pairs = _generate_element(NS_AAS+"valueReferencePairs") for aas_reference_pair in obj: - et_value_list.append(value_reference_pair_to_xml(aas_reference_pair, "valueReferencePair")) + et_value_reference_pairs.append(value_reference_pair_to_xml(aas_reference_pair, NS_AAS+"valueReferencePair")) + et_value_list.append(et_value_reference_pairs) return et_value_list @@ -299,246 +328,164 @@ def value_list_to_xml(obj: model.ValueList, # ############################################################## -def view_to_xml(obj: model.View, tag: str = NS_AAS+"view") -> etree.Element: +def specific_asset_id_to_xml(obj: model.SpecificAssetId, tag: str = NS_AAS + "specifidAssetId") \ + -> etree.Element: """ - serialization of objects of class View to XML + Serialization of objects of class :class:`~aas.model.base.SpecificAssetId` to XML - :param obj: object of class View - :param tag: namespace+tag of the ElementTree object. default is "view" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.base.SpecificAssetId` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:identifierKeyValuePair" + :return: Serialized ElementTree object """ - et_view = abstract_classes_to_xml(tag, obj) - et_contained_elements = _generate_element(name=NS_AAS + "containedElements") - if obj.contained_element: - for contained_element in obj.contained_element: - et_contained_elements.append(reference_to_xml(contained_element, NS_AAS+"containedElementRef")) - et_view.append(et_contained_elements) - return et_view + et_asset_information = abstract_classes_to_xml(tag, obj) + et_asset_information.append(_generate_element(name=NS_AAS + "name", text=obj.name)) + et_asset_information.append(_generate_element(name=NS_AAS + "value", text=obj.value)) + if obj.external_subject_id: + et_asset_information.append(reference_to_xml(obj.external_subject_id, NS_AAS + "externalSubjectId")) + + return et_asset_information -def asset_to_xml(obj: model.Asset, tag: str = NS_AAS+"asset") -> etree.Element: +def asset_information_to_xml(obj: model.AssetInformation, tag: str = NS_AAS+"assetInformation") -> etree.Element: """ - serialization of objects of class Asset to XML + Serialization of objects of class :class:`~aas.model.aas.AssetInformation` to XML - :param obj: object of class Asset - :param tag: namespace+tag of the ElementTree object. default is "asset" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.aas.AssetInformation` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:assetInformation" + :return: Serialized ElementTree object """ - et_asset = abstract_classes_to_xml(tag, obj) - if obj.asset_identification_model: - et_asset.append(reference_to_xml(obj.asset_identification_model, NS_AAS+"assetIdentificationModelRef")) - if obj.bill_of_material: - et_asset.append(reference_to_xml(obj.bill_of_material, NS_AAS+"billOfMaterialRef")) - et_asset.append(_generate_element(name=NS_AAS + "kind", text=_generic.ASSET_KIND[obj.kind])) - return et_asset + et_asset_information = abstract_classes_to_xml(tag, obj) + et_asset_information.append(_generate_element(name=NS_AAS + "assetKind", text=_generic.ASSET_KIND[obj.asset_kind])) + if obj.global_asset_id: + et_asset_information.append(_generate_element(name=NS_AAS + "globalAssetId", text=obj.global_asset_id)) + if obj.specific_asset_id: + et_specific_asset_id = _generate_element(name=NS_AAS + "specificAssetIds") + for specific_asset_id in obj.specific_asset_id: + et_specific_asset_id.append(specific_asset_id_to_xml(specific_asset_id, NS_AAS + "specificAssetId")) + et_asset_information.append(et_specific_asset_id) + if obj.asset_type: + et_asset_information.append(_generate_element(name=NS_AAS + "assetType", text=obj.asset_type)) + if obj.default_thumbnail: + et_asset_information.append(resource_to_xml(obj.default_thumbnail, NS_AAS+"defaultThumbnail")) + + return et_asset_information def concept_description_to_xml(obj: model.ConceptDescription, tag: str = NS_AAS+"conceptDescription") -> etree.Element: """ - serialization of objects of class ConceptDescription to XML + Serialization of objects of class :class:`~aas.model.concept.ConceptDescription` to XML - :param obj: object of class ConceptDescription - :param tag: tag of the ElementTree object. default is "conceptDescription" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.concept.ConceptDescription` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:conceptDescription" + :return: Serialized ElementTree object """ et_concept_description = abstract_classes_to_xml(tag, obj) - if isinstance(obj, model.concept.IEC61360ConceptDescription): - et_embedded_data_specification = _generate_element(NS_AAS+"embeddedDataSpecification") - et_data_spec_content = _generate_element(NS_AAS+"dataSpecificationContent") - et_data_spec_content.append(_iec61360_concept_description_to_xml(obj)) - et_embedded_data_specification.append(et_data_spec_content) - et_concept_description.append(et_embedded_data_specification) - et_embedded_data_specification.append(reference_to_xml(model.Reference(tuple([model.Key( - model.KeyElements.GLOBAL_REFERENCE, - False, - "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0", - model.KeyType.IRI - )])), NS_AAS+"dataSpecification")) if obj.is_case_of: + et_is_case_of = _generate_element(NS_AAS+"isCaseOf") for reference in obj.is_case_of: - et_concept_description.append(reference_to_xml(reference, NS_AAS+"isCaseOf")) + et_is_case_of.append(reference_to_xml(reference, NS_AAS+"reference")) + et_concept_description.append(et_is_case_of) return et_concept_description -def _iec61360_concept_description_to_xml(obj: model.concept.IEC61360ConceptDescription, - tag: str = NS_AAS+"dataSpecificationIEC61360") -> etree.Element: - """ - Add the 'embeddedDataSpecifications' attribute to IEC61360ConceptDescription's JSON representation. - - `IEC61360ConceptDescription` is not a distinct class according DotAAS, but instead is built by referencing - "DataSpecificationIEC61360" as dataSpecification. However, we implemented it as an explicit class, inheriting from - ConceptDescription, but we want to generate compliant XML documents. So, we fake the XML structure of an object - with dataSpecifications. - - :param obj: model.concept.IEC61360ConceptDescription object - :param tag: name of the serialized lss_tag - :return: serialized ElementTree object - """ - - def _iec_lang_string_set_to_xml(lss: model.LangStringSet, lss_tag: str) -> etree.Element: - """ - serialization of objects of class LangStringSet to XML - - :param lss: object of class LangStringSet - :param lss_tag: lss_tag name of the returned XML element (incl. namespace) - :return: serialized ElementTree object - """ - et_lss = _generate_element(name=lss_tag) - for language in lss: - et_lss.append(_generate_element(name=NS_IEC + "langString", - text=lss[language], - attributes={"lang": language})) - return et_lss - - def _iec_reference_to_xml(ref: model.Reference, ref_tag: str = NS_AAS + "reference") -> etree.Element: - """ - serialization of objects of class Reference to XML - - :param ref: object of class Reference - :param ref_tag: ref_tag of the returned element - :return: serialized ElementTree - """ - et_reference = _generate_element(ref_tag) - et_keys = _generate_element(name=NS_IEC + "keys") - for aas_key in ref.key: - et_keys.append(_generate_element(name=NS_IEC + "key", - text=aas_key.value, - attributes={"idType": _generic.KEY_TYPES[aas_key.id_type], - "local": boolean_to_xml(aas_key.local), - "type": _generic.KEY_ELEMENTS[aas_key.type]})) - et_reference.append(et_keys) - return et_reference - - def _iec_value_reference_pair_to_xml(vrp: model.ValueReferencePair, - vrp_tag: str = NS_IEC + "valueReferencePair") -> etree.Element: - """ - serialization of objects of class ValueReferencePair to XML - - :param vrp: object of class ValueReferencePair - :param vrp_tag: vl_tag of the serialized element, default is "valueReferencePair" - :return: serialized ElementTree object - """ - et_vrp = _generate_element(vrp_tag) - et_vrp.append(_iec_reference_to_xml(vrp.value_id, NS_IEC + "valueId")) - et_vrp.append(_value_to_xml(vrp.value, vrp.value_type, tag=NS_IEC+"value")) - return et_vrp - - def _iec_value_list_to_xml(vl: model.ValueList, - vl_tag: str = NS_IEC + "valueList") -> etree.Element: - """ - serialization of objects of class ValueList to XML - - :param vl: object of class ValueList - :param vl_tag: vl_tag of the serialized element, default is "valueList" - :return: serialized ElementTree object - """ - et_value_list = _generate_element(vl_tag) - for aas_reference_pair in vl: - et_value_list.append(_iec_value_reference_pair_to_xml(aas_reference_pair, NS_IEC+"valueReferencePair")) - return et_value_list - - et_iec = _generate_element(tag) - et_iec.append(_iec_lang_string_set_to_xml(obj.preferred_name, NS_IEC + "preferredName")) - if obj.short_name: - et_iec.append(_iec_lang_string_set_to_xml(obj.short_name, NS_IEC + "shortName")) - if obj.unit: - et_iec.append(_generate_element(NS_IEC+"unit", text=obj.unit)) - if obj.unit_id: - et_iec.append(_iec_reference_to_xml(obj.unit_id, NS_IEC+"unitId")) - if obj.source_of_definition: - et_iec.append(_generate_element(NS_IEC+"sourceOfDefinition", text=obj.source_of_definition)) - if obj.symbol: - et_iec.append(_generate_element(NS_IEC+"symbol", text=obj.symbol)) - if obj.data_type: - et_iec.append(_generate_element(NS_IEC+"dataType", text=_generic.IEC61360_DATA_TYPES[obj.data_type])) - if obj.definition: - et_iec.append(_iec_lang_string_set_to_xml(obj.definition, NS_IEC + "definition")) - if obj.value_format: - et_iec.append(_generate_element(NS_IEC+"valueFormat", text=model.datatypes.XSD_TYPE_NAMES[obj.value_format])) - if obj.value_list: - et_iec.append(_iec_value_list_to_xml(obj.value_list, NS_IEC+"valueList")) - if obj.value: - et_iec.append(_generate_element(NS_IEC+"value", text=model.datatypes.xsd_repr(obj.value))) - if obj.value_id: - et_iec.append(_iec_reference_to_xml(obj.value_id, NS_IEC+"valueId")) - if obj.level_types: - for level_type in obj.level_types: - et_iec.append(_generate_element(NS_IEC+"levelType", text=_generic.IEC61360_LEVEL_TYPES[level_type])) - return et_iec +def embedded_data_specification_to_xml(obj: model.EmbeddedDataSpecification, + tag: str = NS_AAS+"embeddedDataSpecification") -> etree.Element: + """ + Serialization of objects of class :class:`~aas.model.base.EmbeddedDataSpecification` to XML + + :param obj: Object of class :class:`~aas.model.base.EmbeddedDataSpecification` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:embeddedDataSpecification" + :return: Serialized ElementTree object + """ + et_embedded_data_specification = abstract_classes_to_xml(tag, obj) + et_embedded_data_specification.append(reference_to_xml(obj.data_specification, tag=NS_AAS + "dataSpecification")) + et_embedded_data_specification.append(data_specification_content_to_xml(obj.data_specification_content)) + return et_embedded_data_specification -def concept_dictionary_to_xml(obj: model.ConceptDictionary, - tag: str = NS_AAS+"conceptDictionary") -> etree.Element: +def data_specification_content_to_xml(obj: model.DataSpecificationContent, + tag: str = NS_AAS+"dataSpecificationContent") -> etree.Element: """ - serialization of objects of class ConceptDictionary to XML + Serialization of objects of class :class:`~aas.model.base.DataSpecificationContent` to XML - :param obj: object of class ConceptDictionary - :param tag: tag of the ElementTree object. default is "conceptDictionary" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.base.DataSpecificationContent` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:dataSpecificationContent" + :return: Serialized ElementTree object """ - et_concept_dictionary = abstract_classes_to_xml(tag, obj) - et_concept_descriptions_refs = _generate_element(NS_AAS + "conceptDescriptionRefs") - if obj.concept_description: - for reference in obj.concept_description: - et_concept_descriptions_refs.append(reference_to_xml(reference, NS_AAS+"conceptDescriptionRef")) - et_concept_dictionary.append(et_concept_descriptions_refs) - return et_concept_dictionary + et_data_specification_content = abstract_classes_to_xml(tag, obj) + if isinstance(obj, model.DataSpecificationIEC61360): + et_data_specification_content.append(data_specification_iec61360_to_xml(obj)) + else: + raise TypeError(f"Serialization of {obj.__class__} to XML is not supported!") + return et_data_specification_content + + +def data_specification_iec61360_to_xml(obj: model.DataSpecificationIEC61360, + tag: str = NS_AAS+"dataSpecificationIec61360") -> etree.Element: + """ + Serialization of objects of class :class:`~aas.model.base.DataSpecificationIEC61360` to XML + + :param obj: Object of class :class:`~aas.model.base.DataSpecificationIEC61360` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:dataSpecificationIec61360" + :return: Serialized ElementTree object + """ + et_data_specification_iec61360 = abstract_classes_to_xml(tag, obj) + et_data_specification_iec61360.append(lang_string_set_to_xml(obj.preferred_name, NS_AAS + "preferredName")) + if obj.short_name is not None: + et_data_specification_iec61360.append(lang_string_set_to_xml(obj.short_name, NS_AAS + "shortName")) + if obj.unit is not None: + et_data_specification_iec61360.append(_generate_element(NS_AAS + "unit", text=obj.unit)) + if obj.unit_id is not None: + et_data_specification_iec61360.append(reference_to_xml(obj.unit_id, NS_AAS + "unitId")) + if obj.source_of_definition is not None: + et_data_specification_iec61360.append(_generate_element(NS_AAS + "sourceOfDefinition", + text=obj.source_of_definition)) + if obj.symbol is not None: + et_data_specification_iec61360.append(_generate_element(NS_AAS + "symbol", text=obj.symbol)) + if obj.data_type is not None: + et_data_specification_iec61360.append(_generate_element(NS_AAS + "dataType", + text=_generic.IEC61360_DATA_TYPES[obj.data_type])) + if obj.definition is not None: + et_data_specification_iec61360.append(lang_string_set_to_xml(obj.definition, NS_AAS + "definition")) + + if obj.value_format is not None: + et_data_specification_iec61360.append(_generate_element(NS_AAS + "valueFormat", text=obj.value_format)) + # this can be either None or an empty set, both of which are equivalent to the bool false + # thus we don't check 'is not None' for this property + if obj.value_list: + et_data_specification_iec61360.append(value_list_to_xml(obj.value_list)) + if obj.value is not None: + et_data_specification_iec61360.append(_generate_element(NS_AAS + "value", text=obj.value)) + if obj.level_types: + et_level_types = _generate_element(NS_AAS + "levelType") + for k, v in _generic.IEC61360_LEVEL_TYPES.items(): + et_level_types.append(_generate_element(NS_AAS + v, text=boolean_to_xml(k in obj.level_types))) + et_data_specification_iec61360.append(et_level_types) + return et_data_specification_iec61360 def asset_administration_shell_to_xml(obj: model.AssetAdministrationShell, tag: str = NS_AAS+"assetAdministrationShell") -> etree.Element: """ - serialization of objects of class AssetAdministrationShell to XML + Serialization of objects of class :class:`~aas.model.aas.AssetAdministrationShell` to XML - :param obj: object of class AssetAdministrationShell - :param tag: tag of the ElementTree object. default is "assetAdministrationShell" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.aas.AssetAdministrationShell` + :param tag: Namespace+Tag of the ElementTree object. Default is "aas:assetAdministrationShell" + :return: Serialized ElementTree object """ et_aas = abstract_classes_to_xml(tag, obj) if obj.derived_from: et_aas.append(reference_to_xml(obj.derived_from, tag=NS_AAS+"derivedFrom")) - et_aas.append(reference_to_xml(obj.asset, tag=NS_AAS+"assetRef")) + et_aas.append(asset_information_to_xml(obj.asset_information, tag=NS_AAS + "assetInformation")) if obj.submodel: - et_submodels = _generate_element(NS_AAS + "submodelRefs") + et_submodels = _generate_element(NS_AAS + "submodels") for reference in obj.submodel: - et_submodels.append(reference_to_xml(reference, tag=NS_AAS+"submodelRef")) + et_submodels.append(reference_to_xml(reference, tag=NS_AAS+"reference")) et_aas.append(et_submodels) - if obj.view: - et_views = _generate_element(NS_AAS + "views") - for view in obj.view: - et_views.append(view_to_xml(view, NS_AAS+"view")) - et_aas.append(et_views) - if obj.concept_dictionary: - et_concept_dictionaries = _generate_element(NS_AAS + "conceptDictionaries") - for concept_dictionary in obj.concept_dictionary: - et_concept_dictionaries.append(concept_dictionary_to_xml(concept_dictionary, - NS_AAS+"conceptDictionary")) - et_aas.append(et_concept_dictionaries) - if obj.security: - et_aas.append(security_to_xml(obj.security, tag=NS_ABAC+"security")) return et_aas -# ############################################################## -# transformation functions to serialize classes from model.security -# ############################################################## - - -def security_to_xml(obj: model.Security, - tag: str = NS_ABAC+"security") -> etree.Element: - """ - serialization of objects of class Security to XML - - todo: This is not yet implemented - - :param obj: object of class Security - :param tag: tag of the serialized element (optional). Default is "security" - :return: serialized ElementTree object - """ - return abstract_classes_to_xml(tag, obj) - - # ############################################################## # transformation functions to serialize classes from model.submodel # ############################################################## @@ -546,15 +493,15 @@ def security_to_xml(obj: model.Security, def submodel_element_to_xml(obj: model.SubmodelElement) -> etree.Element: """ - serialization of objects of class SubmodelElement to XML + Serialization of objects of class :class:`~aas.model.submodel.SubmodelElement` to XML - :param obj: object of class SubmodelElement - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.SubmodelElement` + :return: Serialized ElementTree object """ if isinstance(obj, model.DataElement): return data_element_to_xml(obj) - if isinstance(obj, model.BasicEvent): - return basic_event_to_xml(obj) + if isinstance(obj, model.BasicEventElement): + return basic_event_element_to_xml(obj) if isinstance(obj, model.Capability): return capability_to_xml(obj) if isinstance(obj, model.Entity): @@ -567,38 +514,36 @@ def submodel_element_to_xml(obj: model.SubmodelElement) -> etree.Element: return relationship_element_to_xml(obj) if isinstance(obj, model.SubmodelElementCollection): return submodel_element_collection_to_xml(obj) + if isinstance(obj, model.SubmodelElementList): + return submodel_element_list_to_xml(obj) def submodel_to_xml(obj: model.Submodel, tag: str = NS_AAS+"submodel") -> etree.Element: """ - serialization of objects of class Submodel to XML + Serialization of objects of class :class:`~aas.model.submodel.Submodel` to XML - :param obj: object of class Submodel - :param tag: tag of the serialized element (optional). Default is "submodel" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Submodel` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:submodel" + :return: Serialized ElementTree object """ et_submodel = abstract_classes_to_xml(tag, obj) - et_submodel_elements = _generate_element(NS_AAS + "submodelElements") if obj.submodel_element: + et_submodel_elements = _generate_element(NS_AAS + "submodelElements") for submodel_element in obj.submodel_element: - # TODO: simplify this should our suggestion regarding the XML schema get accepted - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 - et_submodel_element = _generate_element(NS_AAS+"submodelElement") - et_submodel_element.append(submodel_element_to_xml(submodel_element)) - et_submodel_elements.append(et_submodel_element) - et_submodel.append(et_submodel_elements) + et_submodel_elements.append(submodel_element_to_xml(submodel_element)) + et_submodel.append(et_submodel_elements) return et_submodel def property_to_xml(obj: model.Property, tag: str = NS_AAS+"property") -> etree.Element: """ - serialization of objects of class Property to XML + Serialization of objects of class :class:`~aas.model.submodel.Property` to XML - :param obj: object of class Property - :param tag: tag of the serialized element (optional), default is "property" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Property` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:property" + :return: Serialized ElementTree object """ et_property = abstract_classes_to_xml(tag, obj) et_property.append(_generate_element(NS_AAS + "valueType", text=model.datatypes.XSD_TYPE_NAMES[obj.value_type])) @@ -612,81 +557,97 @@ def property_to_xml(obj: model.Property, def multi_language_property_to_xml(obj: model.MultiLanguageProperty, tag: str = NS_AAS+"multiLanguageProperty") -> etree.Element: """ - serialization of objects of class MultiLanguageProperty to XML + Serialization of objects of class :class:`~aas.model.submodel.MultiLanguageProperty` to XML - :param obj: object of class MultiLanguageProperty - :param tag: tag of the serialized element (optional), default is "multiLanguageProperty" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.MultiLanguageProperty` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:multiLanguageProperty" + :return: Serialized ElementTree object """ et_multi_language_property = abstract_classes_to_xml(tag, obj) - if obj.value_id: - et_multi_language_property.append(reference_to_xml(obj.value_id, NS_AAS+"valueId")) if obj.value: et_multi_language_property.append(lang_string_set_to_xml(obj.value, tag=NS_AAS + "value")) + if obj.value_id: + et_multi_language_property.append(reference_to_xml(obj.value_id, NS_AAS+"valueId")) return et_multi_language_property def range_to_xml(obj: model.Range, tag: str = NS_AAS+"range") -> etree.Element: """ - serialization of objects of class Range to XML + Serialization of objects of class :class:`~aas.model.submodel.Range` to XML - :param obj: object of class Range - :param tag: namespace+tag of the serialized element (optional), default is "range - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Range` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:range" + :return: Serialized ElementTree object """ et_range = abstract_classes_to_xml(tag, obj) et_range.append(_generate_element(name=NS_AAS + "valueType", text=model.datatypes.XSD_TYPE_NAMES[obj.value_type])) if obj.min is not None: - et_range.append(_value_to_xml(obj.min, obj.value_type, tag=NS_AAS+"min")) + et_range.append(_value_to_xml(obj.min, obj.value_type, tag=NS_AAS + "min")) if obj.max is not None: - et_range.append(_value_to_xml(obj.max, obj.value_type, tag=NS_AAS+"max")) + et_range.append(_value_to_xml(obj.max, obj.value_type, tag=NS_AAS + "max")) return et_range def blob_to_xml(obj: model.Blob, tag: str = NS_AAS+"blob") -> etree.Element: """ - serialization of objects of class Blob to XML + Serialization of objects of class :class:`~aas.model.submodel.Blob` to XML - :param obj: object of class Blob - :param tag: tag of the serialized element, default is "blob" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Blob` + :param tag: Namespace+Tag of the serialized element. Default is "blob" + :return: Serialized ElementTree object """ et_blob = abstract_classes_to_xml(tag, obj) et_value = etree.Element(NS_AAS + "value") if obj.value is not None: et_value.text = base64.b64encode(obj.value).decode() et_blob.append(et_value) - et_blob.append(_generate_element(NS_AAS + "mimeType", text=obj.mime_type)) + et_blob.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) return et_blob def file_to_xml(obj: model.File, tag: str = NS_AAS+"file") -> etree.Element: """ - serialization of objects of class File to XML + Serialization of objects of class :class:`~aas.model.submodel.File` to XML - :param obj: object of class File - :param tag: tag of the serialized element, default is "file" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.File` + :param tag: Namespace+Tag of the serialized element. Default is "aas:file" + :return: Serialized ElementTree object """ et_file = abstract_classes_to_xml(tag, obj) - et_file.append(_generate_element(NS_AAS + "mimeType", text=obj.mime_type)) if obj.value: et_file.append(_generate_element(NS_AAS + "value", text=obj.value)) + et_file.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) return et_file +def resource_to_xml(obj: model.Resource, + tag: str = NS_AAS+"resource") -> etree.Element: + """ + Serialization of objects of class :class:`~aas.model.base.Resource` to XML + + :param obj: Object of class :class:`~aas.model.base.Resource` + :param tag: Namespace+Tag of the serialized element. Default is "aas:resource" + :return: Serialized ElementTree object + """ + et_resource = abstract_classes_to_xml(tag, obj) + et_resource.append(_generate_element(NS_AAS + "path", text=obj.path)) + if obj.content_type: + et_resource.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) + return et_resource + + def reference_element_to_xml(obj: model.ReferenceElement, tag: str = NS_AAS+"referenceElement") -> etree.Element: """ - serialization of objects of class ReferenceElement to XMl + Serialization of objects of class :class:`~aas.model.submodel.ReferenceElement` to XMl - :param obj: object of class ReferenceElement - :param tag: namespace+tag of the serialized element (optional), default is "referenceElement" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.ReferenceElement` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:referenceElement" + :return: Serialized ElementTree object """ et_reference_element = abstract_classes_to_xml(tag, obj) if obj.value: @@ -697,36 +658,51 @@ def reference_element_to_xml(obj: model.ReferenceElement, def submodel_element_collection_to_xml(obj: model.SubmodelElementCollection, tag: str = NS_AAS+"submodelElementCollection") -> etree.Element: """ - serialization of objects of class SubmodelElementCollection to XML + Serialization of objects of class :class:`~aas.model.submodel.SubmodelElementCollection` to XML Note that we do not have parameter "allowDuplicates" in out implementation - :param obj: object of class SubmodelElementCollection - :param tag: namespace+tag of the serialized element (optional), default is "submodelElementCollection" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.SubmodelElementCollection` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:submodelElementCollection" + :return: Serialized ElementTree object """ et_submodel_element_collection = abstract_classes_to_xml(tag, obj) - # todo: remove wrapping submodelElement-tag, in accordance to future schema - et_value = _generate_element(NS_AAS + "value") if obj.value: + et_value = _generate_element(NS_AAS + "value") for submodel_element in obj.value: - et_submodel_element = _generate_element(NS_AAS+"submodelElement") - et_submodel_element.append(submodel_element_to_xml(submodel_element)) - et_value.append(et_submodel_element) - et_submodel_element_collection.append(et_value) - et_submodel_element_collection.append(_generate_element(NS_AAS + "ordered", text=boolean_to_xml(obj.ordered))) - et_submodel_element_collection.append(_generate_element(NS_AAS + "allowDuplicates", text="false")) + et_value.append(submodel_element_to_xml(submodel_element)) + et_submodel_element_collection.append(et_value) return et_submodel_element_collection +def submodel_element_list_to_xml(obj: model.SubmodelElementList, + tag: str = NS_AAS+"submodelElementList") -> etree.Element: + et_submodel_element_list = abstract_classes_to_xml(tag, obj) + et_submodel_element_list.append(_generate_element(NS_AAS + "orderRelevant", boolean_to_xml(obj.order_relevant))) + if obj.semantic_id_list_element is not None: + et_submodel_element_list.append(reference_to_xml(obj.semantic_id_list_element, + NS_AAS + "semanticIdListElement")) + et_submodel_element_list.append(_generate_element(NS_AAS + "typeValueListElement", _generic.KEY_TYPES[ + model.KEY_TYPES_CLASSES[obj.type_value_list_element]])) + if obj.value_type_list_element is not None: + et_submodel_element_list.append(_generate_element(NS_AAS + "valueTypeListElement", + model.datatypes.XSD_TYPE_NAMES[obj.value_type_list_element])) + if len(obj.value) > 0: + et_value = _generate_element(NS_AAS + "value") + for se in obj.value: + et_value.append(submodel_element_to_xml(se)) + et_submodel_element_list.append(et_value) + return et_submodel_element_list + + def relationship_element_to_xml(obj: model.RelationshipElement, tag: str = NS_AAS+"relationshipElement") -> etree.Element: """ - serialization of objects of class RelationshipElement to XML + Serialization of objects of class :class:`~aas.model.submodel.RelationshipElement` to XML - :param obj: object of class RelationshipElement - :param tag: tag of the serialized element (optional), default is "relationshipElement" - :return: serialized ELementTree object + :param obj: Object of class :class:`~aas.model.submodel.RelationshipElement` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:relationshipElement" + :return: Serialized ELementTree object """ et_relationship_element = abstract_classes_to_xml(tag, obj) et_relationship_element.append(reference_to_xml(obj.first, NS_AAS+"first")) @@ -737,35 +713,35 @@ def relationship_element_to_xml(obj: model.RelationshipElement, def annotated_relationship_element_to_xml(obj: model.AnnotatedRelationshipElement, tag: str = NS_AAS+"annotatedRelationshipElement") -> etree.Element: """ - serialization of objects of class AnnotatedRelationshipElement to XML + Serialization of objects of class :class:`~aas.model.submodel.AnnotatedRelationshipElement` to XML - :param obj: object of class AnnotatedRelationshipElement - :param tag: tag of the serialized element (optional), default is "annotatedRelationshipElement - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.AnnotatedRelationshipElement` + :param tag: Namespace+Tag of the serialized element (optional): Default is "aas:annotatedRelationshipElement" + :return: Serialized ElementTree object """ et_annotated_relationship_element = relationship_element_to_xml(obj, tag) - et_annotations = _generate_element(name=NS_AAS+"annotations") if obj.annotation: + et_annotations = _generate_element(name=NS_AAS + "annotations") for data_element in obj.annotation: - et_data_element = _generate_element(name=NS_AAS+"dataElement") - et_data_element.append(data_element_to_xml(data_element)) - et_annotations.append(et_data_element) - et_annotated_relationship_element.append(et_annotations) + et_annotations.append(data_element_to_xml(data_element)) + et_annotated_relationship_element.append(et_annotations) return et_annotated_relationship_element -def operation_variable_to_xml(obj: model.OperationVariable, - tag: str = NS_AAS+"operationVariable") -> etree.Element: +def operation_variable_to_xml(obj: model.SubmodelElement, tag: str = NS_AAS+"operationVariable") -> etree.Element: """ - serialization of objects of class OperationVariable to XML + Serialization of :class:`~aas.model.submodel.SubmodelElement` to the XML OperationVariable representation + Since we don't implement the `OperationVariable` class, which is just a wrapper for a single + :class:`~aas.model.submodel.SubmodelElement`, elements are serialized as the `aas:value` child of an + `aas:operationVariable` element. - :param obj: object of class OperationVariable - :param tag: tag of the serialized element (optional), default is "operationVariable" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.SubmodelElement` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:operationVariable" + :return: Serialized ElementTree object """ et_operation_variable = _generate_element(tag) et_value = _generate_element(NS_AAS+"value") - et_value.append(submodel_element_to_xml(obj.value)) + et_value.append(submodel_element_to_xml(obj)) et_operation_variable.append(et_value) return et_operation_variable @@ -773,33 +749,32 @@ def operation_variable_to_xml(obj: model.OperationVariable, def operation_to_xml(obj: model.Operation, tag: str = NS_AAS+"operation") -> etree.Element: """ - serialization of objects of class Operation to XML + Serialization of objects of class :class:`~aas.model.submodel.Operation` to XML - :param obj: object of class Operation - :param tag: namespace+tag of the serialized element (optional), default is "operation" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Operation` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:operation" + :return: Serialized ElementTree object """ et_operation = abstract_classes_to_xml(tag, obj) - if obj.input_variable: - for input_ov in obj.input_variable: - et_operation.append(operation_variable_to_xml(input_ov, NS_AAS+"inputVariable")) - if obj.output_variable: - for output_ov in obj.output_variable: - et_operation.append(operation_variable_to_xml(output_ov, NS_AAS+"outputVariable")) - if obj.in_output_variable: - for in_out_ov in obj.in_output_variable: - et_operation.append(operation_variable_to_xml(in_out_ov, NS_AAS+"inoutputVariable")) + for tag, nss in ((NS_AAS+"inputVariables", obj.input_variable), + (NS_AAS+"outputVariables", obj.output_variable), + (NS_AAS+"inoutputVariables", obj.in_output_variable)): + if nss: + et_variables = _generate_element(tag) + for submodel_element in nss: + et_variables.append(operation_variable_to_xml(submodel_element)) + et_operation.append(et_variables) return et_operation def capability_to_xml(obj: model.Capability, tag: str = NS_AAS+"capability") -> etree.Element: """ - serialization of objects of class Capability to XML + Serialization of objects of class :class:`~aas.model.submodel.Capability` to XML - :param obj: object of class Capability - :param tag: tag of the serialized element, default is "capability" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Capability` + :param tag: Namespace+Tag of the serialized element, default is "aas:capability" + :return: Serialized ElementTree object """ return abstract_classes_to_xml(tag, obj) @@ -807,39 +782,55 @@ def capability_to_xml(obj: model.Capability, def entity_to_xml(obj: model.Entity, tag: str = NS_AAS+"entity") -> etree.Element: """ - serialization of objects of class Entity to XML + Serialization of objects of class :class:`~aas.model.submodel.Entity` to XML - :param obj: object of class Entity - :param tag: tag of the serialized element (optional), default is "entity" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.Entity` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:entity" + :return: Serialized ElementTree object """ - # todo: remove wrapping submodelElement, in accordance to future schemas et_entity = abstract_classes_to_xml(tag, obj) - et_statements = _generate_element(NS_AAS + "statements") - for statement in obj.statement: - # todo: remove the once the proposed changes get accepted - et_submodel_element = _generate_element(NS_AAS+"submodelElement") - et_submodel_element.append(submodel_element_to_xml(statement)) - et_statements.append(et_submodel_element) - et_entity.append(et_statements) + if obj.statement: + et_statements = _generate_element(NS_AAS + "statements") + for statement in obj.statement: + et_statements.append(submodel_element_to_xml(statement)) + et_entity.append(et_statements) et_entity.append(_generate_element(NS_AAS + "entityType", text=_generic.ENTITY_TYPES[obj.entity_type])) - if obj.asset: - et_entity.append(reference_to_xml(obj.asset, NS_AAS+"assetRef")) + if obj.global_asset_id: + et_entity.append(_generate_element(NS_AAS + "globalAssetId", text=obj.global_asset_id)) + if obj.specific_asset_id: + et_specific_asset_id = _generate_element(name=NS_AAS + "specificAssetIds") + for specific_asset_id in obj.specific_asset_id: + et_specific_asset_id.append(specific_asset_id_to_xml(specific_asset_id, NS_AAS + "specificAssetId")) + et_entity.append(et_specific_asset_id) return et_entity -def basic_event_to_xml(obj: model.BasicEvent, - tag: str = NS_AAS+"basicEvent") -> etree.Element: +def basic_event_element_to_xml(obj: model.BasicEventElement, tag: str = NS_AAS+"basicEventElement") -> etree.Element: """ - serialization of objects of class BasicEvent to XML + Serialization of objects of class :class:`~aas.model.submodel.BasicEventElement` to XML - :param obj: object of class BasicEvent - :param tag: tag of the serialized element (optional), default is "basicEvent" - :return: serialized ElementTree object + :param obj: Object of class :class:`~aas.model.submodel.BasicEventElement` + :param tag: Namespace+Tag of the serialized element (optional). Default is "aas:basicEventElement" + :return: Serialized ElementTree object """ - et_basic_event = abstract_classes_to_xml(tag, obj) - et_basic_event.append(reference_to_xml(obj.observed, NS_AAS+"observed")) - return et_basic_event + et_basic_event_element = abstract_classes_to_xml(tag, obj) + et_basic_event_element.append(reference_to_xml(obj.observed, NS_AAS+"observed")) + et_basic_event_element.append(_generate_element(NS_AAS+"direction", text=_generic.DIRECTION[obj.direction])) + et_basic_event_element.append(_generate_element(NS_AAS+"state", text=_generic.STATE_OF_EVENT[obj.state])) + if obj.message_topic is not None: + et_basic_event_element.append(_generate_element(NS_AAS+"messageTopic", text=obj.message_topic)) + if obj.message_broker is not None: + et_basic_event_element.append(reference_to_xml(obj.message_broker, NS_AAS+"messageBroker")) + if obj.last_update is not None: + et_basic_event_element.append(_generate_element(NS_AAS+"lastUpdate", + text=model.datatypes.xsd_repr(obj.last_update))) + if obj.min_interval is not None: + et_basic_event_element.append(_generate_element(NS_AAS+"minInterval", + text=model.datatypes.xsd_repr(obj.min_interval))) + if obj.max_interval is not None: + et_basic_event_element.append(_generate_element(NS_AAS+"maxInterval", + text=model.datatypes.xsd_repr(obj.max_interval))) + return et_basic_event_element # ############################################################## @@ -860,14 +851,11 @@ def write_aas_xml_file(file: IO, :param kwargs: Additional keyword arguments to be passed to `tree.write()` """ # separate different kind of objects - assets = [] asset_administration_shells = [] submodels = [] concept_descriptions = [] for obj in data: - if isinstance(obj, model.Asset): - assets.append(obj) - elif isinstance(obj, model.AssetAdministrationShell): + if isinstance(obj, model.AssetAdministrationShell): asset_administration_shells.append(obj) elif isinstance(obj, model.Submodel): submodels.append(obj) @@ -875,23 +863,22 @@ def write_aas_xml_file(file: IO, concept_descriptions.append(obj) # serialize objects to XML - root = etree.Element(NS_AAS + "aasenv", nsmap=NS_MAP) - et_asset_administration_shells = etree.Element(NS_AAS + "assetAdministrationShells") - for aas_obj in asset_administration_shells: - et_asset_administration_shells.append(asset_administration_shell_to_xml(aas_obj)) - et_assets = _generate_element(NS_AAS + "assets") - for ass_obj in assets: - et_assets.append(asset_to_xml(ass_obj)) - et_submodels = etree.Element(NS_AAS + "submodels") - for sub_obj in submodels: - et_submodels.append(submodel_to_xml(sub_obj)) - et_concept_descriptions = etree.Element(NS_AAS + "conceptDescriptions") - for con_obj in concept_descriptions: - et_concept_descriptions.append(concept_description_to_xml(con_obj)) - root.insert(0, et_concept_descriptions) - root.insert(0, et_submodels) - root.insert(0, et_assets) - root.insert(0, et_asset_administration_shells) + root = etree.Element(NS_AAS + "environment", nsmap=_generic.XML_NS_MAP) + if asset_administration_shells: + et_asset_administration_shells = etree.Element(NS_AAS + "assetAdministrationShells") + for aas_obj in asset_administration_shells: + et_asset_administration_shells.append(asset_administration_shell_to_xml(aas_obj)) + root.append(et_asset_administration_shells) + if submodels: + et_submodels = etree.Element(NS_AAS + "submodels") + for sub_obj in submodels: + et_submodels.append(submodel_to_xml(sub_obj)) + root.append(et_submodels) + if concept_descriptions: + et_concept_descriptions = etree.Element(NS_AAS + "conceptDescriptions") + for con_obj in concept_descriptions: + et_concept_descriptions.append(concept_description_to_xml(con_obj)) + root.append(et_concept_descriptions) tree = etree.ElementTree(root) tree.write(file, encoding="UTF-8", xml_declaration=True, method="xml", **kwargs) diff --git a/basyx/aas/backend/backends.py b/basyx/aas/backend/backends.py index d568190c6..e1bac1dca 100644 --- a/basyx/aas/backend/backends.py +++ b/basyx/aas/backend/backends.py @@ -19,7 +19,6 @@ methods when the backend is applicable for the relevant source URI. Then, the Backend class needs to be registered to handle update/commit requests for a specific URI schema, using :meth:`~aas.backend.backends.register_backend`. - """ import abc import re diff --git a/basyx/aas/backend/couchdb.py b/basyx/aas/backend/couchdb.py index 78f615723..ec7caec1b 100644 --- a/basyx/aas/backend/couchdb.py +++ b/basyx/aas/backend/couchdb.py @@ -14,9 +14,10 @@ import weakref from typing import List, Dict, Any, Optional, Iterator, Iterable, Union, Tuple import urllib.parse +import urllib.request +import urllib.error import logging import json - import urllib3 # type: ignore from . import backends @@ -25,17 +26,15 @@ logger = logging.getLogger(__name__) - - _http_pool_manager = urllib3.PoolManager() class CouchDBBackend(backends.Backend): """ This Backend stores each Identifiable object as a single JSON document in the configured CouchDB database. Each - document's id is build from the object's identifier using the pattern {idtype}-{idvalue}; the document's contents - comprise a single property "data", containing the JSON serialization of the BaSyx Python SDK object. The - :ref:`adapter.json ` package is used for serialization and deserialization of objects. + document's id is build from the object's identifier. The document's contents comprise a single property "data", + containing the JSON serialization of the BaSyx Python SDK object. The :ref:`adapter.json ` + package is used for serialization and deserialization of objects. """ @classmethod def update_object(cls, @@ -47,6 +46,7 @@ def update_object(cls, raise CouchDBSourceError("The given store_object is not Identifiable, therefore cannot be found " "in the CouchDB") url = CouchDBBackend._parse_source(store_object.source) + try: data = CouchDBBackend.do_request(url) except CouchDBServerError as e: @@ -73,6 +73,7 @@ def commit_object(cls, data = json.dumps({'data': store_object, "_rev": get_couchdb_revision(url)}, cls=json_serialization.AASToJsonEncoder) + try: response = CouchDBBackend.do_request( url, method='PUT', additional_headers={'Content-type': 'application/json'}, body=data.encode('utf-8')) @@ -80,10 +81,10 @@ def commit_object(cls, except CouchDBServerError as e: if e.code == 409: raise CouchDBConflictError("Could not commit changes to id {} due to a concurrent modification in the " - "database.".format(store_object.identification)) from e + "database.".format(store_object.id)) from e elif e.code == 404: raise KeyError("Object with id {} was not found in the CouchDB at {}" - .format(store_object.identification, url)) from e + .format(store_object.id, url)) from e raise @classmethod @@ -125,7 +126,6 @@ def do_request(cls, url: str, method: str = "GET", additional_headers: Dict[str, basic_auth="{}:{}".format(*auth) if auth else None) headers['Accept'] = 'application/json' headers.update(additional_headers) - try: response = _http_pool_manager.request(method, url, headers=headers, body=body) except (urllib3.exceptions.TimeoutError, urllib3.exceptions.SSLError, urllib3.exceptions.ProtocolError) as e: @@ -264,6 +264,7 @@ def check_database(self, create=False): :param create: If True and the database does not exist, try to create it :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) """ + try: CouchDBBackend.do_request("{}/{}".format(self.url, self.database_name), 'HEAD') except CouchDBServerError as e: @@ -279,52 +280,58 @@ def check_database(self, create=False): logger.info("Creating CouchDB database %s/%s ...", self.url, self.database_name) CouchDBBackend.do_request("{}/{}".format(self.url, self.database_name), 'PUT') - def get_identifiable(self, identifier: Union[str, model.Identifier]) -> model.Identifiable: + def get_identifiable_by_couchdb_id(self, couchdb_id: str) -> model.Identifiable: """ - Retrieve an AAS object from the CouchDB by its :class:`~aas.model.base.Identifier` - - If the :class:`~.aas.model.base.Identifier` is a string, it is assumed that the string is a correct - couchdb-ID-string (according to the - internal conversion rules, see CouchDBObjectStore._transform_id() ) + Retrieve an AAS object from the CouchDB by its couchdb-ID-string :raises KeyError: If no such object is stored in the database :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) """ - if isinstance(identifier, model.Identifier): - identifier = self._transform_id(identifier, False) - # Create and issue HTTP request (raises HTTPError on status != 200) + try: data = CouchDBBackend.do_request( - "{}/{}/{}".format(self.url, self.database_name, urllib.parse.quote(identifier, safe=''))) + "{}/{}/{}".format(self.url, self.database_name, urllib.parse.quote(couchdb_id, safe=''))) except CouchDBServerError as e: if e.code == 404: - raise KeyError("No Identifiable with id {} found in CouchDB database".format(identifier)) from e + raise KeyError("No Identifiable with couchdb-id {} found in CouchDB database".format(couchdb_id)) from e raise # Add CouchDB meta data (for later commits) to object obj = data['data'] if not isinstance(obj, model.Identifiable): raise CouchDBResponseError("The CouchDB document with id {} does not contain an identifiable AAS object." - .format(identifier)) + .format(couchdb_id)) self.generate_source(obj) # Generate the source parameter of this object - set_couchdb_revision("{}/{}/{}".format(self.url, self.database_name, urllib.parse.quote(identifier, safe='')), + set_couchdb_revision("{}/{}/{}".format(self.url, self.database_name, urllib.parse.quote(couchdb_id, safe='')), data["_rev"]) # If we still have a local replication of that object (since it is referenced from anywhere else), update that # replication and return it. with self._object_cache_lock: - if obj.identification in self._object_cache: - old_obj = self._object_cache[obj.identification] + if obj.id in self._object_cache: + old_obj = self._object_cache[obj.id] # If the source does not match the correct source for this CouchDB backend, the object seems to belong # to another backend now, so we return a fresh copy if old_obj.source == obj.source: old_obj.update_from(obj) return old_obj - self._object_cache[obj.identification] = obj + self._object_cache[obj.id] = obj return obj + def get_identifiable(self, identifier: model.Identifier) -> model.Identifiable: + """ + Retrieve an AAS object from the CouchDB by its :class:`~aas.model.base.Identifier` + + :raises KeyError: If no such object is stored in the database + :raises CouchDBError: If error occur during the request to the CouchDB server (see `_do_request()` for details) + """ + try: + return self.get_identifiable_by_couchdb_id(self._transform_id(identifier, False)) + except KeyError as e: + raise KeyError("No Identifiable with id {} found in CouchDB database".format(identifier)) from e + def add(self, x: model.Identifiable) -> None: """ Add an object to the store @@ -337,21 +344,21 @@ def add(self, x: model.Identifiable) -> None: data = json.dumps({'data': x}, cls=json_serialization.AASToJsonEncoder) # Create and issue HTTP request (raises HTTPError on status != 200) + try: response = CouchDBBackend.do_request( - "{}/{}/{}".format(self.url, self.database_name, self._transform_id(x.identification)), + "{}/{}/{}".format(self.url, self.database_name, self._transform_id(x.id)), 'PUT', {'Content-type': 'application/json'}, data.encode('utf-8')) - set_couchdb_revision("{}/{}/{}".format(self.url, self.database_name, self._transform_id(x.identification)), + set_couchdb_revision("{}/{}/{}".format(self.url, self.database_name, self._transform_id(x.id)), response["rev"]) except CouchDBServerError as e: if e.code == 409: - raise KeyError("Identifiable with id {} already exists in CouchDB database".format(x.identification))\ - from e + raise KeyError("Identifiable with id {} already exists in CouchDB database".format(x.id)) from e raise with self._object_cache_lock: - self._object_cache[x.identification] = x + self._object_cache[x.id] = x self.generate_source(x) # Set the source of the object def discard(self, x: model.Identifiable, safe_delete=False) -> None: @@ -360,8 +367,7 @@ def discard(self, x: model.Identifiable, safe_delete=False) -> None: :param x: The object to be deleted :param safe_delete: If `True`, only delete the object if it has not been modified in the database in comparison - to - the provided revision. This uses the CouchDB revision token and thus only works with + to the provided revision. This uses the CouchDB revision token and thus only works with CouchDBIdentifiable objects retrieved from this database. :raises KeyError: If the object does not exist in the database :raises CouchDBConflictError: If safe_delete is `True` and the object has been modified or deleted in the @@ -371,7 +377,7 @@ def discard(self, x: model.Identifiable, safe_delete=False) -> None: logger.debug("Deleting object %s from CouchDB database ...", repr(x)) rev = get_couchdb_revision("{}/{}/{}".format(self.url, self.database_name, - self._transform_id(x.identification))) + self._transform_id(x.id))) if rev is not None and safe_delete: logger.debug("using the object's stored revision token %s for deletion." % rev) @@ -383,31 +389,30 @@ def discard(self, x: model.Identifiable, safe_delete=False) -> None: try: logger.debug("fetching the current object revision for deletion ...") headers = CouchDBBackend.do_request( - "{}/{}/{}".format(self.url, self.database_name, self._transform_id(x.identification)), 'HEAD') + "{}/{}/{}".format(self.url, self.database_name, self._transform_id(x.id)), 'HEAD') rev = headers['ETag'][1:-1] except CouchDBServerError as e: if e.code == 404: - raise KeyError("No AAS object with id {} exists in CouchDB database".format(x.identification))\ + raise KeyError("No AAS object with id {} exists in CouchDB database".format(x.id))\ from e raise - try: CouchDBBackend.do_request( - "{}/{}/{}?rev={}".format(self.url, self.database_name, self._transform_id(x.identification), rev), + "{}/{}/{}?rev={}".format(self.url, self.database_name, self._transform_id(x.id), rev), 'DELETE') except CouchDBServerError as e: if e.code == 404: - raise KeyError("No AAS object with id {} exists in CouchDB database".format(x.identification)) from e + raise KeyError("No AAS object with id {} exists in CouchDB database".format(x.id)) from e elif e.code == 409: raise CouchDBConflictError( "Object with id {} has been modified in the database since " - "the version requested to be deleted.".format(x.identification)) from e + "the version requested to be deleted.".format(x.id)) from e raise delete_couchdb_revision("{}/{}/{}".format(self.url, self.database_name, - self._transform_id(x.identification))) + self._transform_id(x.id))) with self._object_cache_lock: - del self._object_cache[x.identification] + del self._object_cache[x.id] x.source = "" def __contains__(self, x: object) -> bool: @@ -422,10 +427,11 @@ def __contains__(self, x: object) -> bool: if isinstance(x, model.Identifier): identifier = x elif isinstance(x, model.Identifiable): - identifier = x.identification + identifier = x.id else: return False logger.debug("Checking existence of object with id %s in database ...", repr(x)) + try: CouchDBBackend.do_request( "{}/{}/{}".format(self.url, self.database_name, self._transform_id(identifier)), 'HEAD') @@ -464,7 +470,7 @@ def __init__(self, store: CouchDBObjectStore, ids: Iterable[str]): def __next__(self): next_id = next(self._iter) - return self._store.get_identifiable(next_id) + return self._store.get_identifiable_by_couchdb_id(next_id) # Fetch a list of all ids and construct Iterator object logger.debug("Creating iterator over objects in database ...") @@ -478,10 +484,9 @@ def _transform_id(identifier: model.Identifier, url_quote=True) -> str: :param url_quote: If True, the result id string is url-encoded to be used in a HTTP request URL """ - result = "{}-{}".format(identifier.id_type.name, identifier.id) if url_quote: - result = urllib.parse.quote(result, safe='') - return result + identifier = urllib.parse.quote(identifier, safe='') + return identifier def generate_source(self, identifiable: model.Identifiable): """ @@ -490,7 +495,7 @@ def generate_source(self, identifiable: model.Identifiable): :param identifiable: Identifiable object """ source: str = self.url.replace("https://", "couchdbs://").replace("http://", "couchdb://") - source += "/" + self.database_name + "/" + self._transform_id(identifiable.identification) + source += "/" + self.database_name + "/" + self._transform_id(identifiable.id) identifiable.source = source diff --git a/basyx/aas/backend/local_file.py b/basyx/aas/backend/local_file.py index 00cf517a4..c521fa32e 100644 --- a/basyx/aas/backend/local_file.py +++ b/basyx/aas/backend/local_file.py @@ -11,7 +11,6 @@ The :class:`~.LocalFileBackend` takes care of updating and committing objects from and to the files, while the :class:`~LocalFileObjectStore` handles adding, deleting and otherwise managing the AAS objects in a specific Directory. """ -import copy from typing import List, Iterator, Iterable, Union import logging import json @@ -103,40 +102,44 @@ def check_directory(self, create=False): os.mkdir(self.directory_path) logger.info("Creating directory {}".format(self.directory_path)) - def get_identifiable(self, identifier: Union[str, model.Identifier]) -> model.Identifiable: + def get_identifiable_by_hash(self, hash_: str) -> model.Identifiable: """ - Retrieve an AAS object from the local file by its :class:`~aas.model.base.Identifier` - - If the :class:`~.aas.model.base.Identifier` is a string, it is assumed that the string is a correct - local-file-ID-string (as it is outputted by LocalFileObjectStore._transform_id() ) + Retrieve an AAS object from the local file by its identifier hash :raises KeyError: If the respective file could not be found """ - input_identifier = copy.copy(identifier) - if isinstance(identifier, model.Identifier): - identifier = self._transform_id(identifier) - # Try to get the correct file try: - with open("{}/{}.json".format(self.directory_path, identifier), "r") as file: + with open("{}/{}.json".format(self.directory_path, hash_), "r") as file: data = json.load(file, cls=json_deserialization.AASFromJsonDecoder) obj = data["data"] self.generate_source(obj) except FileNotFoundError as e: - raise KeyError("No Identifiable with id {} found in local file database".format(input_identifier)) from e + raise KeyError("No Identifiable with hash {} found in local file database".format(hash_)) from e # If we still have a local replication of that object (since it is referenced from anywhere else), update that # replication and return it. with self._object_cache_lock: - if obj.identification in self._object_cache: - old_obj = self._object_cache[obj.identification] + if obj.id in self._object_cache: + old_obj = self._object_cache[obj.id] # If the source does not match the correct source for this CouchDB backend, the object seems to belong # to another backend now, so we return a fresh copy if old_obj.source == obj.source: old_obj.update_from(obj) return old_obj - self._object_cache[obj.identification] = obj + self._object_cache[obj.id] = obj return obj + def get_identifiable(self, identifier: model.Identifier) -> model.Identifiable: + """ + Retrieve an AAS object from the local file by its :class:`~aas.model.base.Identifier` + + :raises KeyError: If the respective file could not be found + """ + try: + return self.get_identifiable_by_hash(self._transform_id(identifier)) + except KeyError as e: + raise KeyError("No Identifiable with id {} found in local file database".format(identifier)) from e + def add(self, x: model.Identifiable) -> None: """ Add an object to the store @@ -144,12 +147,12 @@ def add(self, x: model.Identifiable) -> None: :raises KeyError: If an object with the same id exists already in the object store """ logger.debug("Adding object %s to Local File Store ...", repr(x)) - if os.path.exists("{}/{}.json".format(self.directory_path, self._transform_id(x.identification))): - raise KeyError("Identifiable with id {} already exists in local file database".format(x.identification)) - with open("{}/{}.json".format(self.directory_path, self._transform_id(x.identification)), "w") as file: + if os.path.exists("{}/{}.json".format(self.directory_path, self._transform_id(x.id))): + raise KeyError("Identifiable with id {} already exists in local file database".format(x.id)) + with open("{}/{}.json".format(self.directory_path, self._transform_id(x.id)), "w") as file: json.dump({"data": x}, file, cls=json_serialization.AASToJsonEncoder, indent=4) with self._object_cache_lock: - self._object_cache[x.identification] = x + self._object_cache[x.id] = x self.generate_source(x) # Set the source of the object def discard(self, x: model.Identifiable) -> None: @@ -161,11 +164,11 @@ def discard(self, x: model.Identifiable) -> None: """ logger.debug("Deleting object %s from Local File Store database ...", repr(x)) try: - os.remove("{}/{}.json".format(self.directory_path, self._transform_id(x.identification))) + os.remove("{}/{}.json".format(self.directory_path, self._transform_id(x.id))) except FileNotFoundError as e: - raise KeyError("No AAS object with id {} exists in local file database".format(x.identification)) from e + raise KeyError("No AAS object with id {} exists in local file database".format(x.id)) from e with self._object_cache_lock: - del self._object_cache[x.identification] + del self._object_cache[x.id] x.source = "" def __contains__(self, x: object) -> bool: @@ -179,7 +182,7 @@ def __contains__(self, x: object) -> bool: if isinstance(x, model.Identifier): identifier = x elif isinstance(x, model.Identifiable): - identifier = x.identification + identifier = x.id else: return False logger.debug("Checking existence of object with id %s in database ...", repr(x)) @@ -203,14 +206,14 @@ def __iter__(self) -> Iterator[model.Identifiable]: """ logger.debug("Iterating over objects in database ...") for name in os.listdir(self.directory_path): - yield self.get_identifiable(name.rstrip(".json")) + yield self.get_identifiable_by_hash(name.rstrip(".json")) @staticmethod def _transform_id(identifier: model.Identifier) -> str: """ Helper method to represent an ASS Identifier as a string to be used as Local file document id """ - return hashlib.sha256("{}-{}".format(identifier.id_type.name, identifier.id).encode("utf-8")).hexdigest() + return hashlib.sha256(identifier.encode("utf-8")).hexdigest() def generate_source(self, identifiable: model.Identifiable) -> str: """ @@ -220,7 +223,7 @@ def generate_source(self, identifiable: model.Identifiable) -> str: """ source: str = "file://localhost/{}/{}.json".format( self.directory_path, - self._transform_id(identifiable.identification) + self._transform_id(identifiable.id) ) identifiable.source = source return source diff --git a/basyx/aas/compliance_tool/cli.py b/basyx/aas/compliance_tool/cli.py index e19e2bc57..19f0bfbc8 100644 --- a/basyx/aas/compliance_tool/cli.py +++ b/basyx/aas/compliance_tool/cli.py @@ -82,6 +82,7 @@ def parse_cli_arguments() -> argparse.ArgumentParser: group.add_argument('--xml', help="Use AAS xml format when checking or creating files", action='store_true') parser.add_argument('-l', '--logfile', help="Log file to be created in addition to output to stdout", default=None) parser.add_argument('--aasx', help="Create or read AASX files", action='store_true') + parser.add_argument('--dont-check-extensions', help="Don't compare Extensions", action='store_false') return parser @@ -96,6 +97,10 @@ def main(): logger.propagate = False logger.addHandler(manager) + data_checker_kwargs = { + 'check_extensions': args.dont_check_extensions + } + if args.action == 'create' or args.action == 'c': manager.add_step('Create example data') if args.aasx: @@ -126,7 +131,7 @@ def main(): cp.title = "Test Title" writer.write_aas_objects("/aasx/data.json" if args.json else "/aasx/data.xml", - [obj.identification for obj in data], data, files, + [obj.id for obj in data], data, files, write_json=args.json) writer.write_core_properties(cp) manager.set_step_status(Status.SUCCESS) @@ -154,19 +159,22 @@ def main(): compliance_tool_xml.check_deserialization(args.file_1, manager) elif args.action == 'example' or args.action == 'e': if args.aasx: - compliance_tool_aasx.check_aas_example(args.file_1, manager) + compliance_tool_aasx.check_aas_example(args.file_1, manager, **data_checker_kwargs) elif args.json: - compliance_tool_json.check_aas_example(args.file_1, manager) + compliance_tool_json.check_aas_example(args.file_1, manager, **data_checker_kwargs) elif args.xml: - compliance_tool_xml.check_aas_example(args.file_1, manager) + compliance_tool_xml.check_aas_example(args.file_1, manager, **data_checker_kwargs) elif args.action == 'files' or args.action == 'f': if args.file_2: if args.aasx: - compliance_tool_aasx.check_aasx_files_equivalence(args.file_1, args.file_2, manager) + compliance_tool_aasx.check_aasx_files_equivalence(args.file_1, args.file_2, manager, + **data_checker_kwargs) elif args.json: - compliance_tool_json.check_json_files_equivalence(args.file_1, args.file_2, manager) + compliance_tool_json.check_json_files_equivalence(args.file_1, args.file_2, manager, + **data_checker_kwargs) elif args.xml: - compliance_tool_xml.check_xml_files_equivalence(args.file_1, args.file_2, manager) + compliance_tool_xml.check_xml_files_equivalence(args.file_1, args.file_2, manager, + **data_checker_kwargs) else: parser.error("f or files requires two file path.") exit() diff --git a/basyx/aas/compliance_tool/compliance_check_aasx.py b/basyx/aas/compliance_tool/compliance_check_aasx.py index bda163e4b..bb3993150 100644 --- a/basyx/aas/compliance_tool/compliance_check_aasx.py +++ b/basyx/aas/compliance_tool/compliance_check_aasx.py @@ -158,7 +158,7 @@ def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> N reader.close() -def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) -> None: +def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None: """ Checks if a file contains all elements of the aas example and reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` @@ -168,6 +168,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) :param file_path: Given file which should be checked :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -189,7 +190,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) state_manager.set_step_status(Status.NOT_EXECUTED) return - checker = AASDataChecker(raise_immediately=False) + checker = AASDataChecker(raise_immediately=False, **kwargs) state_manager.add_step('Check if data is equal to example data') example_data = create_example_aas_binding() @@ -243,11 +244,11 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) checker2.check(cp_new.title == cp.title, "title must be {}".format(cp.title), title=cp_new.title) # Check if file in file object is the same - list_of_id_shorts = ["ExampleSubmodelCollectionUnordered", "ExampleFile"] - obj = example_data.get_identifiable(model.Identifier("https://acplt.org/Test_Submodel", model.IdentifierType.IRI)) + list_of_id_shorts = ["ExampleSubmodelCollection", "ExampleFile"] + obj = example_data.get_identifiable("https://acplt.org/Test_Submodel") for id_short in list_of_id_shorts: obj = obj.get_referable(id_short) - obj2 = obj_store.get_identifiable(model.Identifier("https://acplt.org/Test_Submodel", model.IdentifierType.IRI)) + obj2 = obj_store.get_identifiable("https://acplt.org/Test_Submodel") for id_short in list_of_id_shorts: obj2 = obj2.get_referable(id_short) try: @@ -267,7 +268,8 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) state_manager.set_step_status(Status.SUCCESS) -def check_aasx_files_equivalence(file_path_1: str, file_path_2: str, state_manager: ComplianceToolStateManager) -> None: +def check_aasx_files_equivalence(file_path_1: str, file_path_2: str, state_manager: ComplianceToolStateManager, + **kwargs) -> None: """ Checks if two aasx files contain the same elements in any order and reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` @@ -278,6 +280,7 @@ def check_aasx_files_equivalence(file_path_1: str, file_path_2: str, state_manag :param file_path_1: Given first file which should be checked :param file_path_2: Given second file which should be checked :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -295,7 +298,7 @@ def check_aasx_files_equivalence(file_path_1: str, file_path_2: str, state_manag state_manager.set_step_status(Status.NOT_EXECUTED) return - checker = AASDataChecker(raise_immediately=False) + checker = AASDataChecker(raise_immediately=False, **kwargs) try: state_manager.add_step('Check if data in files are equal') checker.check_object_store(obj_store_1, obj_store_2) diff --git a/basyx/aas/compliance_tool/compliance_check_json.py b/basyx/aas/compliance_tool/compliance_check_json.py index ddc59b3ac..f83b8c773 100644 --- a/basyx/aas/compliance_tool/compliance_check_json.py +++ b/basyx/aas/compliance_tool/compliance_check_json.py @@ -162,7 +162,7 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana return obj_store -def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) -> None: +def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None: """ Checks if a file contains all elements of the aas example and reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` @@ -172,6 +172,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) :param file_path: Given file which should be checked :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` """ # create handler to get logger info logger_example = logging.getLogger(example_aas.__name__) @@ -186,7 +187,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) state_manager.set_step_status(Status.NOT_EXECUTED) return - checker = AASDataChecker(raise_immediately=False) + checker = AASDataChecker(raise_immediately=False, **kwargs) state_manager.add_step('Check if data is equal to example data') checker.check_object_store(obj_store, create_example()) @@ -194,7 +195,8 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) state_manager.add_log_records_from_data_checker(checker) -def check_json_files_equivalence(file_path_1: str, file_path_2: str, state_manager: ComplianceToolStateManager) -> None: +def check_json_files_equivalence(file_path_1: str, file_path_2: str, state_manager: ComplianceToolStateManager, + **kwargs) -> None: """ Checks if two json files contain the same elements in any order and reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` @@ -205,6 +207,7 @@ def check_json_files_equivalence(file_path_1: str, file_path_2: str, state_manag :param file_path_1: Given first file which should be checked :param file_path_2: Given second file which should be checked :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -220,7 +223,7 @@ def check_json_files_equivalence(file_path_1: str, file_path_2: str, state_manag state_manager.set_step_status(Status.NOT_EXECUTED) return - checker = AASDataChecker(raise_immediately=False) + checker = AASDataChecker(raise_immediately=False, **kwargs) try: state_manager.add_step('Check if data in files are equal') checker.check_object_store(obj_store_1, obj_store_2) diff --git a/basyx/aas/compliance_tool/compliance_check_xml.py b/basyx/aas/compliance_tool/compliance_check_xml.py index ed658c3cd..2c5fdf0e6 100644 --- a/basyx/aas/compliance_tool/compliance_check_xml.py +++ b/basyx/aas/compliance_tool/compliance_check_xml.py @@ -162,7 +162,7 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana return obj_store -def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) -> None: +def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None: """ Checks if a file contains all elements of the aas example and reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` @@ -172,6 +172,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) :param file_path: Given file which should be checked :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` """ # create handler to get logger info logger_example = logging.getLogger(example_aas.__name__) @@ -186,7 +187,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) state_manager.set_step_status(Status.NOT_EXECUTED) return - checker = AASDataChecker(raise_immediately=False) + checker = AASDataChecker(raise_immediately=False, **kwargs) state_manager.add_step('Check if data is equal to example data') checker.check_object_store(obj_store, create_example()) @@ -194,7 +195,8 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager) state_manager.add_log_records_from_data_checker(checker) -def check_xml_files_equivalence(file_path_1: str, file_path_2: str, state_manager: ComplianceToolStateManager) -> None: +def check_xml_files_equivalence(file_path_1: str, file_path_2: str, state_manager: ComplianceToolStateManager, + **kwargs) -> None: """ Checks if two xml files contain the same elements in any order and reports any issues using the given :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` @@ -205,6 +207,7 @@ def check_xml_files_equivalence(file_path_1: str, file_path_2: str, state_manage :param file_path_1: Given first file which should be checked :param file_path_2: Given second file which should be checked :param state_manager: :class:`~aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps + :param kwargs: Additional arguments to pass to :class:`~aas.examples.data._helper.AASDataChecker` """ logger = logging.getLogger('compliance_check') logger.addHandler(state_manager) @@ -220,7 +223,7 @@ def check_xml_files_equivalence(file_path_1: str, file_path_2: str, state_manage state_manager.set_step_status(Status.NOT_EXECUTED) return - checker = AASDataChecker(raise_immediately=False) + checker = AASDataChecker(raise_immediately=False, **kwargs) try: state_manager.add_step('Check if data in files are equal') checker.check_object_store(obj_store_1, obj_store_2) diff --git a/basyx/aas/compliance_tool/state_manager.py b/basyx/aas/compliance_tool/state_manager.py index 99afe4611..a8093a4b3 100644 --- a/basyx/aas/compliance_tool/state_manager.py +++ b/basyx/aas/compliance_tool/state_manager.py @@ -17,6 +17,14 @@ @enum.unique class Status(enum.IntEnum): + """ + Possible Status States: + + :cvar SUCCESS: + :cvar SUCCESS_WITH_WARNINGS: + :cvar FAILED: + :cvar NOT_EXECUTED: + """ SUCCESS = 0 SUCCESS_WITH_WARNINGS = 1 FAILED = 2 @@ -25,11 +33,11 @@ class Status(enum.IntEnum): class Step: """ - A step represents a single test stage in a test protocol of a ComplianceToolStateManager + A step represents a single test stage in a test protocol of a :class:`~.ComplianceToolStateManager` :ivar name: Name of the step - :ivar ~.status: status of the step from type Status - :ivar log_list: list of LogRecords which belong to this step + :ivar ~.status: Status of the step from type Status + :ivar log_list: List of `logging.LogRecords` which belong to this step """ def __init__(self, name: str, status: Status, log_list: List[logging.LogRecord]): self.name = name diff --git a/basyx/aas/examples/data/__init__.py b/basyx/aas/examples/data/__init__.py index a1c3fb61c..b82226ad4 100644 --- a/basyx/aas/examples/data/__init__.py +++ b/basyx/aas/examples/data/__init__.py @@ -2,20 +2,17 @@ This package contains functions for the creation of different example AAS objects. example_ass.py - Module for the creation of example asset administration shell, related asset, example submodels and a concept + Module for the creation of example asset administration shell, example submodels and a concept dictionary containing an example concept description example_aas_mandatory_attributes.py - Module for the creation of an example asset administration shell, related asset, example submodels and a concept + Module for the creation of an example asset administration shell, example submodels and a concept dictionary containing an example concept description. All objects only contain mandatory attributes. example_aas_missing_attributes.py - Module for the creation of an example asset administration shell, related asset, example submodels and a concept + Module for the creation of an example asset administration shell, example submodels and a concept dictionary containing an example concept description. All objects contain missing object attribute combination. -example_concept_description.py - Module for creation of an example concept description. - example_submodel_template.py Module for the creation of an example submodel template containing all kind of submodel elements where the kind is always TEMPLATE. @@ -23,7 +20,7 @@ import os from basyx.aas import model -from basyx.aas.examples.data import example_concept_description, example_aas_missing_attributes, example_aas, \ +from basyx.aas.examples.data import example_aas_missing_attributes, example_aas, \ example_aas_mandatory_attributes, example_submodel_template TEST_PDF_FILE = os.path.join(os.path.dirname(__file__), 'TestFile.pdf') @@ -41,14 +38,13 @@ def create_example() -> model.DictObjectStore: obj_store.update(example_aas_mandatory_attributes.create_full_example()) obj_store.update(example_aas_missing_attributes.create_full_example()) obj_store.add(example_submodel_template.create_example_submodel_template()) - obj_store.add(example_concept_description.create_iec61360_concept_description()) return obj_store def create_example_aas_binding() -> model.DictObjectStore: """ creates an object store which is filled with example assets, submodels, concept descriptions and asset - administration shells using the functionality of this package where each asset, submodel and concept description is + administration shells using the functionality of this package where each submodel and concept description is at least referred by one asset administration shell :return: object store @@ -59,22 +55,12 @@ def create_example_aas_binding() -> model.DictObjectStore: obj_store.update(example_aas_missing_attributes.create_full_example()) obj_store.add(example_submodel_template.create_example_submodel_template()) - aas = obj_store.get_identifiable(model.Identifier('https://acplt.org/Test_AssetAdministrationShell', - model.IdentifierType.IRI)) - sm = obj_store.get_identifiable(model.Identifier('https://acplt.org/Test_Submodel_Template', - model.IdentifierType.IRI)) + aas = obj_store.get_identifiable('https://acplt.org/Test_AssetAdministrationShell') + sm = obj_store.get_identifiable('https://acplt.org/Test_Submodel_Template') assert (isinstance(aas, model.aas.AssetAdministrationShell)) # make mypy happy assert (isinstance(sm, model.submodel.Submodel)) # make mypy happy - aas.submodel.add(model.AASReference.from_referable(sm)) + aas.submodel.add(model.ModelReference.from_referable(sm)) - obj_store.add(example_concept_description.create_iec61360_concept_description()) - cd = obj_store.get_identifiable(model.Identifier('http://acplt.org/DataSpecifciations/Example/Identification', - model.IdentifierType.IRI)) - assert (isinstance(cd, model.concept.IEC61360ConceptDescription)) # make mypy happy - cdict = aas.concept_dictionary.get_referable("TestConceptDictionary") - cdict.concept_description.add(model.AASReference.from_referable(cd)) - cd2 = obj_store.get_identifiable(model.Identifier('https://acplt.org/Test_ConceptDescription_Mandatory', - model.IdentifierType.IRI)) - assert (isinstance(cd2, model.concept.ConceptDescription)) # make mypy happy - cdict.concept_description.add(model.AASReference.from_referable(cd2)) + cd = obj_store.get_identifiable('https://acplt.org/Test_ConceptDescription_Mandatory') + assert (isinstance(cd, model.concept.ConceptDescription)) # make mypy happy return obj_store diff --git a/basyx/aas/examples/data/_helper.py b/basyx/aas/examples/data/_helper.py index 3dc93cba0..11db36330 100644 --- a/basyx/aas/examples/data/_helper.py +++ b/basyx/aas/examples/data/_helper.py @@ -8,11 +8,14 @@ Helper classes for checking two objects for completeness and correctness and reporting the check results. """ import pprint -from typing import List, NamedTuple, Iterator, Dict, Any, Type, Optional, Union, Set, Iterable +from typing import List, NamedTuple, Iterator, Dict, Any, Type, Union, Set, Iterable, TypeVar from ... import model +_LIST_OR_COLLECTION = TypeVar("_LIST_OR_COLLECTION", model.SubmodelElementList, model.SubmodelElementCollection) + + class CheckResult(NamedTuple): expectation: str result: bool @@ -90,6 +93,10 @@ def raise_failed(self) -> None: class AASDataChecker(DataChecker): + def __init__(self, check_extensions: bool = True, **kwargs): + super().__init__(**kwargs) + self.check_extensions = check_extensions + def _check_submodel_element(self, object_: model.SubmodelElement, expected_object: model.SubmodelElement): if self.check_is_instance(object_, expected_object.__class__): if isinstance(object_, model.Property): @@ -105,7 +112,9 @@ def _check_submodel_element(self, object_: model.SubmodelElement, expected_objec if isinstance(object_, model.ReferenceElement): return self.check_reference_element_equal(object_, expected_object) # type: ignore if isinstance(object_, model.SubmodelElementCollection): - return self.check_submodel_collection_equal(object_, expected_object) # type: ignore + return self.check_submodel_element_collection_equal(object_, expected_object) # type: ignore + if isinstance(object_, model.SubmodelElementList): + return self.check_submodel_element_list_equal(object_, expected_object) # type: ignore if isinstance(object_, model.AnnotatedRelationshipElement): return self.check_annotated_relationship_element_equal(object_, expected_object) # type: ignore if isinstance(object_, model.RelationshipElement): @@ -116,11 +125,46 @@ def _check_submodel_element(self, object_: model.SubmodelElement, expected_objec return self.check_capability_equal(object_, expected_object) # type: ignore if isinstance(object_, model.Entity): return self.check_entity_equal(object_, expected_object) # type: ignore - if isinstance(object_, model.BasicEvent): - return self.check_basic_event_equal(object_, expected_object) # type: ignore + if isinstance(object_, model.BasicEventElement): + return self.check_basic_event_element_equal(object_, expected_object) # type: ignore else: raise AttributeError('Submodel Element class not implemented') + def _check_has_extension_equal(self, object_: model.HasExtension, expected_object: model.HasExtension): + """ + Checks if the HasExtension object_ has the same HasExtension attributes as the expected_value object and + adds / stores the check result for later analysis. + + :param object_: The HasExtension object which shall be checked + :param expected_object: The expected HasExtension object + :return: The value of expression to be used in control statements + """ + if not self.check_extensions: + return + self.check_contained_element_length(object_, 'extension', model.Extension, len(expected_object.extension)) + for expected_extension in expected_object.extension: + extension = object_.extension.get('name', expected_extension.name) + if self.check(extension is not None, f'{expected_extension!r} must exist'): + self._check_extension_equal(extension, expected_extension) # type: ignore + + found_extensions = self._find_extra_namespace_set_elements_by_name(object_.extension, expected_object.extension) + self.check(found_extensions == set(), f'{object_!r} must not have extra extensions', value=found_extensions) + + def _check_extension_equal(self, object_: model.Extension, expected_object: model.Extension): + """ + Checks if the Extension object_ has the same Extension attributes as the expected_value object and + adds / stores the check result for later analysis. + + :param object_: The Extension object which shall be checked + :param expected_object: The expected Extension object + :return: The value of expression to be used in control statements + """ + self._check_has_semantics_equal(object_, expected_object) + self.check_attribute_equal(object_, 'name', expected_object.name) + self.check_attribute_equal(object_, 'value_type', expected_object.value_type) + self.check_attribute_equal(object_, 'value', expected_object.value) + self.check_attribute_equal(object_, 'refers_to', expected_object.refers_to) + def _check_referable_equal(self, object_: model.Referable, expected_object: model.Referable): """ Checks if the referable object_ has the same referable attributes as the expected_value object and @@ -130,9 +174,14 @@ def _check_referable_equal(self, object_: model.Referable, expected_object: mode :param expected_object: The expected referable object :return: The value of expression to be used in control statements """ - self.check_attribute_equal(object_, "id_short", expected_object.id_short) + # For SubmodelElementLists, the id_shorts of children are randomly generated. + # Thus, this check would always fail if enabled. + if not isinstance(object_.parent, model.SubmodelElementList): + self.check_attribute_equal(object_, "id_short", expected_object.id_short) self.check_attribute_equal(object_, "category", expected_object.category) self.check_attribute_equal(object_, "description", expected_object.description) + self.check_attribute_equal(object_, "display_name", expected_object.display_name) + self._check_has_extension_equal(object_, expected_object) def _check_identifiable_equal(self, object_: model.Identifiable, expected_object: model.Identifiable): """ @@ -145,7 +194,9 @@ def _check_identifiable_equal(self, object_: model.Identifiable, expected_object """ self._check_referable_equal(object_, expected_object) self.check_attribute_equal(object_, "administration", expected_object.administration) - self.check_attribute_equal(object_, "identification", expected_object.identification) + if object_.administration is not None and expected_object.administration is not None: + self._check_has_data_specification_equal(object_.administration, expected_object.administration) + self.check_attribute_equal(object_, "id", expected_object.id) def _check_has_semantics_equal(self, object_: model.HasSemantics, expected_object: model.HasSemantics): """ @@ -157,6 +208,15 @@ def _check_has_semantics_equal(self, object_: model.HasSemantics, expected_objec :return: The value of expression to be used in control statements """ self.check_attribute_equal(object_, "semantic_id", expected_object.semantic_id) + for suppl_semantic_id in expected_object.supplemental_semantic_id: + given_semantic_id = self._find_reference(suppl_semantic_id, object_.supplemental_semantic_id) + self.check(given_semantic_id is not None, f"{object_!r} must have supplementalSemanticId", + value=suppl_semantic_id) + + found_elements = self._find_extra_object(object_.supplemental_semantic_id, + expected_object.supplemental_semantic_id, model.Reference) + self.check(found_elements == set(), '{} must not have extra supplementalSemanticId'.format(repr(object_)), + value=found_elements) def _check_has_kind_equal(self, object_: model.HasKind, expected_object: model.HasKind): """ @@ -178,20 +238,45 @@ def _check_qualifiable_equal(self, object_: model.Qualifiable, expected_object: :param expected_object: The expected qualifiable object :return: The value of expression to be used in control statements """ - self.check_contained_element_length(object_, 'qualifier', model.Constraint, len(expected_object.qualifier)) + self.check_contained_element_length(object_, 'qualifier', model.Qualifier, len(expected_object.qualifier)) for expected_element in expected_object.qualifier: - element = self._find_element_by_attribute(expected_element, object_.qualifier, 'type') - if self.check(element is not None, 'Constraint{} must exist'.format(repr(expected_element))): - if isinstance(element, model.Formula): - self._check_formula_equal(element, expected_element) # type: ignore - elif isinstance(element, model.Qualifier): + element = self._find_element_by_attribute(expected_element, list(object_.qualifier), 'type') + if self.check(element is not None, '{} must exist'.format(repr(expected_element))): + if isinstance(element, model.Qualifier): self._check_qualifier_equal(element, expected_element) # type: ignore else: - raise TypeError('Constraint class not implemented') - found_elements = self._find_extra_elements_by_attribute(object_.qualifier, expected_object.qualifier, 'type') + raise TypeError('Qualifier class not implemented') + + found_elements = self._find_extra_elements_by_attribute(list(object_.qualifier), + list(expected_object.qualifier), 'type') self.check(found_elements == set(), 'Qualifiable Element {} must not have extra elements'.format(repr(object_)), value=found_elements) + def _check_has_data_specification_equal(self, object_: model.HasDataSpecification, + expected_object: model.HasDataSpecification): + """ + Checks if the HasDataSpecification object_ has the same HasDataSpecification attributes + as the expected_value object and adds / stores the check result for later analysis. + + :param object_: The HasDataSpecification object which shall be checked + :param expected_object: The expected HasDataSpecification object + """ + self.check_contained_element_length(object_, 'embedded_data_specifications', model.EmbeddedDataSpecification, + len(expected_object.embedded_data_specifications)) + for expected_dspec in expected_object.embedded_data_specifications: + given_dspec = self._find_element_by_attribute(expected_dspec, object_.embedded_data_specifications, + 'data_specification') + if self.check(given_dspec is not None, 'EmbeddedDataSpecification {} must exist in {}'.format( + repr(expected_dspec.data_specification), repr(object_))): + self.check_data_specification_content_equal(given_dspec.data_specification_content, # type: ignore + expected_dspec.data_specification_content) + + found_elements = self._find_extra_elements_by_attribute(object_.embedded_data_specifications, + expected_object.embedded_data_specifications, + 'data_specification') + self.check(found_elements == set(), '{} must not have extra data specifications'.format(repr(object_)), + value=found_elements) + def _check_abstract_attributes_submodel_element_equal(self, object_: model.SubmodelElement, expected_value: model.SubmodelElement): """ @@ -203,8 +288,28 @@ def _check_abstract_attributes_submodel_element_equal(self, object_: model.Submo """ self._check_referable_equal(object_, expected_value) self._check_has_semantics_equal(object_, expected_value) - self._check_has_kind_equal(object_, expected_value) self._check_qualifiable_equal(object_, expected_value) + self._check_has_data_specification_equal(object_, expected_value) + + def _check_submodel_elements_equal_unordered(self, object_: _LIST_OR_COLLECTION, + expected_value: _LIST_OR_COLLECTION): + """ + Checks if the given SubmodelElement objects are equal (in any order) + + :param object_: Given SubmodelElementCollection or SubmodelElementList containing the objects to check + :param expected_value: SubmodelElementCollection or SubmodelElementList containing the expected elements + :return: + """ + for expected_element in expected_value.value: + try: + element = object_.get_referable(expected_element.id_short) + self._check_submodel_element(element, expected_element) # type: ignore + except KeyError: + self.check(False, 'Submodel Element {} must exist'.format(repr(expected_element))) + + found_elements = self._find_extra_namespace_set_elements_by_id_short(object_.value, expected_value.value) + self.check(found_elements == set(), '{} must not have extra elements'.format(repr(object_)), + value=found_elements) def check_property_equal(self, object_: model.Property, expected_value: model.Property): """ @@ -255,7 +360,7 @@ def check_blob_equal(self, object_: model.Blob, expected_value: model.Blob): """ self._check_abstract_attributes_submodel_element_equal(object_, expected_value) self.check_attribute_equal(object_, 'value', expected_value.value) - self.check_attribute_equal(object_, 'mime_type', expected_value.mime_type) + self.check_attribute_equal(object_, 'content_type', expected_value.content_type) def check_file_equal(self, object_: model.File, expected_value: model.File): """ @@ -267,7 +372,18 @@ def check_file_equal(self, object_: model.File, expected_value: model.File): """ self._check_abstract_attributes_submodel_element_equal(object_, expected_value) self.check_attribute_equal(object_, 'value', expected_value.value) - self.check_attribute_equal(object_, 'mime_type', expected_value.mime_type) + self.check_attribute_equal(object_, 'content_type', expected_value.content_type) + + def check_resource_equal(self, object_: model.Resource, expected_value: model.Resource): + """ + Checks if the given Resource objects are equal + + :param object_: Given Resource object to check + :param expected_value: expected Resource object + :return: + """ + self.check_attribute_equal(object_, 'path', expected_value.path) + self.check_attribute_equal(object_, 'content_type', expected_value.content_type) def check_reference_element_equal(self, object_: model.ReferenceElement, expected_value: model.ReferenceElement): """ @@ -280,8 +396,8 @@ def check_reference_element_equal(self, object_: model.ReferenceElement, expecte self._check_abstract_attributes_submodel_element_equal(object_, expected_value) self.check_attribute_equal(object_, 'value', expected_value.value) - def check_submodel_collection_equal(self, object_: model.SubmodelElementCollection, - expected_value: model.SubmodelElementCollection): + def check_submodel_element_collection_equal(self, object_: model.SubmodelElementCollection, + expected_value: model.SubmodelElementCollection): """ Checks if the given SubmodelElementCollection objects are equal @@ -289,48 +405,35 @@ def check_submodel_collection_equal(self, object_: model.SubmodelElementCollecti :param expected_value: expected SubmodelElementCollection object :return: """ + # the submodel elements are compared unordered, as collections are unordered self._check_abstract_attributes_submodel_element_equal(object_, expected_value) - if isinstance(object_, model.SubmodelElementCollectionUnordered): - self._check_submodel_collection_unordered_equal(object_, expected_value) # type: ignore - elif isinstance(object_, model.SubmodelElementCollectionOrdered): - self._check_submodel_collection_ordered_equal(object_, expected_value) # type: ignore - else: - raise AttributeError('Submodel Element collection class not implemented') - - def _check_submodel_collection_unordered_equal(self, object_: model.SubmodelElementCollectionUnordered, - expected_value: model.SubmodelElementCollectionUnordered): - """ - Checks if the given SubmodelElementCollectionUnordered objects are equal - - :param object_: Given SubmodelElementCollectionUnordered object to check - :param expected_value: expected SubmodelElementCollectionUnordered object - :return: - """ self.check_contained_element_length(object_, 'value', model.SubmodelElement, len(expected_value.value)) - for expected_element in expected_value.value: - element = object_.value.get(expected_element.id_short) - if self.check(element is not None, 'Submodel Element{} must exist'.format(repr(expected_element))): - self._check_submodel_element(element, expected_element) # type: ignore + self._check_submodel_elements_equal_unordered(object_, expected_value) - found_elements = self._find_extra_elements_by_id_short(object_.value, expected_value.value) - self.check(found_elements == set(), 'Submodel Collection {} must not have extra elements'.format(repr(object_)), - value=found_elements) - - def _check_submodel_collection_ordered_equal(self, object_: model.SubmodelElementCollectionUnordered, - expected_value: model.SubmodelElementCollectionUnordered): + def check_submodel_element_list_equal(self, object_: model.SubmodelElementList, + expected_value: model.SubmodelElementList): """ - Checks if the given SubmodelElementCollectionUnordered objects are equal + Checks if the given SubmodelElementList objects are equal - :param object_: Given SubmodelElementCollectionUnordered object to check - :param expected_value: expected SubmodelElementCollectionUnordered object + :param object_: Given SubmodelElementList object to check + :param expected_value: expected SubmodelElementList object :return: """ - self.check_contained_element_length(object_, 'value', model.SubmodelElement, len(expected_value.value)) - list_values = list(object_.value) - list_expected_values = list(expected_value.value) - - for i in range(len(list_expected_values)): - self._check_submodel_element(list_values[i], list_expected_values[i]) + self._check_abstract_attributes_submodel_element_equal(object_, expected_value) + self.check_attribute_equal(object_, 'order_relevant', expected_value.order_relevant) + self.check_attribute_equal(object_, 'semantic_id_list_element', expected_value.semantic_id_list_element) + self.check_attribute_equal(object_, 'value_type_list_element', expected_value.value_type_list_element) + self.check_attribute_equal(object_, 'type_value_list_element', expected_value.type_value_list_element) + self.check_contained_element_length(object_, 'value', object_.type_value_list_element, + len(expected_value.value)) + if not object_.order_relevant or not expected_value.order_relevant: + # It is impossible to compare SubmodelElementLists with order_relevant=False, since it is impossible + # to know which element should be compared against which other element. + raise NotImplementedError("A SubmodelElementList with order_relevant=False cannot be compared!") + + # compare ordered + for se1, se2 in zip(object_.value, expected_value.value): + self._check_submodel_element(se1, se2) def check_relationship_element_equal(self, object_: model.RelationshipElement, expected_value: model.RelationshipElement): @@ -358,12 +461,13 @@ def check_annotated_relationship_element_equal(self, object_: model.AnnotatedRel self.check_contained_element_length(object_, 'annotation', model.DataElement, len(expected_value.annotation)) for expected_data_element in expected_value.annotation: - self.check( - object_.annotation.get(expected_data_element.id_short) is not None, - 'Annotation {} must exist'.format(repr(expected_data_element)) - ) + try: + object_.get_referable(expected_data_element.id_short) + except KeyError: + self.check(False, 'Annotation {} must exist'.format(repr(expected_data_element))) - found_elements = self._find_extra_elements_by_id_short(object_.annotation, expected_value.annotation) + found_elements = self._find_extra_namespace_set_elements_by_id_short(object_.annotation, + expected_value.annotation) self.check(found_elements == set(), 'Annotated Reference {} must not have extra ' 'references'.format(repr(object_)), value=found_elements) @@ -376,9 +480,9 @@ def _check_reference_equal(self, object_: model.Reference, expected_value: model :param expected_value: expected Reference object :return: """ - self.check(object_ == expected_value, "Reference{} must be == {}".format(repr(object_), repr(expected_value))) + self.check(object_ == expected_value, "{} must be == {}".format(repr(object_), repr(expected_value))) - def _find_reference(self, object_: model.Reference, search_list: Union[Set, List]) -> Union[model.Reference, None]: + def _find_reference(self, object_: model.Reference, search_list: Iterable) -> Union[model.Reference, None]: """ Find a reference in an list @@ -391,7 +495,21 @@ def _find_reference(self, object_: model.Reference, search_list: Union[Set, List return element return None - def _find_element_by_attribute(self, object_: object, search_list: Union[Set, List], *attribute: str) -> object: + def _find_specific_asset_id(self, object_: model.SpecificAssetId, search_list: Iterable) \ + -> Union[model.SpecificAssetId, None]: + """ + Find a SpecificAssetId in an list + + :param object_: Given SpecificAssetId which should be find in list + :param search_list: List in which the given SpecificAssetId should be find + :return: the searched SpecificAssetId if found else none + """ + for element in search_list: + if object_ == element: + return element + return None + + def _find_element_by_attribute(self, object_: object, search_list: Iterable, *attribute: str) -> object: """ Find an element in an list @@ -400,7 +518,6 @@ def _find_element_by_attribute(self, object_: object, search_list: Union[Set, Li :param attribute: List of attributes on which the comparison should be done :return: """ - find = False for element in search_list: if isinstance(element, object_.__class__): found = True @@ -411,24 +528,27 @@ def _find_element_by_attribute(self, object_: object, search_list: Union[Set, Li return element return None - def _find_extra_reference(self, object_list: Iterable[model.Reference], - search_list: Iterable[model.Reference]) -> Set[model.Reference]: + def _find_extra_object(self, object_list: Iterable, search_list: Iterable, + type_) -> Union[Set, None]: """ - Find extra reference that are in object_list but noch in search_list + Find extra object that are in object_list but noch in search_list - :param object_list: List which could contain more references than the search_list has + :param object_list: List which could contain more objects than the search_list has :param search_list: List which should be searched - :return: Set of references that are in object_list but not in search_list + :param type_: type of objects which should be find + :return: Set of objects that are in object_list but not in search_list """ found_elements = set() for object_list_element in object_list: - found = False - for search_list_element in search_list: - if object_list_element == search_list_element: - found = True - break - if found is False: - found_elements.add(object_list_element) + if isinstance(object_list_element, type_): + found = False + for search_list_element in search_list: + if isinstance(search_list_element, type_): + if object_list_element == search_list_element: + found = True + break + if found is False: + found_elements.add(object_list_element) return found_elements def _find_extra_elements_by_attribute(self, object_list: Union[Set, List], search_list: Union[Set, List], @@ -456,31 +576,44 @@ def _find_extra_elements_by_attribute(self, object_list: Union[Set, List], searc found_elements.add(object_list_element) return found_elements - def _find_extra_elements_by_id_short(self, object_list: model.NamespaceSet, search_list: model.NamespaceSet) -> Set: + def _find_extra_namespace_set_elements_by_attribute(self, object_list: model.NamespaceSet, + search_list: model.NamespaceSet, attr_name: str) -> Set: """ - Find extra elements that are in object_list but not in search_list + Find extra elements that are in object_list but not in search_list by identifying attribute :param object_list: List which could contain more objects than the search_list has :param search_list: List which should be searched + :param attr_name: Name of the identifying attribute :return: Set of elements that are in object_list but not in search_list """ found_elements = set() for object_list_element in object_list: - element = search_list.get(object_list_element.id_short) + element = search_list.get(attr_name, getattr(object_list_element, attr_name)) if element is None: found_elements.add(object_list_element) return found_elements - def _check_operation_variable_equal(self, object_: model.OperationVariable, - expected_value: model.OperationVariable): + def _find_extra_namespace_set_elements_by_id_short(self, object_list: model.NamespaceSet, + search_list: model.NamespaceSet) -> Set: """ - Checks if the given OperationVariable objects are equal + Find extra Referable objects that are in object_list but not in search_list - :param object_: Given OperationVariable object to check - :param expected_value: expected OperationVariable object - :return: + :param object_list: List which could contain more objects than the search_list has + :param search_list: List which should be searched + :return: Set of elements that are in object_list but not in search_list + """ + return self._find_extra_namespace_set_elements_by_attribute(object_list, search_list, 'id_short') + + def _find_extra_namespace_set_elements_by_name(self, object_list: model.NamespaceSet, + search_list: model.NamespaceSet) -> Set: + """ + Find extra Extension object that are in object_list but not in search_list + + :param object_list: List which could contain more objects than the search_list has + :param search_list: List which should be searched + :return: Set of elements that are in object_list but not in search_list """ - self._check_submodel_element(object_.value, expected_value.value) + return self._find_extra_namespace_set_elements_by_attribute(object_list, search_list, 'name') def check_operation_equal(self, object_: model.Operation, expected_value: model.Operation): """ @@ -491,18 +624,13 @@ def check_operation_equal(self, object_: model.Operation, expected_value: model. :return: """ self._check_abstract_attributes_submodel_element_equal(object_, expected_value) - self.check_contained_element_length(object_, 'input_variable', model.OperationVariable, - len(expected_value.input_variable)) - self.check_contained_element_length(object_, 'output_variable', model.OperationVariable, - len(expected_value.output_variable)) - self.check_contained_element_length(object_, 'in_output_variable', model.OperationVariable, - len(expected_value.in_output_variable)) - for iv1, iv2 in zip(object_.input_variable, expected_value.input_variable): - self._check_operation_variable_equal(iv1, iv2) - for ov1, ov2 in zip(object_.output_variable, expected_value.output_variable): - self._check_operation_variable_equal(ov1, ov2) - for iov1, iov2 in zip(object_.in_output_variable, expected_value.in_output_variable): - self._check_operation_variable_equal(iov1, iov2) + for input_nss, expected_nss, attr_name in ( + (object_.input_variable, expected_value.input_variable, 'input_variable'), + (object_.output_variable, expected_value.output_variable, 'output_variable'), + (object_.in_output_variable, expected_value.in_output_variable, 'in_output_variable')): + self.check_contained_element_length(object_, attr_name, model.SubmodelElement, len(expected_nss)) + for var1, var2 in zip(input_nss, expected_nss): + self._check_submodel_element(var1, var2) def check_capability_equal(self, object_: model.Capability, expected_value: model.Capability): """ @@ -524,37 +652,59 @@ def check_entity_equal(self, object_: model.Entity, expected_value: model.Entity """ self._check_abstract_attributes_submodel_element_equal(object_, expected_value) self.check_attribute_equal(object_, 'entity_type', expected_value.entity_type) - self.check_attribute_equal(object_, 'asset', expected_value.asset) + self.check_attribute_equal(object_, 'global_asset_id', expected_value.global_asset_id) + self._check_specific_asset_ids_equal(object_.specific_asset_id, expected_value.specific_asset_id, object_) self.check_contained_element_length(object_, 'statement', model.SubmodelElement, len(expected_value.statement)) for expected_element in expected_value.statement: - element = object_.statement.get(expected_element.id_short) - self.check(element is not None, 'Entity{} must exist'.format(repr(expected_element))) + element = object_.get_referable(expected_element.id_short) + self.check(element is not None, f'Entity {repr(expected_element)} must exist') + + found_elements = self._find_extra_namespace_set_elements_by_id_short(object_.statement, + expected_value.statement) + self.check(found_elements == set(), f'Enity {repr(object_)} must not have extra statements', + value=found_elements) + + def _check_specific_asset_ids_equal(self, object_: Iterable[model.SpecificAssetId], + expected_value: Iterable[model.SpecificAssetId], + object_parent): + for expected_pair in expected_value: + pair = self._find_specific_asset_id(expected_pair, object_) + if self.check(pair is not None, f'SpecificAssetId {repr(expected_pair)} must exist'): + self.check_specific_asset_id(pair, expected_pair) # type: ignore - found_elements = self._find_extra_elements_by_id_short(object_.statement, expected_value.statement) - self.check(found_elements == set(), 'Enity {} must not have extra statements'.format(repr(object_)), + found_elements = self._find_extra_object(object_, expected_value, model.SpecificAssetId) + self.check(found_elements == set(), f'{repr(object_parent)} must not have extra specificAssetIds', value=found_elements) - def _check_event_equal(self, object_: model.Event, expected_value: model.Event): + def _check_event_element_equal(self, object_: model.EventElement, expected_value: model.EventElement): """ - Checks if the given Event objects are equal + Checks if the given EventElement objects are equal - :param object_: Given Event object to check - :param expected_value: expected Event object + :param object_: Given EventElement object to check + :param expected_value: expected EventElement object :return: """ self._check_abstract_attributes_submodel_element_equal(object_, expected_value) - def check_basic_event_equal(self, object_: model.BasicEvent, expected_value: model.BasicEvent): + def check_basic_event_element_equal(self, object_: model.BasicEventElement, + expected_value: model.BasicEventElement): """ - Checks if the given BasicEvent objects are equal + Checks if the given BasicEventElement objects are equal - :param object_: Given BasicEvent object to check - :param expected_value: expected BasicEvent object + :param object_: Given BasicEventElement object to check + :param expected_value: expected BasicEventElement object :return: """ self._check_abstract_attributes_submodel_element_equal(object_, expected_value) - self._check_event_equal(object_, expected_value) + self._check_event_element_equal(object_, expected_value) self.check_attribute_equal(object_, 'observed', expected_value.observed) + self.check_attribute_equal(object_, 'direction', expected_value.direction) + self.check_attribute_equal(object_, 'state', expected_value.state) + self.check_attribute_equal(object_, 'message_topic', expected_value.message_topic) + self.check_attribute_equal(object_, 'message_broker', expected_value.message_broker) + self.check_attribute_equal(object_, 'last_update', expected_value.last_update) + self.check_attribute_equal(object_, 'min_interval', expected_value.min_interval) + self.check_attribute_equal(object_, 'max_interval', expected_value.max_interval) def check_submodel_equal(self, object_: model.Submodel, expected_value: model.Submodel): """ @@ -568,15 +718,18 @@ def check_submodel_equal(self, object_: model.Submodel, expected_value: model.Su self._check_has_semantics_equal(object_, expected_value) self._check_has_kind_equal(object_, expected_value) self._check_qualifiable_equal(object_, expected_value) + self._check_has_data_specification_equal(object_, expected_value) self.check_contained_element_length(object_, 'submodel_element', model.SubmodelElement, len(expected_value.submodel_element)) for expected_element in expected_value.submodel_element: - element = object_.submodel_element.get(expected_element.id_short) - if self.check(element is not None, 'Submodel Element{} must exist'.format(repr(expected_element))): + try: + element = object_.get_referable(expected_element.id_short) self._check_submodel_element(element, expected_element) # type: ignore + except KeyError: + self.check(False, 'Submodel Element {} must exist'.format(repr(expected_element))) - found_elements = self._find_extra_elements_by_id_short(object_.submodel_element, - expected_value.submodel_element) + found_elements = self._find_extra_namespace_set_elements_by_id_short(object_.submodel_element, + expected_value.submodel_element) self.check(found_elements == set(), 'Submodel {} must not have extra submodel elements'.format(repr(object_)), value=found_elements) @@ -592,32 +745,47 @@ def _check_qualifier_equal(self, object_: model.Qualifier, expected_value: model self.check_attribute_equal(object_, 'value_type', expected_value.value_type) self.check_attribute_equal(object_, 'value', expected_value.value) self.check_attribute_equal(object_, 'value_id', expected_value.value_id) + self.check_attribute_equal(object_, 'kind', expected_value.kind) - def _check_formula_equal(self, object_: model.Formula, expected_value: model.Formula): + def check_specific_asset_id(self, object_: model.SpecificAssetId, + expected_value: model.SpecificAssetId): """ - Checks if the given Formula objects are equal + Checks if the given SpecificAssetId objects are equal - :param object_: Given Formula object to check - :param expected_value: expected Formula object + :param object_: Given SpecificAssetId object to check + :param expected_value: expected SpecificAssetId object :return: """ - for expected_ref in expected_value.depends_on: - ref = self._find_reference(expected_ref, object_.depends_on) - if self.check(ref is not None, 'Reference {} must exist'.format(repr(expected_ref))): - self._check_reference_equal(ref, expected_ref) # type: ignore + self.check_attribute_equal(object_, "name", expected_value.name) + self.check_attribute_equal(object_, "value", expected_value.value) + self.check_attribute_equal(object_, "external_subject_id", expected_value.external_subject_id) + self.check_attribute_equal(object_, "semantic_id", expected_value.semantic_id) - def check_asset_equal(self, object_: model.Asset, expected_value: model.Asset): + def check_asset_information_equal(self, object_: model.AssetInformation, expected_value: model.AssetInformation): """ - Checks if the given Asset objects are equal + Checks if the given AssetInformation objects are equal - :param object_: Given Asset object to check - :param expected_value: expected Asset object + :param object_: Given AssetInformation object to check + :param expected_value: expected AssetInformation object :return: """ - self._check_identifiable_equal(object_, expected_value) - self.check_attribute_equal(object_, 'kind', expected_value.kind) - self.check_attribute_equal(object_, 'asset_identification_model', expected_value.asset_identification_model) - self.check_attribute_equal(object_, 'bill_of_material', expected_value.bill_of_material) + self.check_attribute_equal(object_, 'asset_kind', expected_value.asset_kind) + self.check_attribute_equal(object_, 'global_asset_id', expected_value.global_asset_id) + self.check_contained_element_length(object_, 'specific_asset_id', model.SpecificAssetId, + len(expected_value.specific_asset_id)) + self._check_specific_asset_ids_equal(object_.specific_asset_id, expected_value.specific_asset_id, object_) + self.check_attribute_equal(object_, 'asset_type', object_.asset_type) + if object_.default_thumbnail and expected_value.default_thumbnail: + self.check_resource_equal(object_.default_thumbnail, expected_value.default_thumbnail) + else: + if object_.default_thumbnail: + self.check(expected_value.default_thumbnail is not None, + 'defaultThumbnail object {} must exist'.format(repr(object_.default_thumbnail)), + value=expected_value.default_thumbnail) + else: + self.check(expected_value.default_thumbnail is None, '{} must not have a ' + 'defaultThumbnail object'.format(repr(object_)), + value=expected_value.default_thumbnail) def check_asset_administration_shell_equal(self, object_: model.AssetAdministrationShell, expected_value: model.AssetAdministrationShell): @@ -629,99 +797,21 @@ def check_asset_administration_shell_equal(self, object_: model.AssetAdministrat :return: """ self._check_identifiable_equal(object_, expected_value) - self.check_attribute_equal(object_, 'asset', expected_value.asset) - self.check_security_equal(object_.security, expected_value.security) + self._check_has_data_specification_equal(object_, expected_value) + self.check_asset_information_equal(object_.asset_information, expected_value.asset_information) + self.check_attribute_equal(object_, 'derived_from', expected_value.derived_from) - self.check_contained_element_length(object_, 'submodel', model.AASReference, len(expected_value.submodel)) - self.check_contained_element_length(object_, 'concept_dictionary', model.ConceptDictionary, - len(expected_value.concept_dictionary)) - self.check_contained_element_length(object_, 'view', model.View, len(expected_value.view)) + self.check_contained_element_length(object_, 'submodel', model.ModelReference, len(expected_value.submodel)) for expected_ref in expected_value.submodel: ref = self._find_reference(expected_ref, object_.submodel) if self.check(ref is not None, 'Submodel Reference {} must exist'.format(repr(expected_ref))): self._check_reference_equal(ref, expected_ref) # type: ignore - found_elements = self._find_extra_reference(object_.submodel, expected_value.submodel) + found_elements = self._find_extra_object(object_.submodel, expected_value.submodel, model.ModelReference) self.check(found_elements == set(), 'Asset Administration Shell {} must not have extra submodel ' 'references'.format(repr(object_)), value=found_elements) - for expected_element in expected_value.concept_dictionary: - element = object_.concept_dictionary.get(expected_element.id_short) - if self.check(element is not None, 'Concept Dictionary {} must exist'.format(repr(expected_element))): - self.check_concept_dictionary_equal(element, expected_element) # type: ignore - - found_elements = self._find_extra_elements_by_id_short(object_.concept_dictionary, - expected_value.concept_dictionary) - self.check(found_elements == set(), 'Asset Administration Shell {} must not have extra ' - 'concept dictionaries'.format(repr(object_)), value=found_elements) - - for expected_view in expected_value.view: - view = object_.view.get(expected_view.id_short) - if self.check(view is not None, 'View {} must exist'.format(repr(expected_view))): - self.check_view_equal(view, expected_view) # type: ignore - - found_elements = self._find_extra_elements_by_id_short(object_.view, expected_value.view) - self.check(found_elements == set(), 'Asset Administration Shell {} must not have extra ' - 'views'.format(repr(object_)), value=found_elements) - - def check_concept_dictionary_equal(self, object_: model.ConceptDictionary, - expected_value: model.ConceptDictionary): - """ - Checks if the given ConceptDictionary objects are equal - - :param object_: Given ConceptDictionary object to check - :param expected_value: expected ConceptDictionary object - :return: - """ - self._check_referable_equal(object_, expected_value) - self.check_contained_element_length(object_, 'concept_description', model.AASReference, - len(expected_value.concept_description)) - for expected_ref in expected_value.concept_description: - ref = self._find_reference(expected_ref, object_.concept_description) - if self.check(ref is not None, 'Concept Description Reference {} must exist'.format(repr(expected_ref))): - self._check_reference_equal(ref, expected_ref) # type: ignore - - found_elements = self._find_extra_reference(object_.concept_description, expected_value.concept_description) - self.check(found_elements == set(), 'Concept Dictionary {} must not have extra ' - 'concept description references'.format(repr(object_)), - value=found_elements) - - def check_security_equal(self, object_: Optional[model.Security], - expected_value: Optional[model.Security]): - """ - Checks if the given Security objects are equal - - :param object_: Given Security object to check - :param expected_value: expected Security object - :return: - """ - # TODO: if security is specified - pass - - def check_view_equal(self, object_: model.View, expected_value: model.View): - """ - Checks if the given View objects are equal - - :param object_: Given View object to check - :param expected_value: expected View object - :return: - """ - self._check_referable_equal(object_, expected_value) - self._check_has_semantics_equal(object_, expected_value) - self.check_contained_element_length(object_, 'contained_element', model.AASReference, - len(expected_value.contained_element)) - - for expected_ref in expected_value.contained_element: - ref = self._find_reference(expected_ref, object_.contained_element) - if self.check(ref is not None, 'View Reference {} must exist'.format(repr(expected_ref))): - self._check_reference_equal(ref, expected_ref) # type: ignore - - found_elements = self._find_extra_reference(object_.contained_element, expected_value.contained_element) - self.check(found_elements == set(), 'View Reference {} must not have extra ' - 'submodel element references'.format(repr(object_)), - value=found_elements) - def check_concept_description_equal(self, object_: model.ConceptDescription, expected_value: model.ConceptDescription): """ @@ -732,6 +822,7 @@ def check_concept_description_equal(self, object_: model.ConceptDescription, :return: """ self._check_identifiable_equal(object_, expected_value) + self._check_has_data_specification_equal(object_, expected_value) self.check_contained_element_length(object_, 'is_case_of', model.Reference, len(expected_value.is_case_of)) for expected_ref in expected_value.is_case_of: @@ -739,17 +830,29 @@ def check_concept_description_equal(self, object_: model.ConceptDescription, if self.check(ref is not None, 'Concept Description Reference {} must exist'.format(repr(expected_ref))): self._check_reference_equal(ref, expected_ref) # type: ignore - found_elements = self._find_extra_reference(object_.is_case_of, expected_value.is_case_of) + found_elements = self._find_extra_object(object_.is_case_of, expected_value.is_case_of, + model.ModelReference) self.check(found_elements == set(), 'Concept Description Reference {} must not have extra ' 'is case of references'.format(repr(object_)), value=found_elements) - if isinstance(expected_value, model.IEC61360ConceptDescription): - if self.check_is_instance(object_, model.IEC61360ConceptDescription): - self._check_iec61360_concept_description_equal(object_, expected_value) # type: ignore + def check_data_specification_content_equal( + self, object_: model.DataSpecificationContent, + expected_value: model.DataSpecificationContent): + """ + Checks if the given DataSpecificationContent objects are equal - def _check_iec61360_concept_description_equal(self, object_: model.IEC61360ConceptDescription, - expected_value: model.IEC61360ConceptDescription): + :param object_: Given DataSpecificationContent object to check + :param expected_value: expected DataSpecificationContent object + :return: + """ + self.check(type(object_) is type(expected_value), "type({}) must be == type({})" + .format(repr(object_), repr(expected_value))) + if isinstance(object_, model.base.DataSpecificationIEC61360): + self._check_data_specification_iec61360_equal(object_, expected_value) # type: ignore + + def _check_data_specification_iec61360_equal(self, object_: model.base.DataSpecificationIEC61360, + expected_value: model.base.DataSpecificationIEC61360): """ Checks if the given IEC61360ConceptDescription objects are equal @@ -767,7 +870,6 @@ def _check_iec61360_concept_description_equal(self, object_: model.IEC61360Conce self.check_attribute_equal(object_, 'symbol', expected_value.symbol) self.check_attribute_equal(object_, 'value_format', expected_value.value_format) self.check_attribute_equal(object_, 'value', expected_value.value) - self.check_attribute_equal(object_, 'value_id', expected_value.value_id) self.check_attribute_equal(object_, 'level_types', expected_value.level_types) if expected_value.value_list is not None: @@ -790,36 +892,28 @@ def _check_value_list_equal(self, object_: model.ValueList, expected_value: mode :return: """ for expected_pair in expected_value: - pair = self._find_element_by_attribute(expected_pair, object_, 'value', 'value_id', 'value_type') - self.check(pair is not None, 'ValueReferencePair[value={}, value_id={}, value_type={}] ' - 'must exist'.format(expected_pair.value, expected_pair.value_id, - expected_pair.value_type)) - - found_elements = self._find_extra_elements_by_attribute(object_, expected_value, - 'value', 'value_id', 'value_type') - self.check(found_elements == set(), 'ValueReferenceList must not have extra ValueReferencePairs', + pair = self._find_element_by_attribute(expected_pair, object_, 'value', 'value_id') + self.check(pair is not None, 'ValueReferencePair[value={}, value_id={}] ' + 'must exist'.format(expected_pair.value, expected_pair.value_id)) + + found_elements = self._find_extra_elements_by_attribute(object_, expected_value, 'value', 'value_id') + self.check(found_elements == set(), 'ValueList must not have extra ValueReferencePairs', value=found_elements) - def check_object_store(self, obj_store_1: model.DictObjectStore, - obj_store_2: model.DictObjectStore, list_identifier: str = '2'): + def check_object_store(self, obj_store_1: model.DictObjectStore, obj_store_2: model.DictObjectStore): """ Checks if the given object stores are equal :param obj_store_1: Given object store to check :param obj_store_2: expected object store - :param list_identifier: optional string for naming the list in the second object store. Standard is xxx list 2 - e.g asset list 2 :return: """ # separate different kind of objects - asset_list_1 = [] submodel_list_1 = [] concept_description_list_1 = [] shell_list_1 = [] for obj in obj_store_1: - if isinstance(obj, model.Asset): - asset_list_1.append(obj) - elif isinstance(obj, model.AssetAdministrationShell): + if isinstance(obj, model.AssetAdministrationShell): shell_list_1.append(obj) elif isinstance(obj, model.Submodel): submodel_list_1.append(obj) @@ -829,14 +923,11 @@ def check_object_store(self, obj_store_1: model.DictObjectStore, raise KeyError('Check for {} not implemented'.format(obj)) # separate different kind of objects - asset_list_2 = [] submodel_list_2 = [] concept_description_list_2 = [] shell_list_2 = [] for obj in obj_store_2: - if isinstance(obj, model.Asset): - asset_list_2.append(obj) - elif isinstance(obj, model.AssetAdministrationShell): + if isinstance(obj, model.AssetAdministrationShell): shell_list_2.append(obj) elif isinstance(obj, model.Submodel): submodel_list_2.append(obj) @@ -845,42 +936,33 @@ def check_object_store(self, obj_store_1: model.DictObjectStore, else: raise KeyError('Check for {} not implemented'.format(obj)) - for asset_2 in asset_list_2: - asset_1 = obj_store_1.get(asset_2.identification) - if self.check(asset_1 is not None, 'Asset {} must exist in given asset list'.format(asset_2)): - self.check_asset_equal(asset_1, asset_2) # type: ignore - - found_elements = self._find_extra_elements_by_attribute(asset_list_1, asset_list_2, 'identification') - self.check(found_elements == set(), 'Given asset list must not have extra assets', - value=found_elements) - for shell_2 in shell_list_2: - shell_1 = obj_store_1.get(shell_2.identification) + shell_1 = obj_store_1.get(shell_2.id) if self.check(shell_1 is not None, 'Asset administration shell {} must exist in given asset administration' 'shell list'.format(shell_2)): self.check_asset_administration_shell_equal(shell_1, shell_2) # type: ignore - found_elements = self._find_extra_elements_by_attribute(shell_list_1, shell_list_2, 'identification') + found_elements = self._find_extra_elements_by_attribute(shell_list_1, shell_list_2, 'id') self.check(found_elements == set(), 'Given asset administration shell list must not have extra asset ' 'administration shells', value=found_elements) for submodel_2 in submodel_list_2: - submodel_1 = obj_store_1.get(submodel_2.identification) + submodel_1 = obj_store_1.get(submodel_2.id) if self.check(submodel_1 is not None, 'Submodel {} must exist in given submodel list'.format(submodel_2)): self.check_submodel_equal(submodel_1, submodel_2) # type: ignore - found_elements = self._find_extra_elements_by_attribute(submodel_list_1, submodel_list_2, 'identification') + found_elements = self._find_extra_elements_by_attribute(submodel_list_1, submodel_list_2, 'id') self.check(found_elements == set(), 'Given submodel list must not have extra submodels', value=found_elements) for cd_2 in concept_description_list_2: - cd_1 = obj_store_1.get(cd_2.identification) + cd_1 = obj_store_1.get(cd_2.id) if self.check(cd_1 is not None, 'Concept description {} must exist in given concept description ' 'list'.format(cd_2)): self.check_concept_description_equal(cd_1, cd_2) # type: ignore found_elements = self._find_extra_elements_by_attribute(concept_description_list_1, concept_description_list_2, - 'identification') + 'id') self.check(found_elements == set(), 'Given concept description list must not have extra concept ' 'descriptions', value=found_elements) @@ -896,7 +978,10 @@ def check_attribute_equal(self, object_: object, attribute_name: str, expected_v :param kwargs: Relevant values to add to the check result for further analysis (e.g. the compared values) :return: The value of expression to be used in control statements """ - if attribute_name == 'value_type': + # TODO: going by attribute name here isn't exactly pretty... + if attribute_name in ('value_type', 'value_type_list_element', 'type_value_list_element') \ + and getattr(object_, attribute_name) is not None: + # value_type_list_element can be None and doesn't have the __name__ attribute in this case kwargs['value'] = getattr(object_, attribute_name).__name__ return self.check(getattr(object_, attribute_name) is expected_value, # type:ignore "Attribute {} of {} must be == {}".format( @@ -941,7 +1026,8 @@ def check_contained_element_length(self, object_: object, attribute_name: str, c count = count + 1 kwargs['count'] = count return self.check(count == length, - "{} must contain {} {}s".format(repr(object_), length, class_name.__name__), + "Attribute {} of {} must contain {} {}s".format(attribute_name, repr(object_), + length, class_name.__name__), **kwargs) def check_is_instance(self, object_: object, class_name: Type, **kwargs) -> bool: diff --git a/basyx/aas/examples/data/example_aas.py b/basyx/aas/examples/data/example_aas.py index 7c914eba3..925b4508f 100644 --- a/basyx/aas/examples/data/example_aas.py +++ b/basyx/aas/examples/data/example_aas.py @@ -6,12 +6,12 @@ # SPDX-License-Identifier: MIT """ Module for the creation of an :class:`ObjectStore ` with an example asset -administration shell, related asset and example -submodels and a concept dictionary containing an example concept description +administration shell and example submodels and an example concept description To get this object store use the function :meth:`~aas.examples.data.example_aas.create_full_example`. If you want to get single example objects or want to get more information use the other functions. """ +import datetime import logging from ._helper import AASDataChecker @@ -20,29 +20,54 @@ logger = logging.getLogger(__name__) +_embedded_data_specification_iec61360 = model.EmbeddedDataSpecification( + data_specification=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='https://admin-shell.io/DataSpecificationTemplates/' + 'DataSpecificationIEC61360/3/0'),)), + data_specification_content=model.DataSpecificationIEC61360(preferred_name=model.PreferredNameTypeIEC61360({ + 'de': 'Test Specification', + 'en-US': 'TestSpecification' + }), data_type=model.DataTypeIEC61360.REAL_MEASURE, + definition=model.DefinitionTypeIEC61360({'de': 'Dies ist eine Data Specification für Testzwecke', + 'en-US': 'This is a DataSpecification for testing purposes'}), + short_name=model.ShortNameTypeIEC61360({'de': 'Test Spec', 'en-US': 'TestSpec'}), unit='SpaceUnit', + unit_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Units/SpaceUnit'),)), + source_of_definition='http://acplt.org/DataSpec/ExampleDef', symbol='SU', value_format="M", + value_list={ + model.ValueReferencePair( + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), ), + model.ValueReferencePair( + value='exampleValue2', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId2'),)), )}, + value="TEST", level_types={model.IEC61360LevelType.MIN, model.IEC61360LevelType.MAX}) +) + + def create_full_example() -> model.DictObjectStore: """ - Creates an object store which is filled with an example :class:`~aas.model.aas.Asset`, - :class:`~aas.model.submodel.Submodel`, :class:`~aas.model.concept.ConceptDescription` and - :class:`~aas.model.aas.AssetAdministrationShell` using the functions of this module + Creates an object store which is filled with an example :class:`~aas.model.submodel.Submodel`, + :class:`~aas.model.concept.ConceptDescription` and :class:`~aas.model.aas.AssetAdministrationShell` + using the functions of this module :return: :class:`~aas.model.provider.DictObjectStore` """ obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() obj_store.add(create_example_asset_identification_submodel()) obj_store.add(create_example_bill_of_material_submodel()) - obj_store.add(create_example_asset()) obj_store.add(create_example_submodel()) obj_store.add(create_example_concept_description()) - obj_store.add(create_example_asset_administration_shell(create_example_concept_dictionary())) + obj_store.add(create_example_asset_administration_shell()) return obj_store def create_example_asset_identification_submodel() -> model.Submodel: """ - Creates a :class:`~aas.model.submodel.Submodel` for the identification of the example :class:`~aas.model.aas.Asset` - containing two :class:`~aas.model.submodel.Property` elements according to - 'Verwaltungssschale in der Praxis' + Creates a :class:`~aas.model.submodel.Submodel` containing two :class:`~aas.model.submodel.Property` elements + according to 'Verwaltungssschale in der Praxis' https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/2019-verwaltungsschale-in-der-praxis.html :return: example asset identification submodel @@ -52,19 +77,33 @@ def create_example_asset_identification_submodel() -> model.Submodel: type_='http://acplt.org/Qualifier/ExampleQualifier', value_type=model.datatypes.Int, value=100, - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),))) + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + kind=model.QualifierKind.CONCEPT_QUALIFIER) qualifier2 = model.Qualifier( type_='http://acplt.org/Qualifier/ExampleQualifier2', value_type=model.datatypes.Int, value=50, - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),))) + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + kind=model.QualifierKind.TEMPLATE_QUALIFIER) + + qualifier3 = model.Qualifier( + type_='http://acplt.org/Qualifier/ExampleQualifier3', + value_type=model.datatypes.DateTime, + value=model.datatypes.DateTime(2023, 4, 7, 16, 59, 54, 870123), + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + kind=model.QualifierKind.VALUE_QUALIFIER) + + extension = model.Extension( + name='ExampleExtension', + value_type=model.datatypes.String, + value="ExampleExtensionValue", + refers_to=[model.ModelReference((model.Key(type_=model.KeyTypes.ASSET_ADMINISTRATION_SHELL, + value='http://acplt.org/RefersTo/ExampleRefersTo'),), + model.AssetAdministrationShell)],) # Property-Element conform to 'Verwaltungssschale in der Praxis' page 41 ManufacturerName: # https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/2019-verwaltungsschale-in-der-praxis.html @@ -72,24 +111,27 @@ def create_example_asset_identification_submodel() -> model.Submodel: id_short='ManufacturerName', value_type=model.datatypes.String, value='ACPLT', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),)), - category=None, - description={'en-us': 'Legally valid designation of the natural or judicial person which is directly ' - 'responsible for the design, production, packaging and labeling of a product in ' - 'respect to its being brought into circulation.', - 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, ' - 'Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das ' - '\'Inverkehrbringen\' im eigenen Namen verantwortlich ist'}, + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + category="PARAMETER", + description=model.MultiLanguageTextType({ + 'en-US': 'Legally valid designation of the natural or judicial person which ' + 'is directly responsible for the design, production, packaging and ' + 'labeling of a product in respect to its being brought into ' + 'circulation.', + 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die ' + 'Auslegung, Herstellung und Verpackung sowie die Etikettierung eines ' + 'Produkts im Hinblick auf das \'Inverkehrbringen\' im eigenen Namen ' + 'verantwortlich ist' + }), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='0173-1#02-AAO677#002', - id_type=model.KeyType.IRI),)), + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='0173-1#02-AAO677#002'),)), qualifier={qualifier, qualifier2}, - kind=model.ModelingKind.INSTANCE) + extension={extension}, + supplemental_semantic_id=(), + embedded_data_specifications=() + ) # Property-Element conform to 'Verwaltungssschale in der Praxis' page 44 InstanceId: # https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/2019-verwaltungsschale-in-der-praxis.html @@ -97,52 +139,67 @@ def create_example_asset_identification_submodel() -> model.Submodel: id_short='InstanceId', value_type=model.datatypes.String, value='978-8234-234-342', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),)), - category=None, - description={'en-us': 'Legally valid designation of the natural or judicial person which is directly ' - 'responsible for the design, production, packaging and labeling of a product in ' - 'respect to its being brought into circulation.', - 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, ' - 'Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das ' - '\'Inverkehrbringen\' im eigenen Namen verantwortlich ist'}, + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + category="PARAMETER", + description=model.MultiLanguageTextType({ + 'en-US': 'Legally valid designation of the natural or judicial person which ' + 'is directly responsible for the design, production, packaging and ' + 'labeling of a product in respect to its being brought into ' + 'circulation.', + 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die ' + 'Auslegung, Herstellung und Verpackung sowie die Etikettierung eines ' + 'Produkts im Hinblick auf das \'Inverkehrbringen\' im eigenen Namen ' + 'verantwortlich ist' + }), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber' + ),)), + qualifier={qualifier3}, + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) # asset identification submodel which will be included in the asset object identification_submodel = model.Submodel( - identification=model.Identifier(id_='http://acplt.org/Submodels/Assets/TestAsset/Identification', - id_type=model.IdentifierType.IRI), + id_='http://acplt.org/Submodels/Assets/TestAsset/Identification', submodel_element=(identification_submodel_element_manufacturer_name, identification_submodel_element_instance_id), id_short='Identification', category=None, - description={'en-us': 'An example asset identification submodel for the test application', - 'de': 'Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({ + 'en-US': 'An example asset identification submodel for the test application', + 'de': 'Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung' + }), parent=None, - administration=model.AdministrativeInformation(version='0.9', - revision='0'), - semantic_id=model.Reference((model.Key(type_=model.KeyElements.SUBMODEL, - local=False, - value='http://acplt.org/SubmodelTemplates/AssetIdentification', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + administration=model.AdministrativeInformation(version='9', + revision='0', + creator=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'TestAsset/Identification'), + )), + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/TestAsset/Identification'), + semantic_id=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/SubmodelTemplates/AssetIdentification'),), + model.Submodel), + qualifier=(), + kind=model.ModellingKind.INSTANCE, + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) return identification_submodel def create_example_bill_of_material_submodel() -> model.Submodel: """ - Creates a :class:`~aas.model.submodel.Submodel` for the bill of material of the example - :class:`~aas.model.aas.Asset` containing two entities one co-managed and one - self-managed + creates a :class:`~aas.model.submodel.Submodel` for the bill of material containing two entities one + co-managed and one self-managed :return: example bill of material submodel """ @@ -150,145 +207,126 @@ def create_example_bill_of_material_submodel() -> model.Submodel: id_short='ExampleProperty', value_type=model.datatypes.String, value='exampleValue', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),)), + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), category='CONSTANT', - description={'en-us': 'Example Property object', - 'de': 'Beispiel Property Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/ExampleProperty', - id_type=model.KeyType.IRI),)), - qualifier={model.Formula( - depends_on={model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),))}), - model.Formula()}, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_property2 = model.Property( id_short='ExampleProperty2', value_type=model.datatypes.String, value='exampleValue2', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),)), + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), category='CONSTANT', - description={'en-us': 'Example Property object', - 'de': 'Beispiel Property Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/ExampleProperty', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) entity = model.Entity( id_short='ExampleEntity', - entity_type=model.EntityType.CO_MANAGED_ENTITY, + entity_type=model.EntityType.SELF_MANAGED_ENTITY, statement={submodel_element_property, submodel_element_property2}, - asset=None, - category=None, - description={'en-us': 'Legally valid designation of the natural or judicial person which is directly ' - 'responsible for the design, production, packaging and labeling of a product in ' - 'respect to its being brought into circulation.', - 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, ' - 'Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das ' - '\'Inverkehrbringen\' im eigenen Namen verantwortlich ist'}, + global_asset_id='http://acplt.org/TestAsset/', + specific_asset_id={ + model.SpecificAssetId(name="TestKey", value="TestValue", + external_subject_id=model.ExternalReference( + (model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SpecificAssetId/'),)) + )}, + category="PARAMETER", + description=model.MultiLanguageTextType({ + 'en-US': 'Legally valid designation of the natural or judicial person which ' + 'is directly responsible for the design, production, packaging and ' + 'labeling of a product in respect to its being brought into ' + 'circulation.', + 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die ' + 'Auslegung, Herstellung und Verpackung sowie die Etikettierung eines ' + 'Produkts im Hinblick auf das \'Inverkehrbringen\' im eigenen Namen ' + 'verantwortlich ist' + }), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber' + ),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() ) entity_2 = model.Entity( id_short='ExampleEntity2', - entity_type=model.EntityType.SELF_MANAGED_ENTITY, + entity_type=model.EntityType.CO_MANAGED_ENTITY, statement=(), - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='https://acplt.org/Test_Asset2', - id_type=model.KeyType.IRI),), - model.Asset), - category=None, - description={'en-us': 'Legally valid designation of the natural or judicial person which is directly ' - 'responsible for the design, production, packaging and labeling of a product in ' - 'respect to its being brought into circulation.', - 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, ' - 'Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das ' - '\'Inverkehrbringen\' im eigenen Namen verantwortlich ist'}, + global_asset_id=None, + specific_asset_id=(), + category="PARAMETER", + description=model.MultiLanguageTextType({ + 'en-US': 'Legally valid designation of the natural or judicial person which ' + 'is directly responsible for the design, production, packaging and ' + 'labeling of a product in respect to its being brought into ' + 'circulation.', + 'de': 'Bezeichnung für eine natürliche oder juristische Person, die für die ' + 'Auslegung, Herstellung und Verpackung sowie die Etikettierung eines ' + 'Produkts im Hinblick auf das \'Inverkehrbringen\' im eigenen Namen ' + 'verantwortlich ist' + }), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber' + ),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() ) # bill of material submodel which will be included in the asset object bill_of_material = model.Submodel( - identification=model.Identifier(id_='http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial', - id_type=model.IdentifierType.IRI), + id_='http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial', submodel_element=(entity, entity_2), id_short='BillOfMaterial', category=None, - description={'en-us': 'An example bill of material submodel for the test application', - 'de': 'Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({ + 'en-US': 'An example bill of material submodel for the test application', + 'de': 'Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung' + }), parent=None, - administration=model.AdministrativeInformation(version='0.9'), - semantic_id=model.Reference((model.Key(type_=model.KeyElements.SUBMODEL, - local=False, - value='http://acplt.org/SubmodelTemplates/BillOfMaterial', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + administration=model.AdministrativeInformation(version='9', + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/TestAsset/BillOfMaterial'), + semantic_id=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/SubmodelTemplates/BillOfMaterial'),), + model.Submodel), + qualifier=(), + kind=model.ModellingKind.INSTANCE, + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) return bill_of_material -def create_example_asset() -> model.Asset: - """ - Creates an example :class:`~aas.model.aas.Asset` which holds references to the example asset identification - submodel and bill of material submodel - - :return: example asset - """ - asset = model.Asset( - kind=model.AssetKind.INSTANCE, - identification=model.Identifier(id_='https://acplt.org/Test_Asset', - id_type=model.IdentifierType.IRI), - id_short='Test_Asset', - category=None, - description={'en-us': 'An example asset for the test application', - 'de': 'Ein Beispiel-Asset für eine Test-Anwendung'}, - parent=None, - administration=model.AdministrativeInformation(version='0.9', - revision='0'), - asset_identification_model=model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=False, - value='http://acplt.org/Submodels/Assets/' - 'TestAsset/Identification', - id_type=model.KeyType.IRI),), - model.Submodel), - bill_of_material=model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=False, - value='http://acplt.org/Submodels/Assets/' - 'TestAsset/BillOfMaterial', - id_type=model.KeyType.IRI),), - model.Submodel)) - return asset - - def create_example_submodel() -> model.Submodel: """ Creates an example :class:`~aas.model.submodel.Submodel` containing all kind of @@ -296,44 +334,74 @@ def create_example_submodel() -> model.Submodel: :return: example submodel """ + submodel_element_property = model.Property( - id_short='ExampleProperty', + id_short=None, value_type=model.datatypes.String, value='exampleValue', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),)), + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), category='CONSTANT', - description={'en-us': 'Example Property object', - 'de': 'Beispiel Property Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/ExampleProperty', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),), ), + qualifier=(), + extension=(), + supplemental_semantic_id=(model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/' + 'ExampleProperty/SupplementalId1'),)), + model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/' + 'ExampleProperty/SupplementalId2'),))), + embedded_data_specifications=(_embedded_data_specification_iec61360,)) + + submodel_element_property_2 = model.Property( + id_short=None, + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/' + 'ExampleProperty2/SupplementalId'),)),), + embedded_data_specifications=() + ) submodel_element_multi_language_property = model.MultiLanguageProperty( id_short='ExampleMultiLanguageProperty', - value={'en-us': 'Example value of a MultiLanguageProperty element', - 'de': 'Beispielswert für ein MulitLanguageProperty-Element'}, - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleMultiLanguageValueId', - id_type=model.KeyType.IRI),)), + value=model.MultiLanguageTextType({'en-US': 'Example value of a MultiLanguageProperty element', + 'de': 'Beispielswert für ein MulitLanguageProperty-Element'}), + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleMultiLanguageValueId'),)), category='CONSTANT', - description={'en-us': 'Example MultiLanguageProperty object', - 'de': 'Beispiel MulitLanguageProperty Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example MultiLanguageProperty object', + 'de': 'Beispiel MultiLanguageProperty Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/MultiLanguageProperties/' - 'ExampleMultiLanguageProperty', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/MultiLanguageProperties/' + 'ExampleMultiLanguageProperty'),), + referred_semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty/Referred'),))), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_range = model.Range( id_short='ExampleRange', @@ -341,256 +409,350 @@ def create_example_submodel() -> model.Submodel: min=0, max=100, category='PARAMETER', - description={'en-us': 'Example Range object', - 'de': 'Beispiel Range Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Range object', + 'de': 'Beispiel Range Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Ranges/ExampleRange', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Ranges/ExampleRange'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_blob = model.Blob( id_short='ExampleBlob', - mime_type='application/pdf', - value=bytearray(b'\x01\x02\x03\x04\x05'), + content_type='application/pdf', + value=bytes(b'\x01\x02\x03\x04\x05'), category='PARAMETER', - description={'en-us': 'Example Blob object', - 'de': 'Beispiel Blob Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Blob object', + 'de': 'Beispiel Blob Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Blobs/ExampleBlob', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Blobs/ExampleBlob'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_file = model.File( id_short='ExampleFile', - mime_type='application/pdf', + content_type='application/pdf', value='/TestFile.pdf', category='PARAMETER', - description={'en-us': 'Example File object', - 'de': 'Beispiel File Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example File object', + 'de': 'Beispiel File Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Files/ExampleFile', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Files/ExampleFile'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_file_uri = model.File( id_short='ExampleFileURI', - mime_type='application/pdf', + content_type='application/pdf', value='https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-' 'Administration-Shell-Part1.pdf?__blob=publicationFile&v=5', category='CONSTANT', - description={'en-us': 'Details of the Asset Administration Shell—An example for an external file reference', - 'de': 'Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte ' - 'Datei'}, + description=model.MultiLanguageTextType({ + 'en-US': 'Details of the Asset Administration Shell — An example for an external file reference', + 'de': 'Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei' + }), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Files/ExampleFile', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Files/ExampleFile'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_reference_element = model.ReferenceElement( id_short='ExampleReferenceElement', - value=model.Reference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),)), + value=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), category='PARAMETER', - description={'en-us': 'Example Reference Element object', - 'de': 'Beispiel Reference Element Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Reference Element object', + 'de': 'Beispiel Reference Element Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ReferenceElements/ExampleReferenceElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ReferenceElements/ExampleReferenceElement' + ),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_relationship_element = model.RelationshipElement( id_short='ExampleRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty2', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference(( + model.Key( + type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key( + type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'), + ), model.Property), + second=model.ModelReference(( + model.Key( + type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key( + type_=model.KeyTypes.PROPERTY, + value='ExampleProperty2'), + ), model.Property), category='PARAMETER', - description={'en-us': 'Example RelationshipElement object', - 'de': 'Beispiel RelationshipElement Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example RelationshipElement object', + 'de': 'Beispiel RelationshipElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/RelationshipElements/' - 'ExampleRelationshipElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ModelReference((model.Key(type_=model.KeyTypes.CONCEPT_DESCRIPTION, + value='https://acplt.org/Test_ConceptDescription'),), + model.ConceptDescription), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_annotated_relationship_element = model.AnnotatedRelationshipElement( id_short='ExampleAnnotatedRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty2', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty2'),), + model.Property), annotation={model.Property(id_short="ExampleAnnotatedProperty", value_type=model.datatypes.String, value='exampleValue', + category="PARAMETER", parent=None), model.Range(id_short="ExampleAnnotatedRange", value_type=model.datatypes.Integer, min=1, max=5, + category="PARAMETER", parent=None) }, category='PARAMETER', - description={'en-us': 'Example AnnotatedRelationshipElement object', - 'de': 'Beispiel AnnotatedRelationshipElement Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example AnnotatedRelationshipElement object', + 'de': 'Beispiel AnnotatedRelationshipElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/RelationshipElements/' - 'ExampleAnnotatedRelationshipElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/RelationshipElements/' + 'ExampleAnnotatedRelationshipElement'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) - submodel_element_operation_variable_input = model.OperationVariable( - value=submodel_element_property) + input_variable_property = model.Property( + id_short='ExamplePropertyInput', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyInput'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) - submodel_element_operation_variable_output = model.OperationVariable( - value=submodel_element_property) + output_variable_property = model.Property( + id_short='ExamplePropertyOutput', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyOutput'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) - submodel_element_operation_variable_in_output = model.OperationVariable( - value=submodel_element_property) + in_output_variable_property = model.Property( + id_short='ExamplePropertyInOutput', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyInOutput'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_operation = model.Operation( id_short='ExampleOperation', - input_variable=[submodel_element_operation_variable_input], - output_variable=[submodel_element_operation_variable_output], - in_output_variable=[submodel_element_operation_variable_in_output], + input_variable=[input_variable_property], + output_variable=[output_variable_property], + in_output_variable=[in_output_variable_property], category='PARAMETER', - description={'en-us': 'Example Operation object', - 'de': 'Beispiel Operation Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Operation object', + 'de': 'Beispiel Operation Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Operations/' - 'ExampleOperation', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Operations/' + 'ExampleOperation'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel_element_capability = model.Capability( id_short='ExampleCapability', category='PARAMETER', - description={'en-us': 'Example Capability object', - 'de': 'Beispiel Capability Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Capability object', + 'de': 'Beispiel Capability Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Capabilities/' - 'ExampleCapability', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) - - submodel_element_basic_event = model.BasicEvent( - id_short='ExampleBasicEvent', - observed=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Capabilities/' + 'ExampleCapability'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) + + submodel_element_basic_event_element = model.BasicEventElement( + id_short='ExampleBasicEventElement', + observed=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + direction=model.Direction.OUTPUT, + state=model.StateOfEvent.ON, + message_topic='ExampleTopic', + message_broker=model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, + "http://acplt.org/ExampleMessageBroker"),), + model.Submodel), + last_update=model.datatypes.DateTime(2022, 11, 12, 23, 50, 23, 123456, datetime.timezone.utc), + min_interval=model.datatypes.Duration(microseconds=1), + max_interval=model.datatypes.Duration(years=1, months=2, days=3, hours=4, minutes=5, seconds=6, + microseconds=123456), category='PARAMETER', - description={'en-us': 'Example BasicEvent object', - 'de': 'Beispiel BasicEvent Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example BasicEventElement object', + 'de': 'Beispiel BasicEventElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Events/' - 'ExampleBasicEvent', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) - - submodel_element_submodel_element_collection_ordered = model.SubmodelElementCollectionOrdered( - id_short='ExampleSubmodelCollectionOrdered', - value=(submodel_element_property, - submodel_element_multi_language_property, - submodel_element_range), + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Events/ExampleBasicEventElement'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) + + submodel_element_submodel_element_list = model.SubmodelElementList( + id_short='ExampleSubmodelList', + type_value_list_element=model.Property, + value=(submodel_element_property, submodel_element_property_2), + semantic_id_list_element=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty' + ),)), + value_type_list_element=model.datatypes.String, + order_relevant=True, category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionOrdered object', - 'de': 'Beispiel SubmodelElementCollectionOrdered Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementList object', + 'de': 'Beispiel SubmodelElementList Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionOrdered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) - - submodel_element_submodel_element_collection_unordered = model.SubmodelElementCollectionUnordered( - id_short='ExampleSubmodelCollectionUnordered', + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementLists/' + 'ExampleSubmodelElementList'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) + + submodel_element_submodel_element_collection = model.SubmodelElementCollection( + id_short='ExampleSubmodelCollection', value=(submodel_element_blob, submodel_element_file, submodel_element_file_uri, - submodel_element_reference_element), + submodel_element_multi_language_property, + submodel_element_range, + submodel_element_reference_element, + submodel_element_submodel_element_list), category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionUnordered object', - 'de': 'Beispiel SubmodelElementCollectionUnordered Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementCollection object', + 'de': 'Beispiel SubmodelElementCollection Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionUnordered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementCollections/' + 'ExampleSubmodelElementCollection'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) submodel = model.Submodel( - identification=model.Identifier(id_='https://acplt.org/Test_Submodel', - id_type=model.IdentifierType.IRI), + id_='https://acplt.org/Test_Submodel', submodel_element=(submodel_element_relationship_element, submodel_element_annotated_relationship_element, submodel_element_operation, submodel_element_capability, - submodel_element_basic_event, - submodel_element_submodel_element_collection_ordered, - submodel_element_submodel_element_collection_unordered), + submodel_element_basic_event_element, + submodel_element_submodel_element_collection), id_short='TestSubmodel', category=None, - description={'en-us': 'An example submodel for the test application', - 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({'en-US': 'An example submodel for the test application', + 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='0.9', - revision='0'), - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelTemplates/' - 'ExampleSubmodel', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + administration=model.AdministrativeInformation(version='9', + revision='0', + creator=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'Test_Submodel'), + )),), + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelTemplates/' + 'ExampleSubmodel'),)), + qualifier=(), + kind=model.ModellingKind.INSTANCE, + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=() + ) return submodel @@ -601,92 +763,103 @@ def create_example_concept_description() -> model.ConceptDescription: :return: example concept description """ concept_description = model.ConceptDescription( - identification=model.Identifier(id_='https://acplt.org/Test_ConceptDescription', - id_type=model.IdentifierType.IRI), - is_case_of={model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/DataSpecifications/' - 'ConceptDescriptions/TestConceptDescription', - id_type=model.KeyType.IRI),))}, + id_='https://acplt.org/Test_ConceptDescription', + is_case_of={model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/DataSpecifications/' + 'ConceptDescriptions/TestConceptDescription'),))}, id_short='TestConceptDescription', category=None, - description={'en-us': 'An example concept description for the test application', - 'de': 'Ein Beispiel-ConceptDescription für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({'en-US': 'An example concept description for the test application', + 'de': 'Ein Beispiel-ConceptDescription für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='0.9', - revision='0')) + administration=model.AdministrativeInformation(version='9', + revision='0', + creator=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'Test_ConceptDescription'), + )), + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/Test_ConceptDescription', + embedded_data_specifications=( + _embedded_data_specification_iec61360, + )) + ) return concept_description -def create_example_concept_dictionary() -> model.ConceptDictionary: - """ - Creates an example :class:`~aas.model.concept.ConceptDictionary` containing an :class:`~aas.model.base.AASReference` - to the example :class:`~aas.model.concept.ConceptDescription` - - :return: example concept dictionary - """ - concept_dictionary = model.ConceptDictionary( - id_short='TestConceptDictionary', - category=None, - description={'en-us': 'An example concept dictionary for the test application', - 'de': 'Ein Beispiel-ConceptDictionary für eine Test-Anwendung'}, - parent=None, - concept_description={model.AASReference((model.Key(type_=model.KeyElements.CONCEPT_DESCRIPTION, - local=False, - value='https://acplt.org/Test_ConceptDescription', - id_type=model.KeyType.IRI),), - model.ConceptDescription)}) - return concept_dictionary - - -def create_example_asset_administration_shell(concept_dictionary: model.ConceptDictionary) -> \ +def create_example_asset_administration_shell() -> \ model.AssetAdministrationShell: """ Creates an :class:`~aas.model.aas.AssetAdministrationShell` with references to an example - :class:`~aas.model.aas.Asset` and :class:`~aas.model.submodel.Submodel` and includes a given - :class:`~aas.model.concept.ConceptDictionary` + :class:`~aas.model.submodel.Submodel`. :return: example :class:`~aas.model.aas.AssetAdministrationShell` """ + + asset_information = model.AssetInformation( + asset_kind=model.AssetKind.INSTANCE, + global_asset_id='http://acplt.org/TestAsset/', + specific_asset_id={model.SpecificAssetId(name="TestKey", + value="TestValue", + external_subject_id=model.ExternalReference( + (model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SpecificAssetId/'),)), + semantic_id=model.ExternalReference((model.Key( + model.KeyTypes.GLOBAL_REFERENCE, + "http://acplt.org/SpecificAssetId/" + ),)))}, + asset_type='http://acplt.org/TestAssetType/', + default_thumbnail=model.Resource( + "file:///path/to/thumbnail.png", + "image/png" + ) + ) + asset_administration_shell = model.AssetAdministrationShell( - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='https://acplt.org/Test_Asset', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier(id_='https://acplt.org/Test_AssetAdministrationShell', - id_type=model.IdentifierType.IRI), + asset_information=asset_information, + id_='https://acplt.org/Test_AssetAdministrationShell', id_short='TestAssetAdministrationShell', category=None, - description={'en-us': 'An Example Asset Administration Shell for the test application', - 'de': 'Ein Beispiel-Verwaltungsschale für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({ + 'en-US': 'An Example Asset Administration Shell for the test application', + 'de': 'Ein Beispiel-Verwaltungsschale für eine Test-Anwendung' + }), parent=None, - administration=model.AdministrativeInformation(version='0.9', - revision='0'), - security=None, - submodel={model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=True, - value='https://acplt.org/Test_Submodel', - id_type=model.KeyType.IRI),), - model.Submodel), - model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=True, - value='http://acplt.org/Submodels/Assets/TestAsset/Identification', - id_type=model.KeyType.IRI),), - model.Submodel), - model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=True, - value='http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial', - id_type=model.KeyType.IRI),), - model.Submodel), + administration=model.AdministrativeInformation(version='9', + revision='0', + creator=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'Test_AssetAdministrationShell'), + )), + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/Test_AssetAdministrationShell'), + submodel={model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='https://acplt.org/Test_Submodel'),), + model.Submodel, + model.ExternalReference(( + model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelTemplates/ExampleSubmodel'), + ))), + model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Submodels/Assets/TestAsset/Identification'),), + model.Submodel, + model.ModelReference(( + model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/SubmodelTemplates/AssetIdentification'),), + model.Submodel + )), + model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial'),), + model.Submodel), }, - concept_dictionary=[concept_dictionary], - view=[], - derived_from=model.AASReference((model.Key(type_=model.KeyElements.ASSET_ADMINISTRATION_SHELL, - local=False, - value='https://acplt.org/TestAssetAdministrationShell2', - id_type=model.KeyType.IRI),), - model.AssetAdministrationShell)) + derived_from=model.ModelReference((model.Key(type_=model.KeyTypes.ASSET_ADMINISTRATION_SHELL, + value='https://acplt.org/TestAssetAdministrationShell2'),), + model.AssetAdministrationShell), + extension=(), + embedded_data_specifications=(_embedded_data_specification_iec61360,) + ) return asset_administration_shell @@ -703,19 +876,13 @@ def check_example_bill_of_material_submodel(checker: AASDataChecker, submodel: m checker.check_submodel_equal(submodel, expected_submodel) -def check_example_asset(checker: AASDataChecker, asset: model.Asset) -> None: - expected_asset = create_example_asset() - checker.check_asset_equal(asset, expected_asset) - - def check_example_concept_description(checker: AASDataChecker, concept_description: model.ConceptDescription) -> None: expected_concept_description = create_example_concept_description() checker.check_concept_description_equal(concept_description, expected_concept_description) def check_example_asset_administration_shell(checker: AASDataChecker, shell: model.AssetAdministrationShell) -> None: - example_cd = create_example_concept_dictionary() - expected_shell = create_example_asset_administration_shell(example_cd) + expected_shell = create_example_asset_administration_shell() checker.check_asset_administration_shell_equal(shell, expected_shell) @@ -725,5 +892,5 @@ def check_example_submodel(checker: AASDataChecker, submodel: model.Submodel) -> def check_full_example(checker: AASDataChecker, obj_store: model.DictObjectStore) -> None: - example_data = create_full_example() - checker.check_object_store(example_data, obj_store) + expected_data = create_full_example() + checker.check_object_store(obj_store, expected_data) diff --git a/basyx/aas/examples/data/example_aas_mandatory_attributes.py b/basyx/aas/examples/data/example_aas_mandatory_attributes.py index a69f57022..aa83d3f93 100644 --- a/basyx/aas/examples/data/example_aas_mandatory_attributes.py +++ b/basyx/aas/examples/data/example_aas_mandatory_attributes.py @@ -6,8 +6,8 @@ # SPDX-License-Identifier: MIT """ Module for the creation of an :class:`ObjectStore ` with an example -:class:`~aas.model.aas.AssetAdministrationShell`, related :class:`~aas.model.aas.Asset` and example -:class:`Submodels ` and a :class:`~aas.model.concept.ConceptDictionary` containing an +:class:`~aas.model.aas.AssetAdministrationShell` and example :class:`Submodels ` +and a :class:`~aas.model.concept.ConceptDictionary` containing an example :class:`~aas.model.concept.ConceptDescription`. All objects only contain mandatory attributes. @@ -26,34 +26,20 @@ def create_full_example() -> model.DictObjectStore: """ Creates an :class:`~.aas.model.provider.DictObjectStore` which is filled with an example - :class:`~aas.model.aas.Asset`, :class:`~aas.model.submodel.Submodel`, :class:`~aas.model.concept.ConceptDescription` + :class:`~aas.model.submodel.Submodel`, :class:`~aas.model.concept.ConceptDescription` and :class:`~aas.model.aas.AssetAdministrationShell` using the functions of this module :return: :class:`~aas.model.provider.DictObjectStore` """ obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - obj_store.add(create_example_asset()) obj_store.add(create_example_submodel()) obj_store.add(create_example_empty_submodel()) obj_store.add(create_example_concept_description()) - obj_store.add(create_example_asset_administration_shell(create_example_concept_dictionary())) + obj_store.add(create_example_asset_administration_shell()) obj_store.add(create_example_empty_asset_administration_shell()) return obj_store -def create_example_asset() -> model.Asset: - """ - Creates an example :class:`~aas.model.aas.Asset` where only the `kind` and `identification` attributes are set - - :return: example Asset - """ - asset = model.Asset( - kind=model.AssetKind.INSTANCE, - identification=model.Identifier(id_='https://acplt.org/Test_Asset_Mandatory', - id_type=model.IdentifierType.IRI)) - return asset - - def create_example_submodel() -> model.Submodel: """ Creates an example :class:`~aas.model.submodel.Submodel` containing all kind of @@ -63,51 +49,55 @@ def create_example_submodel() -> model.Submodel: """ submodel_element_property = model.Property( id_short='ExampleProperty', + category="PARAMETER", value_type=model.datatypes.String) submodel_element_multi_language_property = model.MultiLanguageProperty( + category="PARAMETER", id_short='ExampleMultiLanguageProperty') submodel_element_range = model.Range( id_short='ExampleRange', + category="PARAMETER", value_type=model.datatypes.Int) submodel_element_blob = model.Blob( id_short='ExampleBlob', - mime_type='application/pdf') + content_type='application/pdf') submodel_element_file = model.File( id_short='ExampleFile', - mime_type='application/pdf') + content_type='application/pdf') submodel_element_reference_element = model.ReferenceElement( + category="PARAMETER", id_short='ExampleReferenceElement') submodel_element_relationship_element = model.RelationshipElement( id_short='ExampleRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property)) + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property)) submodel_element_annotated_relationship_element = model.AnnotatedRelationshipElement( id_short='ExampleAnnotatedRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property)) + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property)) submodel_element_operation = model.Operation( id_short='ExampleOperation') @@ -115,144 +105,118 @@ def create_example_submodel() -> model.Submodel: submodel_element_capability = model.Capability( id_short='ExampleCapability') - submodel_element_basic_event = model.BasicEvent( - id_short='ExampleBasicEvent', - observed=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property)) + submodel_element_basic_event_element = model.BasicEventElement( + id_short='ExampleBasicEventElement', + observed=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, value='ExampleProperty'),), + model.Property), + direction=model.Direction.INPUT, + state=model.StateOfEvent.OFF) - submodel_element_submodel_element_collection_ordered = model.SubmodelElementCollectionOrdered( - id_short='ExampleSubmodelCollectionOrdered', - value=(submodel_element_property, - submodel_element_multi_language_property, - submodel_element_range)) - - submodel_element_submodel_element_collection_unordered = model.SubmodelElementCollectionUnordered( - id_short='ExampleSubmodelCollectionUnordered', + submodel_element_submodel_element_collection = model.SubmodelElementCollection( + id_short=None, value=(submodel_element_blob, submodel_element_file, + submodel_element_multi_language_property, + submodel_element_property, + submodel_element_range, submodel_element_reference_element)) - submodel_element_submodel_element_collection_unordered_2 = model.SubmodelElementCollectionUnordered( - id_short='ExampleSubmodelCollectionUnordered2', + submodel_element_submodel_element_collection_2 = model.SubmodelElementCollection( + id_short=None, + value=()) + + submodel_element_submodel_element_list = model.SubmodelElementList( + id_short='ExampleSubmodelList', + type_value_list_element=model.SubmodelElementCollection, + value=(submodel_element_submodel_element_collection, submodel_element_submodel_element_collection_2)) + + submodel_element_submodel_element_list_2 = model.SubmodelElementList( + id_short='ExampleSubmodelList2', + type_value_list_element=model.Capability, value=()) submodel = model.Submodel( - identification=model.Identifier(id_='https://acplt.org/Test_Submodel_Mandatory', - id_type=model.IdentifierType.IRI), + id_='https://acplt.org/Test_Submodel_Mandatory', submodel_element=(submodel_element_relationship_element, submodel_element_annotated_relationship_element, submodel_element_operation, submodel_element_capability, - submodel_element_basic_event, - submodel_element_submodel_element_collection_ordered, - submodel_element_submodel_element_collection_unordered, - submodel_element_submodel_element_collection_unordered_2)) + submodel_element_basic_event_element, + submodel_element_submodel_element_list, + submodel_element_submodel_element_list_2)) return submodel def create_example_empty_submodel() -> model.Submodel: """ - Creates an example empty :class:`~aas.model.submodel.Submodel` where only the identification attribute is set + Creates an example empty :class:`~aas.model.submodel.Submodel` where only the id attribute is set :return: example submodel """ return model.Submodel( - identification=model.Identifier(id_='https://acplt.org/Test_Submodel2_Mandatory', - id_type=model.IdentifierType.IRI)) + id_='https://acplt.org/Test_Submodel2_Mandatory') def create_example_concept_description() -> model.ConceptDescription: """ - Creates an example :class:`~aas.model.concept.ConceptDescription` where only the identification attribute is set + Creates an example :class:`~aas.model.concept.ConceptDescription` where only the id attribute is set :return: example concept description """ concept_description = model.ConceptDescription( - identification=model.Identifier(id_='https://acplt.org/Test_ConceptDescription_Mandatory', - id_type=model.IdentifierType.IRI)) + id_='https://acplt.org/Test_ConceptDescription_Mandatory') return concept_description -def create_example_concept_dictionary() -> model.ConceptDictionary: - """ - creates an example :class:`~aas.model.concept.ConceptDictionary` where only the `id_short` attribute is set - - :return: example concept dictionary - """ - concept_dictionary = model.ConceptDictionary( - id_short='TestConceptDictionary') - return concept_dictionary - - -def create_example_asset_administration_shell(concept_dictionary: model.ConceptDictionary) -> \ +def create_example_asset_administration_shell() -> \ model.AssetAdministrationShell: """ - Creates an example :class:`~aas.model.aas.AssetAdministrationShell` containing references to the example - :class:`~aas.model.aas.Asset`, the example :class:`Submodels ` and - including the example :class:`~aas.model.concept.ConceptDictionary` + Creates an example :class:`~aas.model.aas.AssetAdministrationShell` containing references to the example, + the example :class:`~Submodels `. :return: example asset administration shell """ + asset_information = model.AssetInformation( + asset_kind=model.AssetKind.INSTANCE, + global_asset_id='http://acplt.org/Test_Asset_Mandatory/') + asset_administration_shell = model.AssetAdministrationShell( - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='https://acplt.org/Test_Asset_Mandatory', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier(id_='https://acplt.org/Test_AssetAdministrationShell_Mandatory', - id_type=model.IdentifierType.IRI), - submodel={model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=True, - value='https://acplt.org/Test_Submodel_Mandatory', - id_type=model.KeyType.IRI),), - model.Submodel), - model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=True, - value='https://acplt.org/Test_Submodel2_Mandatory', - id_type=model.KeyType.IRI),), - model.Submodel)}, - concept_dictionary=[concept_dictionary]) + asset_information=asset_information, + id_='https://acplt.org/Test_AssetAdministrationShell_Mandatory', + submodel={model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='https://acplt.org/Test_Submodel_Mandatory'),), + model.Submodel), + model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='https://acplt.org/Test_Submodel2_Mandatory'),), + model.Submodel)},) return asset_administration_shell def create_example_empty_asset_administration_shell() -> model.AssetAdministrationShell: """ - Creates an example empty :class:`~aas.model.aas.AssetAdministrationShell` where only the reference to the - :class:`~aas.model.aas.Asset` and the identification - attribute is set + Creates an example empty :class:`~aas.model.aas.AssetAdministrationShell` with just + an empty :class:`~aas.model.aas.AssetInformation` and an :class:`~aas.model.base.Identifier` :return: example asset administration shell """ asset_administration_shell = model.AssetAdministrationShell( - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='https://acplt.org/Test_Asset_Mandatory', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier(id_='https://acplt.org/Test_AssetAdministrationShell2_Mandatory', - id_type=model.IdentifierType.IRI)) + asset_information=model.AssetInformation( + global_asset_id='http://acplt.org/TestAsset2_Mandatory/'), + id_='https://acplt.org/Test_AssetAdministrationShell2_Mandatory') return asset_administration_shell ############################################################################## # check functions for checking if an given object is the same as the example # ############################################################################## -def check_example_asset(checker: AASDataChecker, asset: model.Asset) -> None: - expected_asset = create_example_asset() - checker.check_asset_equal(asset, expected_asset) - - def check_example_concept_description(checker: AASDataChecker, concept_description: model.ConceptDescription) -> None: expected_concept_description = create_example_concept_description() checker.check_concept_description_equal(concept_description, expected_concept_description) def check_example_asset_administration_shell(checker: AASDataChecker, shell: model.AssetAdministrationShell) -> None: - example_cd = create_example_concept_dictionary() - expected_shell = create_example_asset_administration_shell(example_cd) + expected_shell = create_example_asset_administration_shell() checker.check_asset_administration_shell_equal(shell, expected_shell) @@ -273,5 +237,5 @@ def check_example_empty_submodel(checker: AASDataChecker, submodel: model.Submod def check_full_example(checker: AASDataChecker, obj_store: model.DictObjectStore) -> None: - example_data = create_full_example() - checker.check_object_store(example_data, obj_store) + expected_data = create_full_example() + checker.check_object_store(obj_store, expected_data) diff --git a/basyx/aas/examples/data/example_aas_missing_attributes.py b/basyx/aas/examples/data/example_aas_missing_attributes.py index 617b2fc64..cb296c764 100644 --- a/basyx/aas/examples/data/example_aas_missing_attributes.py +++ b/basyx/aas/examples/data/example_aas_missing_attributes.py @@ -8,6 +8,7 @@ Module for the creation of an :class:`ObjectStore ` with missing object attribute combination for testing the serialization """ +import datetime import logging from ... import model @@ -18,43 +19,19 @@ def create_full_example() -> model.DictObjectStore: """ - Creates an :class:`~aas.model.provider.DictObjectStore` containing an example asset identification - :class:`~aas.model.submodel.Submodel`, an example :class:`~aas.model.aas.Asset`, an example - :class:`~aas.model.submodel.Submodel`, + Creates an :class:`~aas.model.provider.DictObjectStore` containing an example :class:`~aas.model.submodel.Submodel`, an example :class:`~aas.model.concept.ConceptDescription` and an example :class:`~aas.model.aas.AssetAdministrationShell` :return: :class:`aas.model.provider.DictObjectStore` """ obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - obj_store.add(create_example_asset()) obj_store.add(create_example_submodel()) obj_store.add(create_example_concept_description()) - obj_store.add(create_example_asset_administration_shell(create_example_concept_dictionary())) + obj_store.add(create_example_asset_administration_shell()) return obj_store -def create_example_asset() -> model.Asset: - """ - Creates an example :class:`~aas.model.aas.Asset` which holds references to the example asset identification submodel - - :return: example asset - """ - asset = model.Asset( - kind=model.AssetKind.INSTANCE, - identification=model.Identifier(id_='https://acplt.org/Test_Asset_Missing', - id_type=model.IdentifierType.IRI), - id_short='Test_Asset', - category=None, - description={'en-us': 'An example asset for the test application', - 'de': 'Ein Beispiel-Asset für eine Test-Anwendung'}, - parent=None, - administration=model.AdministrativeInformation(), - asset_identification_model=None, - bill_of_material=None) - return asset - - def create_example_submodel() -> model.Submodel: """ Creates an example :class:`~aas.model.submodel.Submodel` containing all kind of @@ -72,32 +49,26 @@ def create_example_submodel() -> model.Submodel: value='exampleValue', value_id=None, # TODO category='CONSTANT', - description={'en-us': 'Example Property object', - 'de': 'Beispiel Property Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/ExampleProperty', - id_type=model.KeyType.IRI),)), - qualifier={qualifier}, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),)), + qualifier={qualifier}) submodel_element_multi_language_property = model.MultiLanguageProperty( id_short='ExampleMultiLanguageProperty', - value={'en-us': 'Example value of a MultiLanguageProperty element', - 'de': 'Beispielswert für ein MulitLanguageProperty-Element'}, + value=model.MultiLanguageTextType({'en-US': 'Example value of a MultiLanguageProperty element', + 'de': 'Beispielswert für ein MulitLanguageProperty-Element'}), value_id=None, # TODO category='CONSTANT', - description={'en-us': 'Example MultiLanguageProperty object', - 'de': 'Beispiel MulitLanguageProperty Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example MultiLanguageProperty object', + 'de': 'Beispiel MulitLanguageProperty Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/MultiLanguageProperties/' - 'ExampleMultiLanguageProperty', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/MultiLanguageProperties/' + 'ExampleMultiLanguageProperty'),)), + qualifier=()) submodel_element_range = model.Range( id_short='ExampleRange', @@ -105,238 +76,264 @@ def create_example_submodel() -> model.Submodel: min=0, max=100, category='PARAMETER', - description={'en-us': 'Example Range object', - 'de': 'Beispiel Range Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Range object', + 'de': 'Beispiel Range Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Ranges/ExampleRange', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Ranges/ExampleRange'),)), + qualifier=()) submodel_element_blob = model.Blob( id_short='ExampleBlob', - mime_type='application/pdf', + content_type='application/pdf', value=bytearray(b'\x01\x02\x03\x04\x05'), category='PARAMETER', - description={'en-us': 'Example Blob object', - 'de': 'Beispiel Blob Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Blob object', + 'de': 'Beispiel Blob Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Blobs/ExampleBlob', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Blobs/ExampleBlob'),)), + qualifier=()) submodel_element_file = model.File( id_short='ExampleFile', - mime_type='application/pdf', + content_type='application/pdf', value='/TestFile.pdf', category='PARAMETER', - description={'en-us': 'Example File object', - 'de': 'Beispiel File Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example File object', + 'de': 'Beispiel File Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Files/ExampleFile', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Files/ExampleFile'),)), + qualifier=()) submodel_element_reference_element = model.ReferenceElement( id_short='ExampleReferenceElement', - value=model.Reference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),)), + value=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), model.Submodel), category='PARAMETER', - description={'en-us': 'Example Reference Element object', - 'de': 'Beispiel Reference Element Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Reference Element object', + 'de': 'Beispiel Reference Element Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ReferenceElements/ExampleReferenceElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ReferenceElements/ExampleReferenceElement' + ),)), + qualifier=()) submodel_element_relationship_element = model.RelationshipElement( id_short='ExampleRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), category='PARAMETER', - description={'en-us': 'Example RelationshipElement object', - 'de': 'Beispiel RelationshipElement Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example RelationshipElement object', + 'de': 'Beispiel RelationshipElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/RelationshipElements/' - 'ExampleRelationshipElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/RelationshipElements/' + 'ExampleRelationshipElement'),)), + qualifier=()) submodel_element_annotated_relationship_element = model.AnnotatedRelationshipElement( id_short='ExampleAnnotatedRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), annotation={model.Property(id_short="ExampleAnnotatedProperty", value_type=model.datatypes.String, value='exampleValue', + category="PARAMETER", parent=None), model.Range(id_short="ExampleAnnotatedRange", value_type=model.datatypes.Integer, min=1, max=5, + category="PARAMETER", parent=None) }, category='PARAMETER', - description={'en-us': 'Example AnnotatedRelationshipElement object', - 'de': 'Beispiel AnnotatedRelationshipElement Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example AnnotatedRelationshipElement object', + 'de': 'Beispiel AnnotatedRelationshipElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/RelationshipElements/' - 'ExampleAnnotatedRelationshipElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/RelationshipElements/' + 'ExampleAnnotatedRelationshipElement'),)), + qualifier=()) - submodel_element_operation_variable_input = model.OperationVariable( - value=submodel_element_property) + operation_variable_property = model.Property( + id_short='ExampleProperty', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),)), + qualifier=()) - submodel_element_operation_variable_output = model.OperationVariable( - value=submodel_element_property) + input_variable_property = model.Property( + id_short='ExamplePropertyInput', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyInput'),)), + qualifier=()) - submodel_element_operation_variable_in_output = model.OperationVariable( - value=submodel_element_property) + output_variable_property = model.Property( + id_short='ExamplePropertyOutput', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyOutput'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=()) + + in_output_variable_property = model.Property( + id_short='ExamplePropertyInOutput', + value_type=model.datatypes.String, + value='exampleValue', + value_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ValueId/ExampleValueId'),)), + display_name=model.MultiLanguageNameType({'en-US': 'ExampleProperty', + 'de': 'BeispielProperty'}), + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyInOutput'),)), + qualifier=(), + extension=(), + supplemental_semantic_id=(), + embedded_data_specifications=()) submodel_element_operation = model.Operation( id_short='ExampleOperation', - input_variable=[submodel_element_operation_variable_input], - output_variable=[submodel_element_operation_variable_output], - in_output_variable=[submodel_element_operation_variable_in_output], + input_variable=[input_variable_property], + output_variable=[output_variable_property], + in_output_variable=[in_output_variable_property], category='PARAMETER', - description={'en-us': 'Example Operation object', - 'de': 'Beispiel Operation Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Operation object', + 'de': 'Beispiel Operation Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Operations/' - 'ExampleOperation', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Operations/' + 'ExampleOperation'),)), + qualifier=()) submodel_element_capability = model.Capability( id_short='ExampleCapability', category='PARAMETER', - description={'en-us': 'Example Capability object', - 'de': 'Beispiel Capability Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Capability object', + 'de': 'Beispiel Capability Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Capabilities/' - 'ExampleCapability', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) - - submodel_element_basic_event = model.BasicEvent( - id_short='ExampleBasicEvent', - observed=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Capabilities/' + 'ExampleCapability'),)), + qualifier=()) + + submodel_element_basic_event_element = model.BasicEventElement( + id_short='ExampleBasicEventElement', + observed=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + direction=model.Direction.OUTPUT, + state=model.StateOfEvent.ON, + message_topic='ExampleTopic', + message_broker=model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, + "http://acplt.org/ExampleMessageBroker"),), + model.Submodel), + last_update=model.datatypes.DateTime(2022, 11, 12, 23, 50, 23, 123456, datetime.timezone.utc), + min_interval=model.datatypes.Duration(microseconds=1), + max_interval=model.datatypes.Duration(years=1, months=2, days=3, hours=4, minutes=5, seconds=6, + microseconds=123456), category='PARAMETER', - description={'en-us': 'Example BasicEvent object', - 'de': 'Beispiel BasicEvent Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example BasicEventElement object', + 'de': 'Beispiel BasicEventElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Events/' - 'ExampleBasicEvent', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) - - submodel_element_submodel_element_collection_ordered = model.SubmodelElementCollectionOrdered( - id_short='ExampleSubmodelCollectionOrdered', - value=(submodel_element_property, - submodel_element_multi_language_property, - submodel_element_range), - category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionOrdered object', - 'de': 'Beispiel SubmodelElementCollectionOrdered Element'}, - parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionOrdered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) - - submodel_element_submodel_element_collection_unordered = model.SubmodelElementCollectionUnordered( - id_short='ExampleSubmodelCollectionUnordered', + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Events/ExampleBasicEventElement'),)), + qualifier=()) + + submodel_element_submodel_element_collection = model.SubmodelElementCollection( + id_short='ExampleSubmodelCollection', value=(submodel_element_blob, submodel_element_file, + submodel_element_multi_language_property, + submodel_element_property, + submodel_element_range, submodel_element_reference_element), category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionUnordered object', - 'de': 'Beispiel SubmodelElementCollectionUnordered Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementCollection object', + 'de': 'Beispiel SubmodelElementCollection Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionUnordered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementCollections/' + 'ExampleSubmodelElementCollection'),)), + qualifier=()) submodel = model.Submodel( - identification=model.Identifier(id_='https://acplt.org/Test_Submodel_Missing', - id_type=model.IdentifierType.IRI), + id_='https://acplt.org/Test_Submodel_Missing', submodel_element=(submodel_element_relationship_element, submodel_element_annotated_relationship_element, submodel_element_operation, submodel_element_capability, - submodel_element_basic_event, - submodel_element_submodel_element_collection_ordered, - submodel_element_submodel_element_collection_unordered), + submodel_element_basic_event_element, + submodel_element_submodel_element_collection), id_short='TestSubmodel', category=None, - description={'en-us': 'An example submodel for the test application', - 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({'en-US': 'An example submodel for the test application', + 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='0.9', + administration=model.AdministrativeInformation(version='9', revision='0'), - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelTemplates/' - 'ExampleSubmodel', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.INSTANCE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelTemplates/' + 'ExampleSubmodel'),)), + qualifier=(), + kind=model.ModellingKind.INSTANCE) return submodel @@ -347,81 +344,53 @@ def create_example_concept_description() -> model.ConceptDescription: :return: example concept description """ concept_description = model.ConceptDescription( - identification=model.Identifier(id_='https://acplt.org/Test_ConceptDescription_Missing', - id_type=model.IdentifierType.IRI), + id_='https://acplt.org/Test_ConceptDescription_Missing', is_case_of=None, id_short='TestConceptDescription', category=None, - description={'en-us': 'An example concept description for the test application', - 'de': 'Ein Beispiel-ConceptDescription für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({'en-US': 'An example concept description for the test application', + 'de': 'Ein Beispiel-ConceptDescription für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='0.9', + administration=model.AdministrativeInformation(version='9', revision='0')) return concept_description -def create_example_concept_dictionary() -> model.ConceptDictionary: +def create_example_asset_administration_shell() -> model.AssetAdministrationShell: """ - Creates an example :class:`~aas.model.concept.ConceptDictionary` containing an :class:`~aas.model.base.AASReference` - to the example :class:`~aas.model.concept.ConceptDescription` + Creates an example :class:`~aas.model.aas.AssetAdministrationShell` containing a reference to an example + :class:`~aas.model.submodel.Submodel` - :return: example concept dictionary + :return: example asset administration shell """ - concept_dictionary = model.ConceptDictionary( - id_short='TestConceptDictionary', - category=None, - description={'en-us': 'An example concept dictionary for the test application', - 'de': 'Ein Beispiel-ConceptDictionary für eine Test-Anwendung'}, - parent=None, - concept_description={model.AASReference((model.Key(type_=model.KeyElements.CONCEPT_DESCRIPTION, - local=False, - value='https://acplt.org/Test_ConceptDescription_Missing', - id_type=model.KeyType.IRI),), - model.ConceptDescription)}) - return concept_dictionary - -def create_example_asset_administration_shell(concept_dictionary: model.ConceptDictionary) -> \ - model.AssetAdministrationShell: - """ - Creates an example :class:`~aas.model.aas.AssetAdministrationShell` containing references to the example - :class:`~aas.model.Asset` and example :class:`~aas.model.submodel.Submodel` + resource = model.Resource( + content_type='application/pdf', + path='file:///TestFile.pdf') - :return: example asset administration shell - """ - view = model.View( - id_short='ExampleView', - contained_element={model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=False, - value='https://acplt.org/Test_Submodel_Missing', - id_type=model.KeyType.IRI),), - model.Submodel)}) - view_2 = model.View( - id_short='ExampleView2') + asset_information = model.AssetInformation( + asset_kind=model.AssetKind.INSTANCE, + global_asset_id='http://acplt.org/Test_Asset_Missing/', + specific_asset_id={model.SpecificAssetId(name="TestKey", value="TestValue", + external_subject_id=model.ExternalReference( + (model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SpecificAssetId/'),)))}, + default_thumbnail=resource) asset_administration_shell = model.AssetAdministrationShell( - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='https://acplt.org/Test_Asset_Missing', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier(id_='https://acplt.org/Test_AssetAdministrationShell_Missing', - id_type=model.IdentifierType.IRI), + asset_information=asset_information, + id_='https://acplt.org/Test_AssetAdministrationShell_Missing', id_short='TestAssetAdministrationShell', category=None, - description={'en-us': 'An Example Asset Administration Shell for the test application', - 'de': 'Ein Beispiel-Verwaltungsschale für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({'en-US': 'An Example Asset Administration Shell for the test ' + 'application', + 'de': 'Ein Beispiel-Verwaltungsschale für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='0.9', + administration=model.AdministrativeInformation(version='9', revision='0'), - security=None, - submodel={model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=True, - value='https://acplt.org/Test_Submodel_Missing', - id_type=model.KeyType.IRI),), - model.Submodel)}, - concept_dictionary=[concept_dictionary], - view=[view, view_2], + submodel={model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='https://acplt.org/Test_Submodel_Missing'),), + model.Submodel)}, derived_from=None) return asset_administration_shell @@ -429,19 +398,13 @@ def create_example_asset_administration_shell(concept_dictionary: model.ConceptD ############################################################################## # check functions for checking if an given object is the same as the example # ############################################################################## -def check_example_asset(checker: AASDataChecker, asset: model.Asset) -> None: - expected_asset = create_example_asset() - checker.check_asset_equal(asset, expected_asset) - - def check_example_concept_description(checker: AASDataChecker, concept_description: model.ConceptDescription) -> None: expected_concept_description = create_example_concept_description() checker.check_concept_description_equal(concept_description, expected_concept_description) def check_example_asset_administration_shell(checker: AASDataChecker, shell: model.AssetAdministrationShell) -> None: - example_cd = create_example_concept_dictionary() - expected_shell = create_example_asset_administration_shell(example_cd) + expected_shell = create_example_asset_administration_shell() checker.check_asset_administration_shell_equal(shell, expected_shell) @@ -451,5 +414,5 @@ def check_example_submodel(checker: AASDataChecker, submodel: model.Submodel) -> def check_full_example(checker: AASDataChecker, obj_store: model.DictObjectStore) -> None: - example_data = create_full_example() - checker.check_object_store(example_data, obj_store) + expected_data = create_full_example() + checker.check_object_store(obj_store, expected_data) diff --git a/basyx/aas/examples/data/example_concept_description.py b/basyx/aas/examples/data/example_concept_description.py deleted file mode 100644 index 84a62006d..000000000 --- a/basyx/aas/examples/data/example_concept_description.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors -# -# This program and the accompanying materials are made available under the terms of the MIT License, available in -# the LICENSE file of this project. -# -# SPDX-License-Identifier: MIT -""" -Module for creation of an example :class:`~aas.model.concept.ConceptDescription` -""" -import logging - -from ... import model -from ._helper import AASDataChecker -from ...model.concept import * - -logger = logging.getLogger(__name__) - - -def create_iec61360_concept_description() -> IEC61360ConceptDescription: - """ - Creates a :class:`~aas.model.concept.ConceptDescription` after the IEC61360 standard - - :return: Example concept description - """ - identification = model.Identifier(id_='http://acplt.org/DataSpecifciations/Example/Identification', - id_type=model.IdentifierType.IRI) - return IEC61360ConceptDescription( - identification=identification, - preferred_name={'de': 'Test Specification', 'en-us': "TestSpecification"}, - data_type=IEC61360DataType.REAL_MEASURE, - definition={'de': 'Dies ist eine Data Specification für Testzwecke', - 'en-us': "This is a DataSpecification for testing purposes"}, - short_name={'de': 'Test Spec', 'en-us': "TestSpec"}, - is_case_of={model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ReferenceElements/ConceptDescriptionX', - id_type=model.KeyType.IRI),))}, - id_short="TestSpec_01", - category=None, - description=None, - parent=None, - administration=model.AdministrativeInformation(version='0.9', revision='0'), - unit="SpaceUnit", - unit_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Units/SpaceUnit', - id_type=model.KeyType.IRI),)), - source_of_definition="http://acplt.org/DataSpec/ExampleDef", - symbol="SU", - value_format=model.datatypes.String, - value_list={ - model.ValueReferencePair( - value_type=model.datatypes.String, - value='exampleValue', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId', - id_type=model.KeyType.IRI),)),), - model.ValueReferencePair( - value_type=model.datatypes.String, - value='exampleValue2', - value_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ValueId/ExampleValueId2', - id_type=model.KeyType.IRI),)),)}, - value="TEST", - value_id=None, - level_types={IEC61360LevelType.MIN, IEC61360LevelType.MAX}) - - -############################################################################## -# check functions for checking if an given object is the same as the example # -############################################################################## -def check_example_iec61360_concept_description(checker: AASDataChecker, - concept_description: model.concept.IEC61360ConceptDescription) -> None: - expected_concept_description = create_iec61360_concept_description() - checker.check_concept_description_equal(concept_description, expected_concept_description) - - -def check_full_example(checker: AASDataChecker, obj_store: model.DictObjectStore) -> None: - example_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - example_data.add(create_iec61360_concept_description()) - checker.check_object_store(example_data, obj_store) diff --git a/basyx/aas/examples/data/example_submodel_template.py b/basyx/aas/examples/data/example_submodel_template.py index 26f4f3ef4..ad930f794 100644 --- a/basyx/aas/examples/data/example_submodel_template.py +++ b/basyx/aas/examples/data/example_submodel_template.py @@ -9,6 +9,7 @@ :class:`SubmodelElements ` where the kind is always `TEMPLATE`. """ +import datetime import logging from ... import model @@ -31,31 +32,25 @@ def create_example_submodel_template() -> model.Submodel: value=None, value_id=None, # TODO category='CONSTANT', - description={'en-us': 'Example Property object', - 'de': 'Beispiel Property Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/ExampleProperty', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExampleProperty'),)), + qualifier=()) submodel_element_multi_language_property = model.MultiLanguageProperty( id_short='ExampleMultiLanguageProperty', value=None, value_id=None, # TODO category='CONSTANT', - description={'en-us': 'Example MultiLanguageProperty object', - 'de': 'Beispiel MulitLanguageProperty Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example MultiLanguageProperty object', + 'de': 'Beispiel MulitLanguageProperty Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/MultiLanguageProperties/' - 'ExampleMultiLanguageProperty', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/MultiLanguageProperties/' + 'ExampleMultiLanguageProperty'),)), + qualifier=(),) submodel_element_range = model.Range( id_short='ExampleRange', @@ -63,15 +58,12 @@ def create_example_submodel_template() -> model.Submodel: min=None, max=100, category='PARAMETER', - description={'en-us': 'Example Range object', - 'de': 'Beispiel Range Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Range object', + 'de': 'Beispiel Range Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Ranges/ExampleRange', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Ranges/ExampleRange'),)), + qualifier=(),) submodel_element_range_2 = model.Range( id_short='ExampleRange2', @@ -79,243 +71,263 @@ def create_example_submodel_template() -> model.Submodel: min=0, max=None, category='PARAMETER', - description={'en-us': 'Example Range object', - 'de': 'Beispiel Range Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Range object', + 'de': 'Beispiel Range Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Ranges/ExampleRange', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Ranges/ExampleRange'),)), + qualifier=()) submodel_element_blob = model.Blob( id_short='ExampleBlob', - mime_type='application/pdf', + content_type='application/pdf', value=None, category='PARAMETER', - description={'en-us': 'Example Blob object', - 'de': 'Beispiel Blob Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Blob object', + 'de': 'Beispiel Blob Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Blobs/ExampleBlob', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Blobs/ExampleBlob'),)), + qualifier=()) submodel_element_file = model.File( id_short='ExampleFile', - mime_type='application/pdf', + content_type='application/pdf', value=None, category='PARAMETER', - description={'en-us': 'Example File object', - 'de': 'Beispiel File Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example File object', + 'de': 'Beispiel File Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Files/ExampleFile', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Files/ExampleFile'),)), + qualifier=()) submodel_element_reference_element = model.ReferenceElement( id_short='ExampleReferenceElement', value=None, category='PARAMETER', - description={'en-us': 'Example Reference Element object', - 'de': 'Beispiel Reference Element Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Reference Element object', + 'de': 'Beispiel Reference Element Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/ReferenceElements/ExampleReferenceElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/ReferenceElements/ExampleReferenceElement' + ),)), + qualifier=()) submodel_element_relationship_element = model.RelationshipElement( id_short='ExampleRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), category='PARAMETER', - description={'en-us': 'Example RelationshipElement object', - 'de': 'Beispiel RelationshipElement Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example RelationshipElement object', + 'de': 'Beispiel RelationshipElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/RelationshipElements/' - 'ExampleRelationshipElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/RelationshipElements/' + 'ExampleRelationshipElement'),)), + qualifier=()) submodel_element_annotated_relationship_element = model.AnnotatedRelationshipElement( id_short='ExampleAnnotatedRelationshipElement', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), annotation=(), category='PARAMETER', - description={'en-us': 'Example AnnotatedRelationshipElement object', - 'de': 'Beispiel AnnotatedRelationshipElement Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example AnnotatedRelationshipElement object', + 'de': 'Beispiel AnnotatedRelationshipElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/RelationshipElements/' - 'ExampleAnnotatedRelationshipElement', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/RelationshipElements/' + 'ExampleAnnotatedRelationshipElement'),)), + qualifier=()) - submodel_element_operation_variable_input = model.OperationVariable( - value=submodel_element_property) + input_variable_property = model.Property( + id_short='ExamplePropertyInput', + value_type=model.datatypes.String, + value=None, + value_id=None, + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyInput'),)), + qualifier=()) - submodel_element_operation_variable_output = model.OperationVariable( - value=submodel_element_property) + output_variable_property = model.Property( + id_short='ExamplePropertyOutput', + value_type=model.datatypes.String, + value=None, + value_id=None, + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyOutput'),)), + qualifier=()) - submodel_element_operation_variable_in_output = model.OperationVariable( - value=submodel_element_property) + in_output_variable_property = model.Property( + id_short='ExamplePropertyInOutput', + value_type=model.datatypes.String, + value=None, + value_id=None, + category='CONSTANT', + description=model.MultiLanguageTextType({'en-US': 'Example Property object', + 'de': 'Beispiel Property Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/ExamplePropertyInOutput'),)), + qualifier=()) submodel_element_operation = model.Operation( id_short='ExampleOperation', - input_variable=[submodel_element_operation_variable_input], - output_variable=[submodel_element_operation_variable_output], - in_output_variable=[submodel_element_operation_variable_in_output], + input_variable=[input_variable_property], + output_variable=[output_variable_property], + in_output_variable=[in_output_variable_property], category='PARAMETER', - description={'en-us': 'Example Operation object', - 'de': 'Beispiel Operation Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Operation object', + 'de': 'Beispiel Operation Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Operations/' - 'ExampleOperation', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Operations/' + 'ExampleOperation'),)), + qualifier=()) submodel_element_capability = model.Capability( id_short='ExampleCapability', category='PARAMETER', - description={'en-us': 'Example Capability object', - 'de': 'Beispiel Capability Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example Capability object', + 'de': 'Beispiel Capability Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Capabilities/' - 'ExampleCapability', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Capabilities/' + 'ExampleCapability'),)), + qualifier=()) - submodel_element_basic_event = model.BasicEvent( - id_short='ExampleBasicEvent', - observed=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + submodel_element_basic_event_element = model.BasicEventElement( + id_short='ExampleBasicEventElement', + observed=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + direction=model.Direction.OUTPUT, + state=model.StateOfEvent.ON, + message_topic='ExampleTopic', + message_broker=model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, + "http://acplt.org/ExampleMessageBroker"),), + model.Submodel), + last_update=model.datatypes.DateTime(2022, 11, 12, 23, 50, 23, 123456, datetime.timezone.utc), + min_interval=model.datatypes.Duration(microseconds=1), + max_interval=model.datatypes.Duration(years=1, months=2, days=3, hours=4, minutes=5, seconds=6, + microseconds=123456), category='PARAMETER', - description={'en-us': 'Example BasicEvent object', - 'de': 'Beispiel BasicEvent Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example BasicEventElement object', + 'de': 'Beispiel BasicEventElement Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Events/' - 'ExampleBasicEvent', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Events/ExampleBasicEventElement'),)), + qualifier=()) - submodel_element_submodel_element_collection_ordered = model.SubmodelElementCollectionOrdered( - id_short='ExampleSubmodelCollectionOrdered', - value=(submodel_element_property, + submodel_element_submodel_element_collection = model.SubmodelElementCollection( + id_short=None, + value=( + submodel_element_property, submodel_element_multi_language_property, submodel_element_range, - submodel_element_range_2), + submodel_element_range_2, + submodel_element_blob, + submodel_element_file, + submodel_element_reference_element), category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionOrdered object', - 'de': 'Beispiel SubmodelElementCollectionOrdered Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementCollection object', + 'de': 'Beispiel SubmodelElementCollection Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionOrdered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementCollections/' + 'ExampleSubmodelElementCollection'),)), + qualifier=()) - submodel_element_submodel_element_collection_unordered = model.SubmodelElementCollectionUnordered( - id_short='ExampleSubmodelCollectionUnordered', - value=(submodel_element_blob, - submodel_element_file, - submodel_element_reference_element), + submodel_element_submodel_element_collection_2 = model.SubmodelElementCollection( + id_short=None, + value=(), + category='PARAMETER', + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementCollection object', + 'de': 'Beispiel SubmodelElementCollection Element'}), + parent=None, + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementCollections/' + 'ExampleSubmodelElementCollection'),)), + qualifier=()) + + submodel_element_submodel_element_list = model.SubmodelElementList( + id_short='ExampleSubmodelList', + type_value_list_element=model.SubmodelElementCollection, + value=(submodel_element_submodel_element_collection, submodel_element_submodel_element_collection_2), + semantic_id_list_element=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementCollections/' + 'ExampleSubmodelElementCollection'),)), + order_relevant=True, category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionUnordered object', - 'de': 'Beispiel SubmodelElementCollectionUnordered Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementList object', + 'de': 'Beispiel SubmodelElementList Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionUnordered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementLists/' + 'ExampleSubmodelElementList'),)), + qualifier=()) - submodel_element_submodel_element_collection_unordered_2 = model.SubmodelElementCollectionUnordered( - id_short='ExampleSubmodelCollectionUnordered2', + submodel_element_submodel_element_list_2 = model.SubmodelElementList( + id_short='ExampleSubmodelList2', + type_value_list_element=model.Capability, value=(), + semantic_id_list_element=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementCollections/' + 'ExampleSubmodelElementCollection'),)), + order_relevant=True, category='PARAMETER', - description={'en-us': 'Example SubmodelElementCollectionUnordered object', - 'de': 'Beispiel SubmodelElementCollectionUnordered Element'}, + description=model.MultiLanguageTextType({'en-US': 'Example SubmodelElementList object', + 'de': 'Beispiel SubmodelElementList Element'}), parent=None, - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelElementCollections/' - 'ExampleSubmodelElementCollectionUnordered', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelElementLists/' + 'ExampleSubmodelElementList'),)), + qualifier=()) submodel = model.Submodel( - identification=model.Identifier(id_='https://acplt.org/Test_Submodel_Template', - id_type=model.IdentifierType.IRI), + id_='https://acplt.org/Test_Submodel_Template', submodel_element=(submodel_element_relationship_element, submodel_element_annotated_relationship_element, submodel_element_operation, submodel_element_capability, - submodel_element_basic_event, - submodel_element_submodel_element_collection_ordered, - submodel_element_submodel_element_collection_unordered, - submodel_element_submodel_element_collection_unordered_2), + submodel_element_basic_event_element, + submodel_element_submodel_element_list, + submodel_element_submodel_element_list_2), id_short='TestSubmodel', category=None, - description={'en-us': 'An example submodel for the test application', - 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}, + description=model.MultiLanguageTextType({'en-US': 'An example submodel for the test application', + 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='0.9', + administration=model.AdministrativeInformation(version='9', revision='0'), - semantic_id=model.Reference((model.Key(type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/SubmodelTemplates/' - 'ExampleSubmodel', - id_type=model.KeyType.IRI),)), - qualifier=None, - kind=model.ModelingKind.TEMPLATE) + semantic_id=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/SubmodelTemplates/' + 'ExampleSubmodel'),)), + qualifier=(), + kind=model.ModellingKind.TEMPLATE) return submodel @@ -328,6 +340,6 @@ def check_example_submodel(checker: AASDataChecker, submodel: model.Submodel) -> def check_full_example(checker: AASDataChecker, obj_store: model.DictObjectStore) -> None: - example_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - example_data.add(create_example_submodel_template()) - checker.check_object_store(example_data, obj_store) + expected_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() + expected_data.add(create_example_submodel_template()) + checker.check_object_store(obj_store, expected_data) diff --git a/basyx/aas/examples/tutorial_aasx.py b/basyx/aas/examples/tutorial_aasx.py index 9d9c2c5f8..3e7e59748 100755 --- a/basyx/aas/examples/tutorial_aasx.py +++ b/basyx/aas/examples/tutorial_aasx.py @@ -30,27 +30,26 @@ # See `tutorial_create_simple_aas.py` for more details. submodel = model.Submodel( - identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) -) -asset = model.Asset( - kind=model.AssetKind.INSTANCE, # define that the Asset is of kind instance - identification=model.Identifier(id_='https://acplt.org/Simple_Asset', id_type=model.IdentifierType.IRI) + id_='https://acplt.org/Simple_Submodel' ) aas = model.AssetAdministrationShell( - identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), - asset=model.AASReference.from_referable(asset), - submodel={model.AASReference.from_referable(submodel)} + id_='https://acplt.org/Simple_AAS', + asset_information=model.AssetInformation( + asset_kind=model.AssetKind.INSTANCE, + global_asset_id='http://acplt.org/Simple_Asset' + ), + submodel={model.ModelReference.from_referable(submodel)} ) # Another submodel, which is not related to the AAS: unrelated_submodel = model.Submodel( - identification=model.Identifier('https://acplt.org/Unrelated_Submodel', model.IdentifierType.IRI) + id_='https://acplt.org/Unrelated_Submodel' ) -# We add these objects to an ObjectStore for easy retrieval by identification. +# We add these objects to an ObjectStore for easy retrieval by id. # See `tutorial_storage.py` for more details. We could also use a database-backed ObjectStore here # (see `tutorial_backend_couchdb.py`). -object_store = model.DictObjectStore([submodel, asset, aas, unrelated_submodel]) +object_store = model.DictObjectStore([submodel, aas, unrelated_submodel]) # For holding auxiliary files, which will eventually be added to an AASX package, we need an SupplementaryFileContainer. @@ -79,7 +78,7 @@ submodel.submodel_element.add( model.File(id_short="documentationFile", - mime_type="application/pdf", + content_type="application/pdf", value=actual_file_name)) @@ -87,36 +86,37 @@ # Step 2: Writing AAS objects and auxiliary files to an AASX package # ###################################################################### -# After setting everything up in Step 1, writing the AAS, including the Submdel and Asset objects and the auxiliary -# file to an AASX package is simple. +# After setting everything up in Step 1, writing the AAS, including the Submodel objects and the auxiliary file +# to an AASX package is simple. # Open an AASXWriter with the destination file name and use it as a context handler, to make sure it is properly closed # after doing the modifications: with aasx.AASXWriter("MyAASXPackage.aasx") as writer: # Write the AAS and everything belonging to it to the AASX package - # The `write_aas()` method will automatically fetch the AAS object with the given identification, the referenced - # Asset object and all referenced Submodel and ConceptDescription objects from the ObjectStore. It will also - # scan all sbmodels for `File` objects and fetch the referenced auxiliary files from the SupplementaryFileContainer. - writer.write_aas(aas_id=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), + # The `write_aas()` method will automatically fetch the AAS object with the given id + # and all referenced Submodel objects from the ObjectStore. It will also scan every object for + # semanticIds referencing ConceptDescription, fetch them from the ObjectStore, and scan all sbmodels for `File` + # objects and fetch the referenced auxiliary files from the SupplementaryFileContainer. + # In order to add more than one AAS to the package, we can simply add more Identifiers to the `aas_ids` list. + # + # ATTENTION: As of Version 3.0 RC01 of Details of the Asset Administration Shell, it is not longer valid to add more + # than one "aas-spec" part (JSON/XML part with AAS objects) to an AASX package. Thus, `write_aas` MUST + # only be called once per AASX package! + writer.write_aas(aas_ids=['https://acplt.org/Simple_AAS'], object_store=object_store, - file_store=file_store, - submodel_split_parts=False) # for compatibility with AASX Package Explorer - - # For adding a second AAS to the package, we can simply call `write_aas()` again. - # Warning: This will create a second XML/JSON part in the AASX Package, which is compliant with the "Details of the - # Asset Administration Shell" standard up to version 2.0.1, but not supported by AASX Package Explorer. - - # We can also use a more low-level interface to add a JSON/XML part with any Identifiable objects (not only an AAS - # and referenced objects) in the AASX package manually. `write_aas_objects()` will also take care of adding - # referenced auxiliary files by scanning all submodel objects for contained `File` objects. - # Warning: AASX Package Explorer will only read the first XML part in an AASX package. Thus, in this example, it - # will only find the objects, written by `write_aas()` above. - writer.write_aas_objects(part_name="/aasx/my_aas_part.xml", - object_ids=[ - model.Identifier('https://acplt.org/Unrelated_Submodel', model.IdentifierType.IRI) - ], - object_store=object_store, - file_store=file_store) + file_store=file_store) + + # Alternatively, we can use a more low-level interface to add a JSON/XML part with any Identifiable objects (not + # only an AAS and referenced objects) in the AASX package manually. `write_aas_objects()` will also take care of + # adding referenced auxiliary files by scanning all submodel objects for contained `File` objects. + # + # ATTENTION: As of Version 3.0 RC01 of Details of the Asset Administration Shell, it is not longer valid to add more + # than one "aas-spec" part (JSON/XML part with AAS objects) to an AASX package. Thus, `write_all_aas_objects` SHALL + # only be used as an alternative to `write_aas` and SHALL only be called once! + objects_to_be_written: model.DictObjectStore[model.Identifiable] = model.DictObjectStore([unrelated_submodel]) + writer.write_all_aas_objects(part_name="/aasx/my_aas_part.xml", + objects=objects_to_be_written, + file_store=file_store) # We can also add a thumbnail image to the package (using `writer.write_thumbnail()`) or add metadata: meta_data = pyecma376_2.OPCCoreProperties() @@ -142,8 +142,6 @@ # package file is properly closed when we are finished. with aasx.AASXReader("MyAASXPackage.aasx") as reader: # Read all contained AAS objects and all referenced auxiliary files - # In contrast to the AASX Package Explorer, we are not limited to a single XML part in the package, but instead we - # will read the contents of all included JSON and XML parts into the ObjectStore reader.read_into(object_store=new_object_store, file_store=new_file_store) @@ -154,7 +152,6 @@ # Some quick checks to make sure, reading worked as expected -assert model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) in new_object_store -assert model.Identifier('https://acplt.org/Unrelated_Submodel', model.IdentifierType.IRI) in new_object_store +assert 'https://acplt.org/Simple_Submodel' in new_object_store assert actual_file_name in new_file_store assert new_meta_data.creator == "Chair of Process Control Engineering" diff --git a/basyx/aas/examples/tutorial_create_simple_aas.py b/basyx/aas/examples/tutorial_create_simple_aas.py index fff6e1bd0..c7fcb7be0 100755 --- a/basyx/aas/examples/tutorial_create_simple_aas.py +++ b/basyx/aas/examples/tutorial_create_simple_aas.py @@ -2,7 +2,7 @@ # This work is licensed under a Creative Commons CCZero 1.0 Universal License. # See http://creativecommons.org/publicdomain/zero/1.0/ for more information. """ -Tutorial for the creation of an simple Asset Administration Shell, containing an Asset reference and a Submodel +Tutorial for the creation of an simple Asset Administration Shell, containing an AssetInformation object and a Submodel reference """ @@ -10,88 +10,74 @@ from basyx.aas import model # In this tutorial, you'll get a step by step guide on how to create an Asset Administration Shell (AAS) and all -# required objects within. First, you need an asset for which you want to create an AAS, represented by an Asset object. -# After that, an Asset Administration Shell can be created, containing a reference to that Asset. Then, it's possible to -# add Submodels to the AAS. The Submodels can contain SubmodelElements. +# required objects within. First, you need an AssetInformation object for which you want to create an AAS. After that, +# an Asset Administration Shell can be created. Then, it's possible to add Submodels to the AAS. The Submodels can +# contain SubmodelElements. # # Step by Step Guide: -# step 1: create a simple Asset object -# step 2: create a simple Asset Administration Shell, containing a reference to the Asset -# step 3: create a simple Submodel -# step 4: create a simple Property and add it to the Submodel - - -################################# -# Step 1: Create a Simple Asset # -################################# - -# step 1.1: create an identifier for the Asset -# Here we use an IRI identifier -identifier = model.Identifier(id_='https://acplt.org/Simple_Asset', - id_type=model.IdentifierType.IRI) - -# step 1.2: create the Asset object -asset = model.Asset( - kind=model.AssetKind.INSTANCE, # define that the Asset is of kind instance - identification=identifier # set identifier +# Step 1: create a simple Asset Administration Shell, containing an AssetInformation object +# Step 2: create a simple Submodel +# Step 3: create a simple Property and add it to the Submodel + + +############################################################################################ +# Step 1: Create a Simple Asset Administration Shell Containing an AssetInformation object # +############################################################################################ +# Step 1.1: create the AssetInformation object +asset_information = model.AssetInformation( + asset_kind=model.AssetKind.INSTANCE, + global_asset_id='http://acplt.org/Simple_Asset' ) - -########################################################################################## -# Step 2: Create a Simple Asset Administration Shell Containing a Reference to the Asset # -########################################################################################## - -# step 2.1: create the Asset Administration Shell -identifier = model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI) +# step 1.2: create the Asset Administration Shell +identifier = 'https://acplt.org/Simple_AAS' aas = model.AssetAdministrationShell( - identification=identifier, # set identifier - asset=model.AASReference.from_referable(asset) # generate a Reference object to the Asset (using its identifier) + id_=identifier, # set identifier + asset_information=asset_information ) ############################################################# -# step 3: Create a Simple Submodel Without SubmodelElements # +# Step 2: Create a Simple Submodel Without SubmodelElements # ############################################################# -# step 3.1: create the Submodel object -identifier = model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) +# Step 2.1: create the Submodel object +identifier = 'https://acplt.org/Simple_Submodel' submodel = model.Submodel( - identification=identifier + id_=identifier ) -# step 3.2: create a reference to that Submodel and add it to the Asset Administration Shell's `submodel` set -aas.submodel.add(model.AASReference.from_referable(submodel)) +# Step 2.2: create a reference to that Submodel and add it to the Asset Administration Shell's `submodel` set +aas.submodel.add(model.ModelReference.from_referable(submodel)) # =============================================================== -# ALTERNATIVE: step 2 and 3 can alternatively be done in one step +# ALTERNATIVE: step 1 and 2 can alternatively be done in one step # In this version, the Submodel reference is passed to the Asset Administration Shell's constructor. submodel = model.Submodel( - identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI) + id_='https://acplt.org/Simple_Submodel' ) aas = model.AssetAdministrationShell( - identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), - asset=model.AASReference.from_referable(asset), - submodel={model.AASReference.from_referable(submodel)} + id_='https://acplt.org/Simple_AAS', + asset_information=asset_information, + submodel={model.ModelReference.from_referable(submodel)} ) ############################################################### -# step 4: Create a Simple Property and Add it to the Submodel # +# Step 3: Create a Simple Property and Add it to the Submodel # ############################################################### -# step 4.1: create a global reference to a semantic description of the Property +# Step 3.1: create a global reference to a semantic description of the Property # A global reference consist of one key which points to the address where the semantic description is stored -semantic_reference = model.Reference( +semantic_reference = model.ExternalReference( (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/SimpleProperty' ),) ) -# step 4.2: create the simple Property +# Step 3.2: create the simple Property property_ = model.Property( id_short='ExampleProperty', # Identifying string of the element within the Submodel namespace value_type=model.datatypes.String, # Data type of the value @@ -99,26 +85,24 @@ semantic_id=semantic_reference # set the semantic reference ) -# step 4.3: add the Property to the Submodel +# Step 3.3: add the Property to the Submodel submodel.submodel_element.add(property_) # ===================================================================== -# ALTERNATIVE: step 3 and 4 can also be combined in a single statement: +# ALTERNATIVE: step 2 and 3 can also be combined in a single statement: # Again, we pass the Property to the Submodel's constructor instead of adding it afterwards. submodel = model.Submodel( - identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), + id_='https://acplt.org/Simple_Submodel', submodel_element={ model.Property( id_short='ExampleProperty', value_type=model.datatypes.String, value='exampleValue', - semantic_id=model.Reference( + semantic_id=model.ExternalReference( (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/SimpleProperty' ),) ) ) diff --git a/basyx/aas/examples/tutorial_serialization_deserialization.py b/basyx/aas/examples/tutorial_serialization_deserialization.py index 84b9afabc..8f7b36949 100755 --- a/basyx/aas/examples/tutorial_serialization_deserialization.py +++ b/basyx/aas/examples/tutorial_serialization_deserialization.py @@ -18,44 +18,37 @@ # restore the AAS objects as Python objects. # # Step by Step Guide: -# step 1: creating Asset, Submodel and Asset Administration Shell objects -# step 2: serializing single objects to JSON -# step 3: parsing single objects or custom data structures from JSON -# step 4: writing multiple identifiable objects to a (standard-compliant) JSON/XML file +# Step 1: creating Submodel and Asset Administration Shell objects +# Step 2: serializing single objects to JSON +# Step 3: parsing single objects or custom data structures from JSON +# Step 4: writing multiple identifiable objects to a (standard-compliant) JSON/XML file # Step 5: reading the serialized aas objects from JSON/XML files -########################################################################### -# Step 1: Creating Asset, Submodel and Asset Administration Shell Objects # -########################################################################### +#################################################################### +# Step 1: Creating Submodel and Asset Administration Shell Objects # +#################################################################### # For more details, take a look at `tutorial_create_simple_aas.py` -asset = model.Asset( - kind=model.AssetKind.INSTANCE, - identification=model.Identifier('https://acplt.org/Simple_Asset', model.IdentifierType.IRI) -) submodel = model.Submodel( - identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), + id_='https://acplt.org/Simple_Submodel', submodel_element={ model.Property( id_short='ExampleProperty', value_type=basyx.aas.model.datatypes.String, value='exampleValue', - semantic_id=model.Reference( - (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI + semantic_id=model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/SimpleProperty' ),) ) )} ) aashell = model.AssetAdministrationShell( - identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), - asset=model.AASReference.from_referable(asset), - submodel={model.AASReference.from_referable(submodel)} + id_='https://acplt.org/Simple_AAS', + asset_information=model.AssetInformation(global_asset_id="test"), + submodel={model.ModelReference.from_referable(submodel)} ) @@ -75,7 +68,7 @@ # dumped data structure. aashell_json_string = json.dumps(aashell, cls=basyx.aas.adapter.json.AASToJsonEncoder) -property_json_string = json.dumps(submodel.submodel_element.get_referable('ExampleProperty'), +property_json_string = json.dumps(submodel.submodel_element.get_object_by_attribute("id_short", 'ExampleProperty'), cls=basyx.aas.adapter.json.AASToJsonEncoder) # Using this technique, we can also serialize Python dict and list data structures with nested AAS objects: @@ -107,12 +100,10 @@ # step 4.1: creating an ObjectStore containing the objects to be serialized # For more information, take a look into `tutorial_storage.py` obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() -obj_store.add(asset) obj_store.add(submodel) obj_store.add(aashell) # step 4.2: Again, make sure that the data is up to date -asset.update() submodel.update() aashell.update() @@ -154,6 +145,5 @@ # step 5.3: Retrieving the objects from the ObjectStore # For more information on the availiable techniques, see `tutorial_storage.py`. -submodel_from_xml = xml_file_data.get_identifiable(model.Identifier('https://acplt.org/Simple_Submodel', - model.IdentifierType.IRI)) +submodel_from_xml = xml_file_data.get_identifiable('https://acplt.org/Simple_Submodel') assert isinstance(submodel_from_xml, model.Submodel) diff --git a/basyx/aas/examples/tutorial_storage.py b/basyx/aas/examples/tutorial_storage.py index 8c8724190..d479dae05 100755 --- a/basyx/aas/examples/tutorial_storage.py +++ b/basyx/aas/examples/tutorial_storage.py @@ -3,7 +3,7 @@ # See http://creativecommons.org/publicdomain/zero/1.0/ for more information. """ Tutorial for storing Asset Administration Shells, Submodels and Assets in an ObjectStore and using it for fetching these -objects by identification and resolving references. +objects by id and resolving references. """ # For managing a larger number of Identifiable AAS objects (AssetAdministrationShells, Assets, Submodels, @@ -13,55 +13,54 @@ # `AssetAdministrationShell.submodel` set, etc. # # Step by Step Guide: -# step 1: creating Asset, Submodel and Asset Administration Shell objects -# step 2: storing the data in an ObjectStore for easier handling -# step 3: retrieving objects from the store by their identifier -# step 4: using the ObjectStore to resolve a reference +# Step 1: creating AssetInformation, Submodel and Asset Administration Shell objects +# Step 2: storing the data in an ObjectStore for easier handling +# Step 3: retrieving objects from the store by their identifier +# Step 4: using the ObjectStore to resolve a reference from basyx.aas import model -from basyx.aas.model import Asset, AssetAdministrationShell, Submodel +from basyx.aas.model import AssetInformation, AssetAdministrationShell, Submodel -########################################################################### -# Step 1: Creating Asset, Submodel and Asset Administration Shell objects # -########################################################################### +###################################################################################### +# Step 1: Creating AssetInformation, Submodel and Asset Administration Shell objects # +###################################################################################### # For more details, take a look at `tutorial_create_simple_aas.py` -asset = Asset( - kind=model.AssetKind.INSTANCE, - identification=model.Identifier('https://acplt.org/Simple_Asset', model.IdentifierType.IRI) +asset_information = AssetInformation( + asset_kind=model.AssetKind.INSTANCE, + global_asset_id='http://acplt.org/Simple_Asset' ) + prop = model.Property( id_short='ExampleProperty', value_type=model.datatypes.String, value='exampleValue', - semantic_id=model.Reference( + semantic_id=model.ExternalReference( (model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='http://acplt.org/Properties/SimpleProperty', - id_type=model.KeyType.IRI + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Properties/SimpleProperty' ),) ) ) submodel = Submodel( - identification=model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI), + id_='https://acplt.org/Simple_Submodel', submodel_element={prop} ) aas = AssetAdministrationShell( - identification=model.Identifier('https://acplt.org/Simple_AAS', model.IdentifierType.IRI), - asset=model.AASReference.from_referable(asset), - submodel={model.AASReference.from_referable(submodel)} + id_='https://acplt.org/Simple_AAS', + asset_information=asset_information, + submodel={model.ModelReference.from_referable(submodel)} ) ################################################################## -# step 2: Storing the Data in an ObjectStore for Easier Handling # +# Step 2: Storing the Data in an ObjectStore for Easier Handling # ################################################################## -# step 2.1: create an ObjectStore for identifiable objects +# Step 2.1: create an ObjectStore for identifiable objects # # In this tutorial, we use a `DictObjectStore`, which is a simple in-memory store: It just keeps track of the Python # objects using a dict. @@ -73,24 +72,23 @@ # information. obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() -# step 2.2: add asset, submodel and asset administration shell to store -obj_store.add(asset) +# step 2.2: add submodel and asset administration shell to store obj_store.add(submodel) obj_store.add(aas) ################################################################# -# step 3: Retrieving Objects From the Store by Their Identifier # +# Step 3: Retrieving Objects From the Store by Their Identifier # ################################################################# tmp_submodel = obj_store.get_identifiable( - model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI)) + 'https://acplt.org/Simple_Submodel') assert submodel is tmp_submodel ######################################################## -# step 4: Using the ObjectStore to Resolve a Reference # +# Step 4: Using the ObjectStore to Resolve a Reference # ######################################################## # The `aas` object already contains a reference to the submodel. @@ -102,21 +100,17 @@ assert submodel is tmp_submodel # Now, let's manually create a reference to the Property within the submodel. The reference uses two keys, the first one -# identifying the submodel by its identification, the second one resolving to the Property within the submodel by its +# identifying the submodel by its id, the second one resolving to the Property within the submodel by its # idShort. -property_reference = model.AASReference( +property_reference = model.ModelReference( (model.Key( - type_=model.KeyElements.SUBMODEL, - local=True, - value='https://acplt.org/Simple_Submodel', - id_type=model.KeyType.IRI), + type_=model.KeyTypes.SUBMODEL, + value='https://acplt.org/Simple_Submodel'), model.Key( - type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT), + type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'), ), - target_type=model.Property + type_=model.Property ) # Now, we can resolve this new reference. diff --git a/basyx/aas/model/__init__.py b/basyx/aas/model/__init__.py index f66d29d8e..0e7cad672 100644 --- a/basyx/aas/model/__init__.py +++ b/basyx/aas/model/__init__.py @@ -5,12 +5,12 @@ .. code-block:: python - from aas.model import AssetAdministrationShell, Asset, Submodel, Property + from aas.model import AssetAdministrationShell, Submodel, Property The different modules are: aas.py - The main module, implementing high-level structures, such as AssetAdministrationShell, Asset and ConceptDictionary. + The main module, implementing high-level structures, such as AssetAdministrationShell and ConceptDictionary. base.py Basic structures of the model, including all abstract classes and enumerations. This provides inheritance for the @@ -25,46 +25,38 @@ Providers for AAS objects, in order to store and retrieve :class:`~aas.model.base.Identifiable` objects by their :class:`~aas.model.base.Identifier`. -security.py - Security model of the AAS. Currently not existing. - submodel.py Meta-model of the submodels and events. """ -from typing import Dict - from .aas import * -from .security import * from .base import * from .submodel import * from .provider import * -from .concept import ConceptDescription, ConceptDictionary, IEC61360ConceptDescription +from .concept import ConceptDescription from . import datatypes -# A mapping of BaSyx Python SDK implementation classes to the corresponding `KeyElements` enum members for all classes +# A mapping of BaSyx Python SDK implementation classes to the corresponding `KeyTypes` enum members for all classes # that are covered by this enum. -KEY_ELEMENTS_CLASSES: Dict[Type[Referable], KeyElements] = { - Asset: KeyElements.ASSET, - AssetAdministrationShell: KeyElements.ASSET_ADMINISTRATION_SHELL, - ConceptDescription: KeyElements.CONCEPT_DESCRIPTION, - Submodel: KeyElements.SUBMODEL, - View: KeyElements.VIEW, - ConceptDictionary: KeyElements.CONCEPT_DICTIONARY, - Entity: KeyElements.ENTITY, - BasicEvent: KeyElements.BASIC_EVENT, - Event: KeyElements.EVENT, # type: ignore - Blob: KeyElements.BLOB, - File: KeyElements.FILE, - Operation: KeyElements.OPERATION, - Capability: KeyElements.CAPABILITY, - Property: KeyElements.PROPERTY, - MultiLanguageProperty: KeyElements.MULTI_LANGUAGE_PROPERTY, - Range: KeyElements.RANGE, - ReferenceElement: KeyElements.REFERENCE_ELEMENT, - DataElement: KeyElements.DATA_ELEMENT, # type: ignore - SubmodelElementCollection: KeyElements.SUBMODEL_ELEMENT_COLLECTION, # type: ignore - AnnotatedRelationshipElement: KeyElements.ANNOTATED_RELATIONSHIP_ELEMENT, - RelationshipElement: KeyElements.RELATIONSHIP_ELEMENT, - SubmodelElement: KeyElements.SUBMODEL_ELEMENT, # type: ignore +KEY_TYPES_CLASSES: Dict[Type[Referable], KeyTypes] = { + AssetAdministrationShell: KeyTypes.ASSET_ADMINISTRATION_SHELL, + ConceptDescription: KeyTypes.CONCEPT_DESCRIPTION, + Submodel: KeyTypes.SUBMODEL, + Entity: KeyTypes.ENTITY, + BasicEventElement: KeyTypes.BASIC_EVENT_ELEMENT, + EventElement: KeyTypes.EVENT_ELEMENT, # type: ignore + Blob: KeyTypes.BLOB, + File: KeyTypes.FILE, + Operation: KeyTypes.OPERATION, + Capability: KeyTypes.CAPABILITY, + Property: KeyTypes.PROPERTY, + MultiLanguageProperty: KeyTypes.MULTI_LANGUAGE_PROPERTY, + Range: KeyTypes.RANGE, + ReferenceElement: KeyTypes.REFERENCE_ELEMENT, + DataElement: KeyTypes.DATA_ELEMENT, # type: ignore + SubmodelElementCollection: KeyTypes.SUBMODEL_ELEMENT_COLLECTION, + SubmodelElementList: KeyTypes.SUBMODEL_ELEMENT_LIST, + AnnotatedRelationshipElement: KeyTypes.ANNOTATED_RELATIONSHIP_ELEMENT, + RelationshipElement: KeyTypes.RELATIONSHIP_ELEMENT, + SubmodelElement: KeyTypes.SUBMODEL_ELEMENT, # type: ignore } diff --git a/basyx/aas/model/_string_constraints.py b/basyx/aas/model/_string_constraints.py new file mode 100644 index 000000000..d471201f4 --- /dev/null +++ b/basyx/aas/model/_string_constraints.py @@ -0,0 +1,182 @@ +# Copyright (c) 2023 the Eclipse BaSyx Authors +# +# This program and the accompanying materials are made available under the terms of the MIT License, available in +# the LICENSE file of this project. +# +# SPDX-License-Identifier: MIT +""" +This module implements constraint functions for the listed constrained string types and is meant for internal use only. +All types are constrained in length (min and max), RevisionType and VersionType are additionally constrained +by a regular expression. The following types aliased in the base module are constrained: +- ContentType +- Identifier +- LabelType +- MessageTopicType +- NameType +- PathType +- RevisionType +- ShortNameType +- QualifierType +- VersionType +""" + +import re + +from typing import Callable, Optional, Type, TypeVar + + +_T = TypeVar("_T") +AASD130_RE = re.compile("[\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]*") + + +def _unicode_escape(value: str) -> str: + """ + Escapes unicode characters such as \uD7FF, that may be used in regular expressions, for better error messages. + """ + return value.encode("unicode_escape").decode("utf-8") + + +# Functions to verify the constraints for a given value. +def check(value: str, type_name: str, min_length: int = 0, max_length: Optional[int] = None, + pattern: Optional[re.Pattern] = None) -> None: + if len(value) < min_length: + raise ValueError(f"{type_name} has a minimum length of {min_length}! (length: {len(value)})") + if max_length is not None and len(value) > max_length: + raise ValueError(f"{type_name} has a maximum length of {max_length}! (length: {len(value)})") + if pattern is not None and not pattern.fullmatch(value): + raise ValueError(f"{type_name} must match the pattern '{_unicode_escape(pattern.pattern)}'! " + f"(value: '{_unicode_escape(value)}')") + # Constraint AASd-130: an attribute with data type "string" shall consist of these characters only: + if not AASD130_RE.fullmatch(value): + # It's easier to implement this as a ValueError, because otherwise AASConstraintViolation would need to be + # imported from `base` and the ConstrainedLangStringSet would need to except AASConstraintViolation errors + # as well, while only re-raising ValueErrors. Thus, even if an AASConstraintViolation would be raised here, + # in case of a ConstrainedLangStringSet it would be re-raised as a ValueError anyway. + raise ValueError(f"Every string must match the pattern '{_unicode_escape(AASD130_RE.pattern)}'! " + f"(value: '{_unicode_escape(value)}')") + + +def check_content_type(value: str, type_name: str = "ContentType") -> None: + return check(value, type_name, 1, 100) + + +def check_identifier(value: str, type_name: str = "Identifier") -> None: + return check(value, type_name, 1, 2000) + + +def check_label_type(value: str, type_name: str = "LabelType") -> None: + return check(value, type_name, 1, 64) + + +def check_message_topic_type(value: str, type_name: str = "MessageTopicType") -> None: + return check(value, type_name, 1, 255) + + +def check_name_type(value: str, type_name: str = "NameType") -> None: + return check(value, type_name, 1, 128) + + +def check_path_type(value: str, type_name: str = "PathType") -> None: + return check_identifier(value, type_name) + + +def check_qualifier_type(value: str, type_name: str = "QualifierType") -> None: + return check_name_type(value, type_name) + + +def check_revision_type(value: str, type_name: str = "RevisionType") -> None: + return check(value, type_name, 1, 4, re.compile(r"([0-9]|[1-9][0-9]*)")) + + +def check_short_name_type(value: str, type_name: str = "ShortNameType") -> None: + return check(value, type_name, 1, 64) + + +def check_value_type_iec61360(value: str, type_name: str = "ValueTypeIEC61360") -> None: + return check(value, type_name, 1, 2000) + + +def check_version_type(value: str, type_name: str = "VersionType") -> None: + return check(value, type_name, 1, 4, re.compile(r"([0-9]|[1-9][0-9]*)")) + + +def create_check_function(min_length: int = 0, max_length: Optional[int] = None, pattern: Optional[re.Pattern] = None) \ + -> Callable[[str, str], None]: + """ + Returns a new `check_type` function with mandatory `type_name` for the given min_length, max_length and pattern + constraints. + + This is the type-independent alternative to :func:`~.check_content_type`, :func:`~.check_identifier`, etc. + It is used for the definition of the :class:`ConstrainedLangStringSets `, + as a "Basic" constrained string type only exists for :class:`~aas.model.base.MultiLanguageNameType`, where all + values are :class:`ShortNames `. All other + :class:`:class:`ConstrainedLangStringSets ` use custom constraints. + """ + def check_fn(value: str, type_name: str) -> None: + return check(value, type_name, min_length, max_length, pattern) + return check_fn + + +# Decorator functions to add getter/setter to classes for verification, whenever a value is updated. +def constrain_attr(pub_attr_name: str, constraint_check_fn: Callable[[str], None]) \ + -> Callable[[Type[_T]], Type[_T]]: + def decorator_fn(decorated_class: Type[_T]) -> Type[_T]: + def _getter(self) -> Optional[str]: + return getattr(self, "_" + pub_attr_name) + + def _setter(self, value: Optional[str]) -> None: + # if value is None, skip checks. incorrect 'None' assignments are caught by the type checker anyway + if value is not None: + constraint_check_fn(value) + setattr(self, "_" + pub_attr_name, value) + + if hasattr(decorated_class, pub_attr_name): + raise AttributeError(f"{decorated_class.__name__} already has an attribute named '{pub_attr_name}'") + setattr(decorated_class, pub_attr_name, property(_getter, _setter)) + return decorated_class + + return decorator_fn + + +def constrain_content_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_content_type) + + +def constrain_identifier(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_identifier) + + +def constrain_label_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_label_type) + + +def constrain_message_topic_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_message_topic_type) + + +def constrain_name_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_name_type) + + +def constrain_path_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_path_type) + + +def constrain_qualifier_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_qualifier_type) + + +def constrain_revision_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_revision_type) + + +def constrain_short_name_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_short_name_type) + + +def constrain_version_type(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_version_type) + + +def constrain_value_type_iec61360(pub_attr_name: str) -> Callable[[Type[_T]], Type[_T]]: + return constrain_attr(pub_attr_name, check_value_type_iec61360) diff --git a/basyx/aas/model/aas.py b/basyx/aas/model/aas.py index 380eba08b..9edf891ea 100644 --- a/basyx/aas/model/aas.py +++ b/basyx/aas/model/aas.py @@ -6,163 +6,170 @@ # SPDX-License-Identifier: MIT """ The main module of the AAS meta-model. It is used to define the class structures of high level elements such as -:class:`~.AssetAdministrationShell` and :class:`~.Asset`. +AssetAdministrationShell. This module contains the following classes from an up-to-down-level: - - :class:`~.AssetAdministrationShell` - - :class:`~.Asset` - - :class:`~.View` + - :class:`~.AssetInformation` """ -from typing import Optional, Set, Iterable, TYPE_CHECKING +from typing import Optional, Set, Iterable, List -from . import base, concept -from .security import Security +from . import base, _string_constraints from .submodel import Submodel -class View(base.Referable, base.HasSemantics): - """ - A view is a collection of referable elements w.r.t. to a specific viewpoint of one or more stakeholders. - - todo: what does this exactly? - - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar contained_element: Unordered list of :class:`References ` to elements of class - :class:`~aas.model.base.Referable` - :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) - :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next :class:`~aas.model.base.Referable` parent element of - the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar semantic_id: :class:`~aas.model.base.Identifier` of the semantic definition of the element. It is called - semantic id of the element. The semantic id may either reference an external global id or it may reference a - :class:`~aas.model.base.Referable` model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - """ - def __init__(self, - id_short: str, - contained_element: Optional[Set[base.AASReference]] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, - semantic_id: Optional[base.Reference] = None): - """ - TODO: Add instruction what to do after construction - """ - super().__init__() - self.id_short = id_short - self.contained_element: Set[base.AASReference] = set() if contained_element is None else contained_element - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent - self.semantic_id: Optional[base.Reference] = semantic_id - - -class Asset(base.Identifiable): +@_string_constraints.constrain_identifier("asset_type") +class AssetInformation: """ - An Asset describes meta data of an asset that is represented by an AAS - - The asset may either represent an asset type or an asset instance. The asset has a globally unique - :class:`~aas.model.base.Identifier` plus – if needed – additional domain specific (proprietary) identifiers. - - :ivar kind: Denotes whether the Asset is of kind "Type" or "Instance". - :ivar ~.identification: The globally unique identification of the element. - (inherited from :class:`~aas.model.base.Identifiable`) - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) - :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next :class:`~aas.model.base.Referable` parent element of - the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar administration: Administrative information of an :class:`~aas.model.base.Identifiable` element. - (inherited from :class:`~aas.model.base.Identifiable`) - :ivar asset_identification_model: A :class:`~aas.model.base.AASReference` to a :class:`~aas.model.submodel.Submodel` - that defines the handling of additional domain - specific (proprietary) Identifiers for the asset like e.g. serial number etc - :ivar bill_of_material: Bill of material of the asset represented by a :class:`~aas.model.submodel.Submodel` of the - same AAS. This submodel - contains a set of entities describing the material used to compose the composite I4.0 - Component. + In AssetInformation identifying meta data of the asset that is represented by an AAS is defined. + + The asset may either represent an asset type or an asset instance. + The asset has a globally unique identifier plus – if needed – additional domain specific (proprietary) + identifiers. However, to support the corner case of very first phase of lifecycle where a stabilised/constant + global asset identifier does not already exist, the corresponding attribute “globalAssetId” is optional. + + *Constraint AASd-131*: The globalAssetId or at least one specificAssetId shall be defined for AssetInformation. + + :ivar asset_kind: Denotes whether the Asset is of :class:`~aas.model.base.AssetKind` "TYPE" or "INSTANCE". + Default is "INSTANCE". + :ivar global_asset_id: :class:`~aas.model.base.Identifier` modelling the identifier of the asset the AAS is + representing. + This attribute is required as soon as the AAS is exchanged via partners in the + life cycle of the asset. In a first phase of the life cycle the asset might not yet have a + global id but already an internal identifier. The internal identifier would be modelled via + :attr:`~.specificAssetId`. + :ivar specific_asset_id: Additional domain specific, typically proprietary Identifier (Set of + :class:`SpecificAssetIds ` for the asset like + e.g. serial number etc. + :ivar asset_type: In case AssetInformation/assetKind is applicable the AssetInformation/assetType is the asset ID + of the type asset of the asset under consideration as identified by + AssetInformation/globalAssetId. + *Note:* In case AssetInformation/assetKind is "Instance" then the AssetInformation/assetType + denotes which "Type" the asset is of. But it is also possible to have + an AssetInformation/assetType of an asset of kind "Type". + :ivar default_thumbnail: Thumbnail of the asset represented by the asset administration shell. Used as default. """ def __init__(self, - kind: base.AssetKind, - identification: base.Identifier, - id_short: str = "", - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, - administration: Optional[base.AdministrativeInformation] = None, - asset_identification_model: Optional[base.AASReference[Submodel]] = None, - bill_of_material: Optional[base.AASReference[Submodel]] = None): - super().__init__() - self.kind: base.AssetKind = kind - self.identification: base.Identifier = identification - self.id_short = id_short - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent - self.administration: Optional[base.AdministrativeInformation] = administration - self.asset_identification_model: Optional[base.AASReference[Submodel]] = asset_identification_model - self.bill_of_material: Optional[base.AASReference[Submodel]] = bill_of_material + asset_kind: base.AssetKind = base.AssetKind.INSTANCE, + global_asset_id: Optional[base.Identifier] = None, + specific_asset_id: Iterable[base.SpecificAssetId] = (), + asset_type: Optional[base.Identifier] = None, + default_thumbnail: Optional[base.Resource] = None): - -class AssetAdministrationShell(base.Identifiable, base.Namespace): + super().__init__() + self.asset_kind: base.AssetKind = asset_kind + self.asset_type: Optional[base.Identifier] = asset_type + self.default_thumbnail: Optional[base.Resource] = default_thumbnail + # assign private attributes, bypassing setters, as constraints will be checked below + self._specific_asset_id: base.ConstrainedList[base.SpecificAssetId] = base.ConstrainedList( + specific_asset_id, + item_set_hook=self._check_constraint_set_spec_asset_id, + item_del_hook=self._check_constraint_del_spec_asset_id + ) + self._global_asset_id: Optional[base.Identifier] = global_asset_id + self._validate_global_asset_id(global_asset_id) + self._validate_aasd_131(global_asset_id, bool(specific_asset_id)) + + @property + def global_asset_id(self) -> Optional[base.Identifier]: + return self._global_asset_id + + @global_asset_id.setter + def global_asset_id(self, global_asset_id: Optional[base.Identifier]) -> None: + self._validate_global_asset_id(global_asset_id) + self._validate_aasd_131(global_asset_id, bool(self.specific_asset_id)) + self._global_asset_id = global_asset_id + + @property + def specific_asset_id(self) -> base.ConstrainedList[base.SpecificAssetId]: + return self._specific_asset_id + + @specific_asset_id.setter + def specific_asset_id(self, specific_asset_id: Iterable[base.SpecificAssetId]) -> None: + # constraints are checked via _check_constraint_set_spec_asset_id() in this case + self._specific_asset_id[:] = specific_asset_id + + def _check_constraint_set_spec_asset_id(self, items_to_replace: List[base.SpecificAssetId], + new_items: List[base.SpecificAssetId], + old_list: List[base.SpecificAssetId]) -> None: + self._validate_aasd_131(self.global_asset_id, + len(old_list) - len(items_to_replace) + len(new_items) > 0) + + def _check_constraint_del_spec_asset_id(self, _item_to_del: base.SpecificAssetId, + old_list: List[base.SpecificAssetId]) -> None: + self._validate_aasd_131(self.global_asset_id, len(old_list) > 1) + + @staticmethod + def _validate_global_asset_id(global_asset_id: Optional[base.Identifier]) -> None: + if global_asset_id is not None: + _string_constraints.check_identifier(global_asset_id) + + @staticmethod + def _validate_aasd_131(global_asset_id: Optional[base.Identifier], specific_asset_id_nonempty: bool) -> None: + if global_asset_id is None and not specific_asset_id_nonempty: + raise base.AASConstraintViolation(131, + "An AssetInformation has to have a globalAssetId or a specificAssetId") + if global_asset_id is not None: + _string_constraints.check_identifier(global_asset_id) + + def __repr__(self) -> str: + return "AssetInformation(assetKind={}, globalAssetId={}, specificAssetId={}, assetType={}, " \ + "defaultThumbnail={})".format(self.asset_kind, self._global_asset_id, str(self.specific_asset_id), + self.asset_type, str(self.default_thumbnail)) + + +class AssetAdministrationShell(base.Identifiable, base.UniqueIdShortNamespace, base.HasDataSpecification): """ An Asset Administration Shell - :ivar asset: :class:`~aas.model.base.Reference` to the :class:`~.Asset` the AAS is representing. - :ivar ~.identification: The globally unique identification of the element. - (inherited from :class:`~aas.model.base.Identifiable`) - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar asset_information: :class:`~.AssetInformation` of the asset this AssetAdministrationShell is representing + :ivar ~.id: The globally unique id (:class:`~aas.model.base.Identifier`) of the element. + (inherited from :class:`~aas.model.base.Identifiable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next :class:`~aas.model.base.Referable` parent element of - the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar administration: Administrative information of an :class:`~aas.model.base.Identifiable` element. - (inherited from :class:`~aas.model.base.Identifiable`) - :ivar ~.security: Definition of the security relevant aspects of the AAS. - :ivar ~.submodel: Unordered list of :class:`AASReferences ` to - :class:`Submodels ` to describe typically the asset of an AAS. - :ivar concept_dictionary: Unordered list of :class:`ConceptDictionaries `. - The concept dictionaries typically contain only - descriptions for elements that are also used within the AAS - :ivar view: Unordered list of stakeholder specific :class:`Views <~.View>` that can group the elements of the AAS. - :ivar derived_from: The :class:`~aas.model.base.AASReference` to the AAS the AAs was derived from + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) + :ivar administration: :class:`~aas.model.base.AdministrativeInformation` of an + :class:`~.aas.model.base.Identifiable` element. (inherited from + :class:`~aas.model.base.Identifiable`) + :ivar ~.submodel: Unordered list of :class:`submodels ` to describe typically the asset + of an AAS. (Initialization-parameter: `submodel_`) + :ivar derived_from: The :class:`reference ` to the AAS the AAs was derived from + :ivar embedded_data_specifications: List of Embedded data specification. + :ivar extension: An extension of the element. + (from :class:`~aas.model.base.HasExtensions`) """ def __init__(self, - asset: base.AASReference[Asset], - identification: base.Identifier, - id_short: str = "", - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + asset_information: AssetInformation, + id_: base.Identifier, + id_short: Optional[base.NameType] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, administration: Optional[base.AdministrativeInformation] = None, - security: Optional[Security] = None, - submodel: Optional[Set[base.AASReference[Submodel]]] = None, - concept_dictionary: Iterable[concept.ConceptDictionary] = (), - view: Iterable[View] = (), - derived_from: Optional[base.AASReference["AssetAdministrationShell"]] = None): + submodel: Optional[Set[base.ModelReference[Submodel]]] = None, + derived_from: Optional[base.ModelReference["AssetAdministrationShell"]] = None, + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] + = (), + extension: Iterable[base.Extension] = ()): super().__init__() - self.identification: base.Identifier = identification + self.id: base.Identifier = id_ + self.asset_information: AssetInformation = asset_information self.id_short = id_short - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent + self.display_name: Optional[base.MultiLanguageNameType] = display_name + self.category = category + self.description: Optional[base.MultiLanguageTextType] = description + self.parent: Optional[base.UniqueIdShortNamespace] = parent self.administration: Optional[base.AdministrativeInformation] = administration - self.derived_from: Optional[base.AASReference[AssetAdministrationShell]] = derived_from - self.security: Optional[Security] = security - self.asset: base.AASReference[Asset] = asset - self.submodel: Set[base.AASReference[Submodel]] = set() if submodel is None else submodel - self.concept_dictionary: base.NamespaceSet[concept.ConceptDictionary] = \ - base.NamespaceSet(self, concept_dictionary) - self.view: base.NamespaceSet[View] = base.NamespaceSet(self, view) + self.derived_from: Optional[base.ModelReference["AssetAdministrationShell"]] = derived_from + self.submodel: Set[base.ModelReference[Submodel]] = set() if submodel is None else submodel + self.embedded_data_specifications: List[base.EmbeddedDataSpecification] = list(embedded_data_specifications) + self.extension = base.NamespaceSet(self, [("name", True)], extension) diff --git a/basyx/aas/model/base.py b/basyx/aas/model/base.py index 70e32fe9c..dc3079625 100644 --- a/basyx/aas/model/base.py +++ b/basyx/aas/model/base.py @@ -5,7 +5,7 @@ # # SPDX-License-Identifier: MIT """ -This module implements the basic structures of the AAS metamodel, including the abstract classes and enums needed for +This module implements the basic structures of the AAS meta-model, including the abstract classes and enums needed for the higher level classes to inherit from. """ @@ -14,104 +14,101 @@ import itertools from enum import Enum, unique from typing import List, Optional, Set, TypeVar, MutableSet, Generic, Iterable, Dict, Iterator, Union, overload, \ - MutableSequence, Type, Any, TYPE_CHECKING, Tuple + MutableSequence, Type, Any, TYPE_CHECKING, Tuple, Callable, MutableMapping import re -from . import datatypes +from . import datatypes, _string_constraints from ..backend import backends if TYPE_CHECKING: from . import provider -DataTypeDef = Type[datatypes.AnyXSDType] +DataTypeDefXsd = Type[datatypes.AnyXSDType] ValueDataType = datatypes.AnyXSDType # any xsd atomic type (from .datatypes) +ValueList = Set["ValueReferencePair"] BlobType = bytes -MimeType = str # any mimetype as in RFC2046 + +# The following string aliases are constrained by the decorator functions defined in the string_constraints module, +# wherever they are used for a instance attributes. +ContentType = str # any mimetype as in RFC2046 +Identifier = str +LabelType = str +MessageTopicType = str +NameType = str PathType = str QualifierType = str -# A dict of language-Identifier (according to ISO 639-1 and ISO 3166-1) and string in this language. -# The meaning of the string in each language is the same. -# << Data Type >> Example ["en-US", "germany"] -LangStringSet = Dict[str, str] - - -@unique -class IdentifierType(Enum): - """ - Enumeration of different types of Identifiers for global identification - - :cvar IRDI: IRDI (International Registration Data Identifier) according to ISO29002-5 as an Identifier scheme for - properties and classifications. - :cvar IRI: IRI according to Rfc 3987. Every URI is an IRI - :cvar CUSTOM: Custom identifiers like GUIDs (globally unique Identifiers) - """ - - IRDI = 0 - IRI = 1 - CUSTOM = 2 +RevisionType = str +ShortNameType = str +VersionType = str +ValueTypeIEC61360 = str @unique -class KeyElements(Enum): +class KeyTypes(Enum): """ Enumeration for denoting which kind of entity is referenced. They can be categorized in ReferableElements, - IdentifiableElements and other KeyElements + IdentifiableElements and other KeyTypes **IdentifiableElements starting from 0** - :cvar ASSET: :class:`~aas.model.aas.Asset` :cvar ASSET_ADMINISTRATION_SHELL: :class:`~aas.model.aas.AssetAdministrationShell` :cvar CONCEPT_DESCRIPTION: :class:`~aas.model.concept.ConceptDescription` :cvar SUBMODEL: :class:`~aas.model.submodel.Submodel` **ReferableElements starting from 1000** - :cvar ACCESS_PERMISSION_RULE: access permission rule + *Note:* DataElement is abstract, i. e. if a key uses :attr:`~.KeyTypes.DATA_ELEMENT` the reference may be + :class:`~aas.model.submodel.Property`, :class:`~aas.model.submodel.File` etc. + + *Note:* SubmodelElement is abstract, i.e. if a key uses :attr:`~.KeyTypes.SUBMODEL_ELEMENT` + the reference may be a :class:`~aas.model.submodel.Property`, a + :class:`~aas.model.submodel.SubmodelElementCollection`, an :class:`~aas.model.submodel.Operation` etc. + :cvar ANNOTATED_RELATIONSHIP_ELEMENT: :class:`~aas.model.submodel.AnnotatedRelationshipElement` - :cvar BASIC_EVENT: :class:`~aas.model.submodel.BasicEvent` + :cvar BASIC_EVENT_ELEMENT: :class:`~aas.model.submodel.BasicEventElement` :cvar BLOB: :class:`~aas.model.submodel.Blob` :cvar CAPABILITY: :class:`~aas.model.submodel.Capability` - :cvar CONCEPT_DICTIONARY: :class:`~aas.model.concept.ConceptDictionary` - :cvar DATA_ELEMENT: :class:`~aas.model.submodel.DataElement` *Note:* Date Element is abstract, i. e. if a key uses - "DATA_ELEMENT" the reference may be Property, File etc. + :cvar DATA_ELEMENT: :class:`~aas.model.submodel.DataElement` :cvar ENTITY: :class:`~aas.model.submodel.Entity` - :cvar EVENT: :class:`~aas.model.submodel.Event`, *Note:* Event is abstract + :cvar EVENT_ELEMENT: :class:`~aas.model.submodel.EventElement`, Note: EventElement is abstract :cvar FILE: :class:`~aas.model.submodel.File` - :cvar MULTI_LANGUAGE_PROPERTY: property with a value that can be provided in multiple languages + :cvar MULTI_LANGUAGE_PROPERTY: :class:`~aas.model.submodel.MultiLanguageProperty` property with a value that can be + provided in multiple languages :cvar OPERATION: :class:`~aas.model.submodel.Operation` :cvar PROPERTY: :class:`~aas.model.submodel.Property` :cvar RANGE: :class:`~aas.model.submodel.Range` with min and max - :cvar REFERENCE_ELEMENT: :class:`aas.model.submodel.ReferenceElement` + :cvar REFERENCE_ELEMENT: :class:`~aas.model.submodel.ReferenceElement` :cvar RELATIONSHIP_ELEMENT: :class:`~aas.model.submodel.RelationshipElement` - :cvar SUBMODEL_ELEMENT: :class:`~aas.model.submodel.SubmodelElement`, Note: Submodel Element is abstract, - i.e. if a key uses “SUBMODEL_ELEMENT” the reference may be a :class:`~aas.model.submodel.Property`, a - :class:`~aas.model.submodel.SubmodelElementCollection`, an :class:`~aas.model.submodel.Operation` etc. + :cvar SUBMODEL_ELEMENT: :class:`~aas.model.submodel.SubmodelElement` :cvar SUBMODEL_ELEMENT_COLLECTION: :class:`~aas.model.submodel.SubmodelElementCollection` - :cvar VIEW: :class:`~aas.model.aas.View` + :cvar SUBMODEL_ELEMENT_LIST: :class:`~aas.model.submodel.SubmodelElementList` - **KeyElements starting from 2000** + **KeyTypes starting from 2000** :cvar GLOBAL_REFERENCE: reference to an element not belonging to an asset administration shell :cvar FRAGMENT_REFERENCE: unique reference to an element within a file. The file itself is assumed to be part of an - asset administration shell. + asset administration shell. """ - # IdentifiableElements starting from 0 - ASSET = 0 + # AasIdentifiables starting from 0 + # keep _ASSET = 0 as a protected enum member here, so 0 isn't reused by a future key type + _ASSET = 0 ASSET_ADMINISTRATION_SHELL = 1 CONCEPT_DESCRIPTION = 2 SUBMODEL = 3 - # ReferableElements starting from 1000 - ACCESS_PERMISSION_RULE = 1000 + # AasSubmodelElements starting from 1000 + # keep _ACCESS_PERMISSION_RULE = 1000 as a protected enum member here, so 1000 isn't reused by a future key type + _ACCESS_PERMISSION_RULE = 1000 ANNOTATED_RELATIONSHIP_ELEMENT = 1001 - BASIC_EVENT = 1002 + BASIC_EVENT_ELEMENT = 1002 BLOB = 1003 CAPABILITY = 1004 - CONCEPT_DICTIONARY = 1005 + # keep _CONCEPT_DICTIONARY = 1005 as a protected enum member here, so 1005 isn't reused by a future key type + _CONCEPT_DICTIONARY = 1005 DATA_ELEMENT = 1006 ENTITY = 1007 - EVENT = 1008 + EVENT_ELEMENT = 1008 FILE = 1009 MULTI_LANGUAGE_PROPERTY = 1010 OPERATION = 1011 @@ -121,35 +118,59 @@ class KeyElements(Enum): RELATIONSHIP_ELEMENT = 1015 SUBMODEL_ELEMENT = 1016 SUBMODEL_ELEMENT_COLLECTION = 1017 - VIEW = 1018 + # keep _VIEW = 1018 as a protected enum member here, so 1018 isn't reused by a future key type + _VIEW = 1018 + SUBMODEL_ELEMENT_LIST = 1019 - # KeyElements starting from 2000 + # GenericFragmentKeys and GenericGloballyIdentifiables starting from 2000 GLOBAL_REFERENCE = 2000 FRAGMENT_REFERENCE = 2001 + @property + def is_aas_identifiable(self) -> bool: + return self in (self.ASSET_ADMINISTRATION_SHELL, self.CONCEPT_DESCRIPTION, self.SUBMODEL) -@unique -class KeyType(Enum): - """ - Enumeration for denoting the type of the key value. + @property + def is_generic_globally_identifiable(self) -> bool: + return self == self.GLOBAL_REFERENCE - :cvar IRDI: IRDI (International Registration Data Identifier) according to ISO29002-5 as an Identifier scheme for - properties and classifications. - :cvar IRI: IRI according to Rfc 3987. Every URI is an IRI - :cvar CUSTOM: Custom identifiers like GUIDs (globally unique Identifiers) - :cvar IDSHORT: id_short of a referable element - :cvar FRAGMENT_ID: identifier of a fragment within a file - """ + @property + def is_generic_fragment_key(self) -> bool: + return self == self.FRAGMENT_REFERENCE - IRDI = 0 - IRI = 1 - CUSTOM = 2 - IDSHORT = 3 - FRAGMENT_ID = 4 + @property + def is_aas_submodel_element(self) -> bool: + return self in ( + self.ANNOTATED_RELATIONSHIP_ELEMENT, + self.BASIC_EVENT_ELEMENT, + self.BLOB, + self.CAPABILITY, + self.DATA_ELEMENT, + self.ENTITY, + self.EVENT_ELEMENT, + self.FILE, + self.MULTI_LANGUAGE_PROPERTY, + self.OPERATION, + self.PROPERTY, + self.RANGE, + self.REFERENCE_ELEMENT, + self.RELATIONSHIP_ELEMENT, + self.SUBMODEL_ELEMENT, + self.SUBMODEL_ELEMENT_COLLECTION, + self.SUBMODEL_ELEMENT_LIST + ) + + @property + def is_aas_referable_non_identifiable(self) -> bool: + return self.is_aas_submodel_element + + @property + def is_fragment_key_element(self) -> bool: + return self.is_aas_referable_non_identifiable or self.is_generic_fragment_key @property - def is_local_key_type(self) -> bool: - return self in (KeyType.IDSHORT, KeyType.FRAGMENT_ID) + def is_globally_identifiable(self) -> bool: + return self.is_aas_identifiable or self.is_generic_globally_identifiable @unique @@ -157,11 +178,12 @@ class EntityType(Enum): """ Enumeration for denoting whether an entity is a self-managed or a co-managed entity - :cvar CO_MANAGED_ENTITY: For co-managed entities there is no separate AAS. Co-managed entities need to be part of a - self-managed entity - :cvar SELF_MANAGED_ENTITY: Self-managed entities have their own AAS but can be part of the bill of material of a - composite self-managed entity. The asset of an I4.0-component is a self-managed entity - per definition. + :cvar CO_MANAGED_ENTITY: For co-managed entities there is no separate + :class:`AAS `. Co-managed entities need to be part + of a self-managed entity + :cvar SELF_MANAGED_ENTITY: Self-managed entities have their own + :class:`AAS `, but can be part of the bill of + material of a composite self-managed entity. """ CO_MANAGED_ENTITY = 0 @@ -169,15 +191,19 @@ class EntityType(Enum): @unique -class ModelingKind(Enum): +class ModellingKind(Enum): """ Enumeration for denoting whether an element is a type or an instance. + *Note:* An :attr:`~.ModellingKind.INSTANCE` becomes an individual entity of a template, for example a device model, + by defining specific property values. + + *Note:* In an object-oriented view, an instance denotes an object of a template (class). :cvar TEMPLATE: Software element which specifies the common attributes shared by all instances of the template :cvar INSTANCE: concrete, clearly identifiable component of a certain template. *Note:* It becomes an individual entity of a template, for example a device model, by defining specific property values. - *Note:* In an object oriented view, an instance denotes an object of a template (class). + *Note:* In an object-oriented view, an instance denotes an object of a template (class). """ TEMPLATE = 0 @@ -187,210 +213,385 @@ class ModelingKind(Enum): @unique class AssetKind(Enum): """ - Enumeration for denoting whether an element is a type or an instance. + Enumeration for denoting whether an asset is a type asset or an instance asset or whether this kind of + classification is not applicable. + *Note:* :attr:`~.AssetKind.INSTANCE` becomes an individual entity of a type, for example a device, by defining + specific property values. + + *Note:* In an object oriented view, an instance denotes an object of a class (of a type) - :cvar TYPE: hardware or software element which specifies the common attributes shared by all instances of the type - :cvar INSTANCE: concrete, clearly identifiable component of a certain type, - *Note:* It becomes an individual entity of a type, for example a device, by defining specific - property values. - *Note:* In an object oriented view, an instance denotes an object of a class (of a type) + :cvar TYPE: Type asset + :cvar INSTANCE: Instance asset + :cvar NOT_APPLICABLE: Neither a type asset nor an instance asset """ TYPE = 0 INSTANCE = 1 + NOT_APPLICABLE = 2 + + +class QualifierKind(Enum): + """ + Enumeration for denoting whether a Qualifier is a concept, template or value qualifier. + + :cvar CONCEPT_QUALIFIER: qualifies the semantic definition the element is referring to (HasSemantics/semanticId) + :cvar TEMPLATE_QUALIFIER: qualifies the elements within a specific submodel on concept level. Template qualifiers + are only applicable to elements with kind="Template" + :cvar VALUE_QUALIFIER: qualifies the value of the element and can change during run-time. Value qualifiers are only + applicable to elements with kind="Instance" + """ + + CONCEPT_QUALIFIER = 0 + TEMPLATE_QUALIFIER = 1 + VALUE_QUALIFIER = 2 + + +@unique +class Direction(Enum): + """ + Direction of an event. Used in :class:`aas.model.submodel.BasicEventElement`. + """ + + INPUT = 0 + OUTPUT = 1 + + +@unique +class StateOfEvent(Enum): + """ + State of an event. Used in :class:`aas.model.submodel.BasicEventElement`. + """ + + ON = 0 + OFF = 1 + + +class LangStringSet(MutableMapping[str, str]): + """ + A mapping of language code to string. Must be non-empty. + + langString is an RDF data type. A langString is a value tagged with a language code. RDF requires + IETF BCP 4723 language tags, i.e. simple two-letter language tags for Locales like “de” conformant to ISO 639-1 + are allowed as well as language tags plus extension like “de-DE” for country code, dialect etc. like in “en-US” or + “en-GB” for English (United Kingdom) and English (United States). IETF language tags are referencing ISO 639, + ISO 3166 and ISO 15924. + """ + def __init__(self, dict_: Dict[str, str]): + self._dict: Dict[str, str] = {} + + if len(dict_) < 1: + raise ValueError(f"A {self.__class__.__name__} must not be empty!") + for ltag in dict_: + self._check_language_tag_constraints(ltag) + self._dict[ltag] = dict_[ltag] + + @classmethod + def _check_language_tag_constraints(cls, ltag: str): + split = ltag.split("-", 1) + lang_code = split[0] + if len(lang_code) != 2 or not lang_code.isalpha() or not lang_code.islower(): + raise ValueError(f"The language code of the language tag must consist of exactly two lower-case letters! " + f"Given language tag and language code: '{ltag}', '{lang_code}'") + + def __getitem__(self, item: str) -> str: + return self._dict[item] + + def __setitem__(self, key: str, value: str) -> None: + self._check_language_tag_constraints(key) + self._dict[key] = value + + def __delitem__(self, key: str) -> None: + if len(self._dict) == 1: + raise KeyError(f"A {self.__class__.__name__} must not be empty!") + del self._dict[key] + + def __iter__(self) -> Iterator[str]: + return iter(self._dict) + + def __len__(self) -> int: + return len(self._dict) + + def __repr__(self) -> str: + return self.__class__.__name__ + "(" + ", ".join(f'{k}="{v}"' for k, v in self.items()) + ")" + + def clear(self) -> None: + raise KeyError(f"A {self.__class__.__name__} must not be empty!") + + +class ConstrainedLangStringSet(LangStringSet, metaclass=abc.ABCMeta): + """ + A :class:`~.LangStringSet` with constrained values. + """ + @abc.abstractmethod + def __init__(self, dict_: Dict[str, str], constraint_check_fn: Callable[[str, str], None]): + super().__init__(dict_) + self._constraint_check_fn: Callable[[str, str], None] = constraint_check_fn + for ltag, text in self._dict.items(): + self._check_text_constraints(ltag, text) + + def _check_text_constraints(self, ltag: str, text: str) -> None: + try: + self._constraint_check_fn(text, self.__class__.__name__) + except ValueError as e: + raise ValueError(f"The text for the language tag '{ltag}' is invalid: {e}") from e + + def __setitem__(self, key: str, value: str) -> None: + self._check_text_constraints(key, value) + super().__setitem__(key, value) + + +class MultiLanguageNameType(ConstrainedLangStringSet): + """ + A :class:`~.ConstrainedLangStringSet` where each value is a :class:`~.ShortNameType`. + See also: :func:`~aas.model._string_constraints.check_short_name_type` + """ + def __init__(self, dict_: Dict[str, str]): + super().__init__(dict_, _string_constraints.check_short_name_type) + + +class MultiLanguageTextType(ConstrainedLangStringSet): + """ + A :class:`~.ConstrainedLangStringSet` where each value must have at least 1 and at most 1023 characters. + """ + def __init__(self, dict_: Dict[str, str]): + super().__init__(dict_, _string_constraints.create_check_function(min_length=1, max_length=1023)) + + +class DefinitionTypeIEC61360(ConstrainedLangStringSet): + """ + A :class:`~.ConstrainedLangStringSet` where each value must have at least 1 and at most 1023 characters. + """ + def __init__(self, dict_: Dict[str, str]): + super().__init__(dict_, _string_constraints.create_check_function(min_length=1, max_length=1023)) + + +class PreferredNameTypeIEC61360(ConstrainedLangStringSet): + """ + A :class:`~.ConstrainedLangStringSet` where each value must have at least 1 and at most 255 characters. + """ + def __init__(self, dict_: Dict[str, str]): + super().__init__(dict_, _string_constraints.create_check_function(min_length=1, max_length=255)) + + +class ShortNameTypeIEC61360(ConstrainedLangStringSet): + """ + A :class:`~.ConstrainedLangStringSet` where each value must have at least 1 and at most 18 characters. + """ + def __init__(self, dict_: Dict[str, str]): + super().__init__(dict_, _string_constraints.create_check_function(min_length=1, max_length=18)) class Key: """ A key is a reference to an element by its id. - :ivar type: Denote which kind of entity is referenced. In case type = GlobalReference then the element is a - global unique id. In all other cases the key references a model element of the same or of another AAS. - The name of the model element is explicitly listed. - :ivar local: Denotes if the key references a model element of the same AAS (=true) or not (=false). In case of - local = false the key may reference a model element of another AAS or an entity outside any AAS that - has a global unique id. - :ivar value: The key value, for example an IRDI if the idType=IRDI - :ivar id_type: Type of the key value. In case of idType = idShort local shall be true. In case type=GlobalReference - idType shall not be IdShort. + :ivar type_: Denote which kind of entity is referenced. In case type = :attr:`~.KeyTypes.GLOBAL_REFERENCE` then + the element is a global unique id. In all other cases the key references a model element of the same or + of another AAS. The name of the model element is explicitly listed. + :ivar value: The key value, for example an IRDI or IRI """ def __init__(self, - type_: KeyElements, - local: bool, - value: str, - id_type: KeyType): + type_: KeyTypes, + value: Identifier): """ TODO: Add instruction what to do after construction """ - self.type: KeyElements - self.local: bool - self.value: str - self.id_type: KeyType + _string_constraints.check_identifier(value) + self.type: KeyTypes + self.value: Identifier super().__setattr__('type', type_) - super().__setattr__('local', local) super().__setattr__('value', value) - super().__setattr__('id_type', id_type) def __setattr__(self, key, value): """Prevent modification of attributes.""" raise AttributeError('Reference is immutable') def __repr__(self) -> str: - return "Key(local={}, id_type={}, value={})".format(self.local, self.id_type.name, self.value) + return "Key(type={}, value={})".format(self.type.name, self.value) def __str__(self) -> str: - return "{}={}".format(self.id_type.name, self.value) + return self.value def __eq__(self, other: object) -> bool: if not isinstance(other, Key): return NotImplemented - return (self.id_type is other.id_type - and self.value == other.value - and self.local == other.local + return (self.value == other.value and self.type == other.type) def __hash__(self): - return hash((self.id_type, self.value, self.local, self.type)) + return hash((self.value, self.type)) def get_identifier(self) -> Optional["Identifier"]: """ - Get an :class:`~.Identifier` object corresponding to this key, if it is a global key. + Get an :class:`~.Identifier` object corresponding to this key, if it is an identifiable key. - :return: None if this is no global key, otherwise a corresponding :class:`~.Identifier` object + :return: None if this is no identifiable key, otherwise a corresponding :class:`~.Identifier` string. """ - if self.id_type.is_local_key_type: + if not self.type.is_aas_identifiable: return None - return Identifier(self.value, IdentifierType(self.id_type.value)) + return self.value @staticmethod def from_referable(referable: "Referable") -> "Key": """ Construct a key for a given :class:`~.Referable` (or :class:`~.Identifiable`) object + + :param referable: :class:`~.Referable` or :class:`~.Identifiable` object + :returns: :class:`~.Key` """ # Get the `type` by finding the first class from the base classes list (via inspect.getmro), that is contained # in KEY_ELEMENTS_CLASSES - from . import KEY_ELEMENTS_CLASSES + from . import KEY_TYPES_CLASSES, SubmodelElementList try: - key_type = next(iter(KEY_ELEMENTS_CLASSES[t] + key_type = next(iter(KEY_TYPES_CLASSES[t] for t in inspect.getmro(type(referable)) - if t in KEY_ELEMENTS_CLASSES)) + if t in KEY_TYPES_CLASSES)) except StopIteration: - key_type = KeyElements.PROPERTY + key_type = KeyTypes.PROPERTY - local = True # TODO if isinstance(referable, Identifiable): - return Key(key_type, local, referable.identification.id, - KeyType(referable.identification.id_type.value)) + return Key(key_type, referable.id) + elif isinstance(referable.parent, SubmodelElementList): + try: + return Key(key_type, str(referable.parent.value.index(referable))) # type: ignore + except ValueError as e: + raise ValueError(f"Object {referable!r} is not contained within its parent {referable.parent!r}") from e else: - return Key(key_type, local, referable.id_short, KeyType.IDSHORT) + if referable.id_short is None: + raise ValueError(f"Can't create Key for {referable!r} without an id_short!") + return Key(key_type, referable.id_short) + +_NSO = TypeVar('_NSO', bound=Union["Referable", "Qualifier", "HasSemantics", "Extension"]) -class AdministrativeInformation: + +class Namespace(metaclass=abc.ABCMeta): """ - Administrative meta-information for an element like version information. + Abstract baseclass for all objects which form a Namespace to hold objects and resolve them by their + specific attribute. - **Constraint AASd-005:** A revision requires a version. This means, if there is no version there is no revision - either + <> - :ivar version: Version of the element. - :ivar revision: Revision of the element. + :ivar namespace_element_sets: List of :class:`NamespaceSets ` """ + @abc.abstractmethod + def __init__(self) -> None: + super().__init__() + self.namespace_element_sets: List[NamespaceSet] = [] - def __init__(self, - version: Optional[str] = None, - revision: Optional[str] = None): + def _get_object(self, object_type: Type[_NSO], attribute_name: str, attribute) -> _NSO: """ - Initializer of AdministrativeInformation + Find an :class:`~._NSO` in this namespace by its attribute - :raises ValueError: If version is None and revision is not None + :raises KeyError: If no such :class:`~._NSO` can be found + """ + for ns_set in self.namespace_element_sets: + try: + return ns_set.get_object_by_attribute(attribute_name, attribute) + except KeyError: + continue + raise KeyError(f"{object_type.__name__} with {attribute_name} {attribute} not found in this namespace") - TODO: Add instruction what to do after construction + def _add_object(self, attribute_name: str, obj: _NSO) -> None: """ - if version is None and revision is not None: - raise ValueError("A revision requires a version. This means, if there is no version there is no revision " - "neither.") - self.version: Optional[str] = version - self._revision: Optional[str] = revision + Add an :class:`~._NSO` to this namespace by its attribute - def _get_revision(self): - return self._revision + :raises KeyError: If no such :class:`~._NSO` can be found + """ + for ns_set in self.namespace_element_sets: + if attribute_name not in ns_set.get_attribute_name_list(): + continue + ns_set.add(obj) + return + raise ValueError(f"{obj!r} can't be added to this namespace") - def _set_revision(self, revision: str): - if self.version is None: - raise ValueError("A revision requires a version. This means, if there is no version there is no revision " - "neither. Please set version first.") - else: - self._revision = revision + def _remove_object(self, object_type: type, attribute_name: str, attribute) -> None: + """ + Remove an :class:`~.NSO` from this namespace by its attribute - def __eq__(self, other) -> bool: - if not isinstance(other, AdministrativeInformation): - return NotImplemented - return self.version == other.version and self._revision == other._revision + :raises KeyError: If no such :class:`~.NSO` can be found + """ + for ns_set in self.namespace_element_sets: + if attribute_name in ns_set.get_attribute_name_list(): + try: + ns_set.remove_by_id(attribute_name, attribute) + return + except KeyError: + continue + raise KeyError(f"{object_type.__name__} with {attribute_name} {attribute} not found in this namespace") - def __repr__(self) -> str: - return "AdministrativeInformation(version={}, revision={})".format(self.version, self.revision) - revision = property(_get_revision, _set_revision) +class HasExtension(Namespace, metaclass=abc.ABCMeta): + """ + Abstract baseclass for all objects which form a Namespace to hold Extension objects and resolve them by their + name. + <> -class Identifier: - """ - Used to uniquely identify an entity by using an identifier. + *Constraint AASd-077:* The name of an extension within HasExtensions needs to be unique. + + TODO: This constraint is not yet implemented, a new Class for CustomSets should be implemented - :ivar id: Identifier of the element. Its type is defined in id_type. - :ivar id_type: :class:`~.IdentifierType`, e.g. URI, IRDI etc. + :ivar namespace_element_sets: List of :class:`NamespaceSets ` + :ivar extension: A :class:`~.NamespaceSet` of :class:`Extensions <.Extension>` of the element. + :ivar _MEMBER_OBJ_TYPE: :class:`_NSO ` + :ivar _ATTRIBUTE_NAME: Specific attribute name `. """ + @abc.abstractmethod + def __init__(self) -> None: + super().__init__() + self.namespace_element_sets: List[NamespaceSet] = [] + self.extension: NamespaceSet[Extension] - def __init__(self, - id_: str, - id_type: IdentifierType): + def get_extension_by_name(self, name: str) -> "Extension": """ - TODO: Add instruction what to do after construction + Find an :class:`~.Extension` in this namespace by its name + + :raises KeyError: If no such :class:`~.Extension` can be found """ - self.id: str - self.id_type: IdentifierType - super().__setattr__('id', id_) - super().__setattr__('id_type', id_type) + return super()._get_object(Extension, "name", name) - def __setattr__(self, key, value): - """Prevent modification of attributes.""" - raise AttributeError('Identifier are immutable') + def add_extension(self, extension: "Extension") -> None: + """ + Add a :class:`~.Extension` to this Namespace - def __hash__(self): - return hash((self.id_type, self.id)) + :param extension: The :class:`~.Extension` to add + :raises KeyError: If a :class:`~.Extension` with the same name is already present in this namespace + :raises ValueError: If the given :class:`~.Extension` already has a parent namespace + """ + return super()._add_object("name", extension) - def __eq__(self, other: object) -> bool: - if not isinstance(other, Identifier): - return NotImplemented - return self.id_type == other.id_type and self.id == other.id + def remove_extension_by_name(self, name: str) -> None: + """ + Remove an :class:`~.Extension` from this namespace by its name - def __repr__(self) -> str: - return "Identifier({}={})".format(self.id_type.name, self.id) + :raises KeyError: If no such :class:`~.Extension` can be found + """ + return super()._remove_object(HasExtension, "name", name) -class Referable(metaclass=abc.ABCMeta): +class Referable(HasExtension, metaclass=abc.ABCMeta): """ An element that is referable by its id_short. This id is not globally unique. This id is unique within the name space of the element. <> - **Constraint AASd-001:** In case of a referable element not being an identifiable element this id is - mandatory and used for referring to the element in its name space. + *Constraint AASd-001:* In case of a referable element not being an identifiable element the + idShort is mandatory and used for referring to the element in its name space. + *Constraint AASd-002:* idShort shall only feature letters, digits, underscore ("_"); starting + mandatory with a letter. + *Constraint AASd-004:* Add parent in case of non identifiable elements. + *Constraint AASd-022:* idShort of non-identifiable referables shall be unique in its namespace (case-sensitive) - **Constraint AASd-002:** idShort shall only feature letters, digits, underscore ("_"); starting - mandatory with a letter. - - **Constraint AASd-003:** idShort shall be matched case insensitive. - - **Constraint AASd-004:** Add parent in case of non identifiable elements. - - :ivar id_short: Identifying string of the element within its name space. - :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. + :ivar _id_short: Identifying string of the element within its name space + :ivar ~.category: The category is a value that gives further meta information w.r.t. to the class of the element. + It affects the expected existence of attributes and the applicability of constraints. :ivar description: Description or comments on the element. - :ivar parent: Reference to the next referable parent element of the element. + :ivar parent: Reference (in form of a :class:`~.UniqueIdShortNamespace`) to the next referable parent element + of the element. + :ivar source: Source of the object, an URI, that defines where this object's data originates from. This is used to specify where the Referable should be updated from and committed to. Default is an empty string, making it use the source of its ancestor, if possible. @@ -398,69 +599,107 @@ class Referable(metaclass=abc.ABCMeta): @abc.abstractmethod def __init__(self): super().__init__() - self._id_short: Optional[str] = "" - self.category: Optional[str] = "" - self.description: Optional[LangStringSet] = dict() + self._id_short: Optional[NameType] = None + self.display_name: Optional[MultiLanguageNameType] = dict() + self._category: Optional[NameType] = None + self.description: Optional[MultiLanguageTextType] = dict() # We use a Python reference to the parent Namespace instead of a Reference Object, as specified. This allows # simpler and faster navigation/checks and it has no effect in the serialized data formats anyway. - self.parent: Optional[Namespace] = None + self.parent: Optional[UniqueIdShortNamespace] = None self.source: str = "" def __repr__(self) -> str: reversed_path = [] item = self # type: Any - while item is not None: - if isinstance(item, Identifiable): - reversed_path.append(str(item.identification)) - break - elif isinstance(item, Referable): - reversed_path.append(item.id_short) - item = item.parent - else: - raise AttributeError('Referable must have an identifiable as root object and only parents that are ' - 'referable') - - return "{}[{}]".format(self.__class__.__name__, " / ".join(reversed(reversed_path))) - - def _get_id_short(self): + if item.id_short is not None: + from .submodel import SubmodelElementList + while item is not None: + if isinstance(item, Identifiable): + reversed_path.append(item.id) + break + elif isinstance(item, Referable): + if isinstance(item.parent, SubmodelElementList): + reversed_path.append(f"{item.parent.id_short}[{item.parent.value.index(item)}]") + item = item.parent + else: + reversed_path.append(item.id_short) + item = item.parent + else: + raise AttributeError('Referable must have an identifiable as root object and only parents that are ' + 'referable') + + return self.__class__.__name__ + ("[{}]".format(" / ".join(reversed(reversed_path))) if reversed_path else "") + + def _get_id_short(self) -> Optional[NameType]: return self._id_short - def _set_id_short(self, id_short: Optional[str]): + def _set_category(self, category: Optional[NameType]): """ Check the input string - Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and - used for referring to the element in its name space. - Constraint AASd-002: idShort shall only feature letters, digits, underscore ('_'); starting mandatory with a - letter + :param category: The category is a value that gives further meta information w.r.t. to the class of the element. + It affects the expected existence of attributes and the applicability of constraints. + :raises ValueError: if the constraint is not fulfilled + """ + if category is not None: + _string_constraints.check_name_type(category) + self._category = category + + def _get_category(self) -> Optional[NameType]: + return self._category - Additionally check that the idShort is not already present in the same parent Namespace (if this object is - already contained in a parent Namespace). + category = property(_get_category, _set_category) + + def _set_id_short(self, id_short: Optional[NameType]): + """ + Check the input string + + Constraint AASd-002: idShort of Referables shall only feature letters, digits, underscore ("_"); starting + mandatory with a letter. I.e. [a-zA-Z][a-zA-Z0-9_]+ + Constraint AASd-022: idShort of non-identifiable referables shall be unique in its namespace (case-sensitive) :param id_short: Identifying string of the element within its name space :raises ValueError: if the constraint is not fulfilled :raises KeyError: if the new idShort causes a name collision in the parent Namespace """ - if id_short is None and not hasattr(self, 'identification'): - raise ValueError("The id_short for not identifiable elements is mandatory") - test_id_short: str = str(id_short) - if not re.fullmatch("[a-zA-Z0-9_]*", test_id_short): - raise ValueError("The id_short must contain only letters, digits and underscore") - if len(test_id_short) > 0 and not test_id_short[0].isalpha(): - raise ValueError("The id_short must start with a letter") - - if self.parent is not None and id_short != self.id_short: + if id_short == self.id_short: + return + if id_short is not None: + _string_constraints.check_name_type(id_short) + test_id_short: NameType = str(id_short) + if not re.fullmatch("[a-zA-Z0-9_]*", test_id_short): + raise AASConstraintViolation( + 2, + "The id_short must contain only letters, digits and underscore" + ) + if not test_id_short[0].isalpha(): + raise AASConstraintViolation( + 2, + "The id_short must start with a letter" + ) + + if self.parent is not None: + if id_short is None: + raise AASConstraintViolation(117, f"id_short of {self!r} cannot be unset, since it is already " + f"contained in {self.parent!r}") + from .submodel import SubmodelElementList + if isinstance(self.parent, SubmodelElementList): + raise AASConstraintViolation(120, f"id_short of {self!r} cannot be set, because it is " + f"contained in a {self.parent!r}") for set_ in self.parent.namespace_element_sets: - if id_short in set_: - raise KeyError("Referable with id_short '{}' is already present in the parent Namespace" - .format(id_short)) + if set_.contains_id("id_short", id_short): + raise AASConstraintViolation(22, "Object with id_short '{}' is already present in the parent " + "Namespace".format(id_short)) + + set_add_list: List[NamespaceSet] = [] for set_ in self.parent.namespace_element_sets: if self in set_: + set_add_list.append(set_) set_.discard(self) - self._id_short = id_short - set_.add(self) - break + self._id_short = id_short + for set_ in set_add_list: + set_.add(self) # Redundant to the line above. However this way, we make sure that we really update the _id_short self._id_short = id_short @@ -475,7 +714,7 @@ def update(self, If there is no source in any ancestor, this function will do nothing :param max_age: Maximum age of the local data in seconds. This method may return early, if the previous update - of the object has been performed less than `max_age` seconds ago. + of the object has been performed less than `max_age` seconds ago. :param recursive: Also call update on all children of this object. Default is True :param _indirect_source: Internal parameter to avoid duplicate updating. :raises backends.BackendError: If no appropriate backend or the data source is not available @@ -503,8 +742,10 @@ def update(self, if recursive: # update all the children who have their own source - if isinstance(self, Namespace): + if isinstance(self, UniqueIdShortNamespace): for namespace_set in self.namespace_element_sets: + if "id_short" not in namespace_set.get_attribute_name_list(): + continue for referable in namespace_set: referable.update(max_age, recursive=True, _indirect_source=False) @@ -512,10 +753,11 @@ def find_source(self) -> Tuple[Optional["Referable"], Optional[List[str]]]: # t """ Finds the closest source in this objects ancestors. If there is no source, returns None - :return: (The closest ancestor with a defined source, the relative path of id_shorts to that ancestor) + :return: Tuple with the closest ancestor with a defined source and the relative path of id_shorts to that + ancestor """ referable: Referable = self - relative_path: List[str] = [self.id_short] + relative_path: List[NameType] = [self.id_short] while referable is not None: if referable.source != "": relative_path.reverse() @@ -557,7 +799,7 @@ def commit(self) -> None: ancestors. If there is no source, this function will do nothing. """ current_ancestor = self.parent - relative_path: List[str] = [self.id_short] + relative_path: List[NameType] = [self.id_short] # Commit to all ancestors with sources while current_ancestor: assert isinstance(current_ancestor, Referable) @@ -579,8 +821,10 @@ def _direct_source_commit(self): store_object=self, relative_path=[]) - if isinstance(self, Namespace): + if isinstance(self, UniqueIdShortNamespace): for namespace_set in self.namespace_element_sets: + if "id_short" not in namespace_set.get_attribute_name_list(): + continue for referable in namespace_set: referable._direct_source_commit() @@ -592,8 +836,8 @@ def _direct_source_commit(self): class UnexpectedTypeError(TypeError): """ - Exception to be raised by :meth:`~aas.model.base.AASReference.resolve` if the retrieved object has not the - expected type. + Exception to be raised by :meth:`aas.model.base.ModelReference.resolve` if the retrieved object has not the expected + type. :ivar value: The object of unexpected type """ @@ -602,118 +846,195 @@ def __init__(self, value: Referable, *args): self.value = value -class Reference: +class Reference(metaclass=abc.ABCMeta): """ Reference to either a model element of the same or another AAs or to an external entity. A reference is an ordered list of keys, each key referencing an element. The complete list of keys may for - example be concatenated to a path that then gives unique access to an element or entity + example be concatenated to a path that then gives unique access to an element or entity. - :ivar: key: Ordered list of unique reference in its name space, each key referencing an element. The complete - list of keys may for example be concatenated to a path that then gives unique access to an element - or entity. - :ivar: type: The type of the referenced object (additional attribute, not from the AAS Metamodel) - """ + This is the abstract superclass of ExternalReference and ModelReference, which implements common attributes and + methods used in both reference types. The two reference types are implemented as separate classes in this SDK to + allow typing and resolving of References with Reference/type=ModelReference. - def __init__(self, - key: Tuple[Key, ...]): - """ - Initializer of Reference + <> - :param key: Ordered list of unique reference in its name space, each key referencing an element. The complete - list of keys may for example be concatenated to a path that then gives unique access to an element - or entity. + *Constraint AASd-121:* For References the value of Key/type of the first key of Reference/keys shall be one of + GloballyIdentifiables. - TODO: Add instruction what to do after construction - """ + :ivar key: Ordered list of unique reference in its name space, each key referencing an element. The complete + list of keys may for example be concatenated to a path that then gives unique access to an element + or entity. + :ivar referred_semantic_id: SemanticId of the referenced model element. For external references there typically is + no semantic id. + """ + @abc.abstractmethod + def __init__(self, key: Tuple[Key, ...], referred_semantic_id: Optional["Reference"] = None): if len(key) < 1: raise ValueError("A reference must have at least one key!") + # Constraint AASd-121 is enforced by checking AASd-122 for external references and AASd-123 for model references + self.key: Tuple[Key, ...] + self.referred_semantic_id: Optional["Reference"] super().__setattr__('key', key) + super().__setattr__('referred_semantic_id', referred_semantic_id) def __setattr__(self, key, value): """Prevent modification of attributes.""" raise AttributeError('Reference is immutable') - def __repr__(self) -> str: - return "Reference(key={})".format(self.key) - def __hash__(self): - return hash(self.key) + return hash((self.__class__, self.key)) def __eq__(self, other: object) -> bool: - if not isinstance(other, Reference): + if not isinstance(other, self.__class__): return NotImplemented if len(self.key) != len(other.key): return False - return all(k1 == k2 for k1, k2 in zip(self.key, other.key)) + return all(k1 == k2 for k1, k2 in zip(self.key, other.key)) \ + and self.referred_semantic_id == other.referred_semantic_id + +class ExternalReference(Reference): + """ + Reference to either a model element of the same or another AAs or to an external entity. -class AASReference(Reference, Generic[_RT]): + A reference is an ordered list of keys, each key referencing an element. The complete list of keys may for + example be concatenated to a path that then gives unique access to an element or entity. + + *Constraint AASd-122:* For external references, i.e. References with Reference/type = ExternalReference, + the value of Key/type of the first key of Reference/keys shall be one of GenericGloballyIdentifiables. + *Constraint AASd-124:* For external references, i.e. References with Reference/type = ExternalReference, + the last key of Reference/keys shall be either one of GenericGloballyIdentifiables + or one of GenericFragmentKeys. + + :ivar key: Ordered list of unique reference in its name space, each key referencing an element. The complete + list of keys may for example be concatenated to a path that then gives unique access to an element + or entity. + :ivar referred_semantic_id: SemanticId of the referenced model element. For external references there typically is + no semantic id. """ - Typed :class:`~.Reference` to any :class:`~.Referable` :class:`~aas.model.aas.AssetAdministrationShell` object. - This is a special construct of the implementation to allow typed references and dereferencing. + def __init__(self, key: Tuple[Key, ...], referred_semantic_id: Optional["Reference"] = None): + super().__init__(key, referred_semantic_id) + + if not key[0].type.is_generic_globally_identifiable: + raise AASConstraintViolation(122, "The type of the first key of an ExternalReference must be a " + f"GenericGloballyIdentifiable: {key[0]!r}") + if not key[-1].type.is_generic_globally_identifiable and not key[-1].type.is_generic_fragment_key: + raise AASConstraintViolation(124, "The type of the last key of an ExternalReference must be a " + f"GenericGloballyIdentifiable or a GenericFragmentKey: {key[-1]!r}") - :ivar key: Ordered list of unique references in its name space, each key referencing an element. The complete - list of keys may for example be concatenated to a path that then gives unique access to an element - or entity (inherited from :class:`~.Reference`). - :ivar: type: The type of the referenced object (additional parameter, not from the AAS Metamodel), - Initialisation parameter: `target_type` + def __repr__(self) -> str: + return "ExternalReference(key={})".format(self.key) + + +class ModelReference(Reference, Generic[_RT]): """ - def __init__(self, - key: Tuple[Key, ...], - target_type: Type[_RT]): - """ - TODO: Add instruction what to do after construction - """ - # TODO check keys for validity. GlobalReference and Fragment-Type keys are not allowed here - super().__init__(key) + Typed Reference to any referable AAS object. + + This is a special construct of the implementation to allow typed references and de-referencing. + + *Constraint AASd-123:* For model references, i.e. References with Reference/type = ModelReference, + the value of Key/type of the first key of Reference/keys shall be one of AasIdentifiables. + *Constraint AASd-125:* For model references, i.e. References with Reference/type = ModelReference with more than + one key in Reference/keys, the value of Key/type of each of the keys following the first key of Reference/keys + shall be one of FragmentKeys. + *Constraint AASd-126:* For model references, i.e. References with Reference/type = ModelReference with more than + one key in Reference/keys, the value of Key/type of the last Key in the reference key chain may be one of + GenericFragmentKeys, or no key at all shall have a value out of GenericFragmentKeys. + *Constraint AASd-127:* For model references, i.e. References with Reference/type = ModelReference with more than + one key in Reference/keys, a key with Key/type FragmentReference shall be preceded by a key with Key/type + File or Blob. All other AAS fragments, i.e. Key/type values out of AasSubmodelElements, + do not support fragments. + *Constraint AASd-128:* For model references the Key/value of a Key preceded by a Key with + Key/type=SubmodelElementList is an integer number denoting the position in the array of the + submodel element list. + + :ivar key: Ordered list of unique :class:`Keys <.Key>` in its name space, each key referencing an element. + The complete list of keys may for example be concatenated to a path that then gives unique access to an + element or entity. + :ivar ~.type: The type of the referenced object (additional parameter, not from the AAS Metamodel) + *Initialization parameter:* `type_` + :ivar referred_semantic_id: SemanticId of the referenced model element. For external references there typically is + no semantic id. + """ + def __init__(self, key: Tuple[Key, ...], type_: Type[_RT], referred_semantic_id: Optional[Reference] = None): + super().__init__(key, referred_semantic_id) + + if not key[0].type.is_aas_identifiable: + raise AASConstraintViolation(123, "The type of the first key of a ModelReference must be an " + f"AasIdentifiable: {key[0]!r}") + for k in key[1:]: + if not k.type.is_fragment_key_element: + raise AASConstraintViolation(125, "The type of all keys following the first of a ModelReference " + f"must be one of FragmentKeyElements: {k!r}") + if not key[-1].type.is_generic_fragment_key: + for k in key[:-1]: + if k.type.is_generic_fragment_key: + raise AASConstraintViolation(126, f"Key {k!r} is a GenericFragmentKey, " + f"but the last key of the chain is not: {key[-1]!r}") + for pk, k in zip(key, key[1:]): + if k.type == KeyTypes.FRAGMENT_REFERENCE and pk.type not in (KeyTypes.BLOB, KeyTypes.FILE): + raise AASConstraintViolation(127, f"{k!r} is not preceeded by a key of type File or Blob, but {pk!r}") + if pk.type == KeyTypes.SUBMODEL_ELEMENT_LIST and not k.value.isnumeric(): + raise AASConstraintViolation(128, f"Key {pk!r} references a SubmodelElementList, " + f"but the value of the succeeding key ({k!r}) is not a non-negative " + f"integer: {k.value}") + self.type: Type[_RT] - object.__setattr__(self, 'type', target_type) + object.__setattr__(self, 'type', type_) def resolve(self, provider_: "provider.AbstractObjectProvider") -> _RT: """ Follow the :class:`~.Reference` and retrieve the :class:`~.Referable` object it points to + :param provider_: :class:`~aas.model.provider.AbstractObjectProvider` :return: The referenced object (or a proxy object for it) :raises IndexError: If the list of keys is empty - :raises TypeError: If one of the intermediate objects on the path is not a Namespace + :raises TypeError: If one of the intermediate objects on the path is not a :class:`~aas.model.base.Namespace` :raises UnexpectedTypeError: If the retrieved object is not of the expected type (or one of its subclasses). The object is stored in the `value` attribute of the exception :raises KeyError: If the reference could not be resolved """ - # Find key index last (global) identifier-key in key list (from https://stackoverflow.com/a/6890255/10315508) - try: - last_identifier_index = next(i - for i in reversed(range(len(self.key))) - if self.key[i].get_identifier()) - except StopIteration: - # If no identifier-key is contained in the list, we could try to resolve the path locally. - # TODO implement local resolution - raise NotImplementedError("We currently don't support local-only references without global identifier keys") - resolved_keys: List[str] = [] # for more helpful error messages + from . import SubmodelElementList - # First, resolve the identifier-key via the provider - identifier: Identifier = self.key[last_identifier_index].get_identifier() # type: ignore + # For ModelReferences, the first key must be an AasIdentifiable. So resolve the first key via the provider. + identifier: Optional[Identifier] = self.key[0].get_identifier() + if identifier is None: + raise AssertionError("Retrieving the identifier of the first key failed.") + + resolved_keys: List[str] = [] # for more helpful error messages try: item: Referable = provider_.get_identifiable(identifier) except KeyError as e: - raise KeyError("Could not resolve global reference key {}".format(identifier)) from e + raise KeyError("Could not resolve identifier {}".format(identifier)) from e resolved_keys.append(str(identifier)) - # Now, follow path, given by remaining keys, recursively - for key in self.key[last_identifier_index+1:]: - if not isinstance(item, Namespace): + # All keys following the first must not reference identifiables (AASd-125). Thus, we can just follow the path + # recursively. + for key in self.key[1:]: + if not isinstance(item, UniqueIdShortNamespace): raise TypeError("Object retrieved at {} is not a Namespace".format(" / ".join(resolved_keys))) + is_submodel_element_list = isinstance(item, SubmodelElementList) try: - item = item.get_referable(key.value) - except KeyError as e: - raise KeyError("Could not resolve id_short {} at {}".format(key.value, " / ".join(resolved_keys)))\ + if is_submodel_element_list: + # The key's value must be numeric, since this is checked for keys following keys of type + # SUBMODEL_ELEMENT_LIST on construction of ModelReferences. + # Additionally item is known to be a SubmodelElementList which supports __getitem__ because we're in + # the `is_submodel_element_list` branch, but mypy doesn't infer types based on isinstance checks + # stored in boolean variables. + item = item.value[int(key.value)] # type: ignore + resolved_keys[-1] += f"[{key.value}]" + else: + item = item.get_referable(key.value) + resolved_keys.append(item.id_short) + except (KeyError, IndexError) as e: + raise KeyError("Could not resolve {} {} at {}".format( + "index" if is_submodel_element_list else "id_short", key.value, " / ".join(resolved_keys)))\ from e - resolved_keys.append(item.id_short) # Check type if not isinstance(item, self.type): @@ -726,7 +1047,8 @@ def get_identifier(self) -> Identifier: Retrieve the :class:`~.Identifier` of the :class:`~.Identifiable` object, which is referenced or in which the referenced :class:`~.Referable` is contained. - :raises ValueError: If this :class:`~.Reference` does not include a Key with global KeyType (IRDI, IRI, CUSTOM) + :returns: :class:`~.Identifier` + :raises ValueError: If this :class:`~.ModelReference` does not include a Key of AasIdentifiable type """ try: last_identifier = next(key.get_identifier() @@ -734,28 +1056,31 @@ def get_identifier(self) -> Identifier: if key.get_identifier()) return last_identifier # type: ignore # MyPy doesn't get the generator expression above except StopIteration: - raise ValueError("Reference cannot be represented as an Identifier, since it does not contain a Key with " - "global KeyType (IRDI, IRI, CUSTOM)") + raise ValueError("ModelReference cannot be represented as an Identifier, since it does not contain a Key" + f" of an AasIdentifiable type ({[t.name for t in KeyTypes if t.is_aas_identifiable]})") def __repr__(self) -> str: - return "AASReference(type={}, key={})".format(self.type.__name__, self.key) + return "ModelReference<{}>(key={})".format(self.type.__name__, self.key) @staticmethod - def from_referable(referable: Referable) -> "AASReference": + def from_referable(referable: Referable) -> "ModelReference": """ - Construct an :class:`~.AASReference` to a given :class:`~.Referable` AAS object + Construct an :class:`~.ModelReference` to a given :class:`~.Referable` AAS object This requires that the :class:`~.Referable` object is :class:`~.Identifiable` itself or is a child-, grand-child-, etc. object of an :class:`~.Identifiable` object. Additionally, the object must be an instance of a known :class:`~.Referable` type. - :raises ValueError: If no Identifiable object is found while traversing the object's ancestors + :param referable: :class:`~aas.model.base.Referable` object to construct the :class:`~.ModelReference` from + :returns: Constructed :class:`~.ModelReference` + :raises ValueError: If no :class:`~aas.model.base.Identifiable` object is found while traversing the object's + ancestors """ # Get the first class from the base classes list (via inspect.getmro), that is contained in KEY_ELEMENTS_CLASSES - from . import KEY_ELEMENTS_CLASSES + from . import KEY_TYPES_CLASSES try: - ref_type = next(iter(t for t in inspect.getmro(type(referable)) if t in KEY_ELEMENTS_CLASSES)) + ref_type = next(iter(t for t in inspect.getmro(type(referable)) if t in KEY_TYPES_CLASSES)) except StopIteration: ref_type = Referable @@ -765,12 +1090,164 @@ def from_referable(referable: Referable) -> "AASReference": keys.append(Key.from_referable(ref)) if isinstance(ref, Identifiable): keys.reverse() - return AASReference(tuple(keys), ref_type) + return ModelReference(tuple(keys), ref_type) if ref.parent is None or not isinstance(ref.parent, Referable): raise ValueError("The given Referable object is not embedded within an Identifiable object") ref = ref.parent +@_string_constraints.constrain_content_type("content_type") +@_string_constraints.constrain_path_type("path") +class Resource: + """ + Resource represents an address to a file (a locator). The value is an URI that can represent an absolute or relative + path. + + :ivar path: Path and name of the resource (with file extension). The path can be absolute or relative. + :ivar content_type: Content type of the content of the file. The content type states which file extensions the file + can have. + """ + def __init__(self, path: PathType, content_type: Optional[ContentType] = None): + self.path: PathType = path + self.content_type: Optional[ContentType] = content_type + + def __repr__(self): + return f"Resource[{self.path}]" + + +class DataSpecificationContent: + """ + Data specification content is part of a data specification template and defines + which additional attributes shall be added to the element instance that references + the data specification template and meta information about the template itself. + + *Constraint AASc-3a-050:* If the `Data_specification_IEC_61360` is used + for an element, the value of `Has_data_specification.embedded_data_specifications` + shall contain the external reference to the IRI of the corresponding data specification + template + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + """ + @abc.abstractmethod + def __init__(self): + pass + + +class EmbeddedDataSpecification: + """ + Embed the content of a data specification. + + :ivar data_specification: Reference to the data specification + :ivar data_specification_content: Actual content of the data specification + """ + def __init__( + self, + data_specification: Reference, + data_specification_content: DataSpecificationContent, + ) -> None: + self.data_specification: Reference = data_specification + self.data_specification_content: DataSpecificationContent = data_specification_content + + def __repr__(self): + return f"EmbeddedDataSpecification[{self.data_specification}]" + + +class HasDataSpecification(metaclass=abc.ABCMeta): + """ + Element that can be extended by using data specification templates. + + A data specification template defines a named set of additional attributes an + element may or shall have. The data specifications used are explicitly specified + with their global ID. + + *Note:* Please consider, that we have not implemented DataSpecification template class + + :ivar embedded_data_specifications: List of :class:`~.EmbeddedDataSpecification`. + """ + @abc.abstractmethod + def __init__( + self, + embedded_data_specifications: Iterable[EmbeddedDataSpecification] = (), + ) -> None: + self.embedded_data_specifications = list(embedded_data_specifications) + + +@_string_constraints.constrain_version_type("version") +@_string_constraints.constrain_identifier("template_id") +class AdministrativeInformation(HasDataSpecification): + """ + Administrative meta-information for an element like version information. + + *Constraint AASd-005:* If AdministrativeInformation/version is not specified then also + AdministrativeInformation/revision shall be unspecified. This means, a revision + requires a version. if there is no version there is no revision neither. Revision is + optional. + + :ivar version: Version of the element. + :ivar revision: Revision of the element. + :ivar creator: The subject ID of the subject responsible for making the element + :ivar template_id: Identifier of the template that guided the creation of the element + + *Note:* In case of a submodel, the template ID is the identifier of the submodel template that guided the + creation of the submodel. + + *Note:* The submodel template ID is not relevant for validation. Here, the Submodel/semanticId shall be used + + *Note:* Usage of the template ID is not restricted to submodel instances. + The creation of submodel templates can also be guided by another submodel template. + + :ivar embedded_data_specifications: List of Embedded data specification. + used by the element. + """ + + def __init__(self, + version: Optional[VersionType] = None, + revision: Optional[RevisionType] = None, + creator: Optional[Reference] = None, + template_id: Optional[Identifier] = None, + embedded_data_specifications: Iterable[EmbeddedDataSpecification] = ()): + """ + Initializer of AdministrativeInformation + + :raises ValueError: If version is None and revision is not None + + TODO: Add instruction what to do after construction + """ + super().__init__() + self.version: Optional[VersionType] = version + self._revision: Optional[RevisionType] + self.revision = revision + self.creator: Optional[Reference] = creator + self.template_id: Optional[Identifier] = template_id + self.embedded_data_specifications: List[EmbeddedDataSpecification] = list(embedded_data_specifications) + + def _get_revision(self): + return self._revision + + def _set_revision(self, revision: Optional[RevisionType]): + if self.version is None and revision: + raise AASConstraintViolation(5, "A revision requires a version. This means, if there is no version " + "there is no revision neither. Please set version first.") + if revision is not None: + _string_constraints.check_revision_type(revision) + self._revision = revision + + revision = property(_get_revision, _set_revision) + + def __eq__(self, other) -> bool: + if not isinstance(other, AdministrativeInformation): + return NotImplemented + return self.version == other.version \ + and self._revision == other._revision \ + and self.creator == other.creator \ + and self.template_id == other.template_id + + def __repr__(self) -> str: + return "AdministrativeInformation(version={}, revision={}, creator={}, template_id={})".format( + self.version, self.revision, self.creator, self.template_id) + + +@_string_constraints.constrain_identifier("id") class Identifiable(Referable, metaclass=abc.ABCMeta): """ An element that has a globally unique :class:`~.Identifier`. @@ -778,16 +1255,124 @@ class Identifiable(Referable, metaclass=abc.ABCMeta): <> :ivar administration: :class:`~.AdministrativeInformation` of an identifiable element. - :ivar ~.identification: The globally unique identification of the element. + :ivar ~.id: The globally unique id of the element. """ @abc.abstractmethod - def __init__(self): + def __init__(self) -> None: super().__init__() self.administration: Optional[AdministrativeInformation] = None - self.identification: Identifier = Identifier("", IdentifierType.IRDI) + # The id attribute is set by all inheriting classes __init__ functions. + self.id: Identifier def __repr__(self) -> str: - return "{}[{}]".format(self.__class__.__name__, self.identification) + return "{}[{}]".format(self.__class__.__name__, self.id) + + +_T = TypeVar("_T") + + +class ConstrainedList(MutableSequence[_T], Generic[_T]): + """ + A type of list that can be constrained by hooks, useful when implementing AASd constraints. This list can be + initialized with an `item_add_hook`, `item_set_hook` and an `item_del_hook`. + + The item_add_hook is called every time an item is added to the list. It is passed the item that is added and + all items currently contained in the list. + + The `item_set_hook` is called every time one or multiple items are overwritten with one or multiple new items, à la + `list[i] = new_item` or `list[i:j] = new_items`. It is passed the item(s) about to replaced, the new item(s) and all + items currently contained in the list. + Note that this can also be used to clear the list, e.g. `list[:] = []`. Thus, to ensure that a list is never empty, + `item_set_hook` must be used in addition to `item_del_hook`. + + Finally, `item_del_hook` is called whenever an item is removed from the list, (e.g. via `.remove()`, `.pop()` or + `del list[i]`. It is passed the item about to be deleted and the current list elements. + """ + + def __init__(self, items: Iterable[_T], item_add_hook: Optional[Callable[[_T, List[_T]], None]] = None, + item_set_hook: Optional[Callable[[List[_T], List[_T], List[_T]], None]] = None, + item_del_hook: Optional[Callable[[_T, List[_T]], None]] = None) -> None: + super().__init__() + self._list: List[_T] = [] + self._item_add_hook: Optional[Callable[[_T, List[_T]], None]] = item_add_hook + self._item_set_hook: Optional[Callable[[List[_T], List[_T], List[_T]], None]] = item_set_hook + self._item_del_hook: Optional[Callable[[_T, List[_T]], None]] = item_del_hook + self.extend(items) + + def insert(self, index: int, value: _T) -> None: + if self._item_add_hook is not None: + self._item_add_hook(value, self._list) + self._list.insert(index, value) + + def extend(self, values: Iterable[_T]) -> None: + v_list = list(values) + if self._item_add_hook is not None: + for idx, v in enumerate(v_list): + self._item_add_hook(v, self._list + v_list[:idx]) + self._list = self._list + v_list + + def clear(self) -> None: + # clear() repeatedly deletes the last item by default, making it not atomic + del self[:] + + @overload + def __getitem__(self, index: int) -> _T: ... + + @overload + def __getitem__(self, index: slice) -> MutableSequence[_T]: ... + + def __getitem__(self, index: Union[int, slice]) -> Union[_T, MutableSequence[_T]]: + return self._list[index] + + @overload + def __setitem__(self, index: int, value: _T) -> None: ... + + @overload + def __setitem__(self, index: slice, value: Iterable[_T]) -> None: ... + + def __setitem__(self, index: Union[int, slice], value: Union[_T, Iterable[_T]]) -> None: + # TODO: remove the following type: ignore once mypy supports type narrowing using overload information + # https://github.com/python/mypy/issues/4063 + if isinstance(index, int): + if self._item_set_hook is not None: + self._item_set_hook([self._list[index]], [value], self._list) # type: ignore + self._list[index] = value # type: ignore + return + if self._item_set_hook is not None: + self._item_set_hook(self._list[index], list(value), self._list) # type: ignore + self._list[index] = value # type: ignore + + @overload + def __delitem__(self, index: int) -> None: ... + + @overload + def __delitem__(self, index: slice) -> None: ... + + def __delitem__(self, index: Union[int, slice]) -> None: + if isinstance(index, int): + if self._item_del_hook is not None: + self._item_del_hook(self._list[index], self._list) + del self._list[index] + return + if self._item_del_hook is not None: + indices = range(len(self._list))[index] + # To avoid partial deletions, perform a dry run first. + dry_run_list = self._list.copy() + # Delete high indices first to avoid conflicts by changing indices due to deletion of other objects. + for i in sorted(indices, reverse=True): + self._item_del_hook(dry_run_list[i], dry_run_list) + del dry_run_list[i] + # If all went well, we can now perform the real deletion. + del self._list[index] + + def __len__(self) -> int: + return len(self._list) + + def __repr__(self) -> str: + return repr(self._list) + + def __eq__(self, other) -> bool: + return other == self._list class HasSemantics(metaclass=abc.ABCMeta): @@ -796,14 +1381,133 @@ class HasSemantics(metaclass=abc.ABCMeta): <> + *Constraint AASd-118:* If a supplemental semantic ID (HasSemantics/supplementalSemanticId) is defined, + there shall also be a main semantic ID (HasSemantics/semanticId). + :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the element. The semantic id may either reference an external global id or it may reference a referable model element of kind=Type that defines the semantics of the element. + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. """ @abc.abstractmethod - def __init__(self): + def __init__(self) -> None: super().__init__() - self.semantic_id: Optional[Reference] = None + # TODO: parent can be any `Namespace`, unfortunately this definition would be incompatible with the definition + # of Referable.parent as `UniqueIdShortNamespace` + self.parent: Optional[Any] = None + self._supplemental_semantic_id: ConstrainedList[Reference] = ConstrainedList( + [], item_add_hook=self._check_constraint_add) + self._semantic_id: Optional[Reference] = None + + def _check_constraint_add(self, _new: Reference, _list: List[Reference]) -> None: + if self.semantic_id is None: + raise AASConstraintViolation(118, "A semantic_id must be defined before adding a supplemental_semantic_id!") + + @property + def semantic_id(self) -> Optional[Reference]: + return self._semantic_id + + @semantic_id.setter + def semantic_id(self, semantic_id: Optional[Reference]) -> None: + if semantic_id is None and len(self.supplemental_semantic_id) > 0: + raise AASConstraintViolation(118, "semantic_id can not be removed while there is at least one " + f"supplemental_semantic_id: {self.supplemental_semantic_id!r}") + if self.parent is not None: + if semantic_id is not None: + for set_ in self.parent.namespace_element_sets: + if set_.contains_id("semantic_id", semantic_id): + raise KeyError("Object with semantic_id is already present in the parent Namespace") + set_add_list: List[NamespaceSet] = [] + for set_ in self.parent.namespace_element_sets: + if self in set_: + set_add_list.append(set_) + set_.discard(self) + self._semantic_id = semantic_id + for set_ in set_add_list: + set_.add(self) + # Redundant to the line above. However this way, we make sure that we really update the _semantic_id + self._semantic_id = semantic_id + + @property + def supplemental_semantic_id(self) -> ConstrainedList[Reference]: + return self._supplemental_semantic_id + + @supplemental_semantic_id.setter + def supplemental_semantic_id(self, supplemental_semantic_id: Iterable[Reference]): + self._supplemental_semantic_id[:] = supplemental_semantic_id + + +class Extension(HasSemantics): + """ + Single extension of an element + + :ivar name: An extension of the element. + :ivar value_type: Type (:class:`~.DataTypeDefXsd`) of the value of the extension. Default: xsd:string + :ivar value: Value (:class:`~.ValueDataType`) of the extension + :ivar refers_to: An iterable of :class:`~.ModelReference` to elements the extension refers to + :ivar semantic_id: The semantic_id defined in the :class:`~.HasSemantics` class. + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + """ + + def __init__(self, + name: NameType, + value_type: Optional[DataTypeDefXsd] = None, + value: Optional[ValueDataType] = None, + refers_to: Iterable[ModelReference] = (), + semantic_id: Optional[Reference] = None, + supplemental_semantic_id: Iterable[Reference] = ()): + super().__init__() + self.parent: Optional[HasExtension] = None + self._name: NameType + self.name: NameType = name + self.value_type: Optional[DataTypeDefXsd] = value_type + self._value: Optional[ValueDataType] + self.value = value + self.refers_to: Set[ModelReference] = set(refers_to) + self.semantic_id: Optional[Reference] = semantic_id + self.supplemental_semantic_id: ConstrainedList[Reference] = ConstrainedList(supplemental_semantic_id) + + def __repr__(self) -> str: + return "Extension(name={})".format(self.name) + + @property + def value(self): + return self._value + + @value.setter + def value(self, value) -> None: + if value is None: + self._value = None + else: + if self.value_type is None: + raise ValueError('ValueType must be set, if value is not None') + self._value = datatypes.trivial_cast(value, self.value_type) + + @property + def name(self): + return self._name + + @name.setter + def name(self, name: NameType) -> None: + _string_constraints.check_name_type(name) + if self.parent is not None: + for set_ in self.parent.namespace_element_sets: + if set_.contains_id("name", name): + raise KeyError("Object with name '{}' is already present in the parent Namespace" + .format(name)) + set_add_list: List[NamespaceSet] = [] + for set_ in self.parent.namespace_element_sets: + if self in set_: + set_add_list.append(set_) + set_.discard(self) + self._name = name + for set_ in set_add_list: + set_.add(self) + # Redundant to the line above. However this way, we make sure that we really update the _name + self._name = name class HasKind(metaclass=abc.ABCMeta): @@ -813,93 +1517,102 @@ class HasKind(metaclass=abc.ABCMeta): <> - :ivar kind: Kind of the element: either type or instance. Default = Instance. + :ivar _kind: Kind of the element: either type or instance. Default = :attr:`~ModellingKind.INSTANCE`. """ @abc.abstractmethod - def __init__(self): + def __init__(self) -> None: super().__init__() - self._kind: ModelingKind = ModelingKind.INSTANCE + self._kind: ModellingKind = ModellingKind.INSTANCE @property def kind(self): return self._kind -class Constraint(metaclass=abc.ABCMeta): +class Qualifiable(Namespace, metaclass=abc.ABCMeta): """ - A constraint is used to further qualify an element. + Abstract baseclass for all objects which form a Namespace to hold :class:`~.Qualifier` objects and resolve them by + their type. <> - """ - @abc.abstractmethod - def __init__(self): - pass - -class Qualifiable(metaclass=abc.ABCMeta): - """ - The value of a qualifiable element may be further qualified by one or more qualifiers or complex formulas. - - <> - - :ivar qualifier: Unordered list of :class:`Constraints <~.Constraint>` that gives additional qualification of a + :ivar namespace_element_sets: A list of all :class:`NamespaceSets <.NamespaceSet>` of this Namespace + :ivar qualifier: Unordered list of :class:`Qualifiers <~.Qualifier>` that gives additional qualification of a qualifiable element. """ @abc.abstractmethod - def __init__(self): + def __init__(self) -> None: super().__init__() - self.qualifier: Set[Constraint] = set() + self.namespace_element_sets: List[NamespaceSet] = [] + self.qualifier: NamespaceSet[Qualifier] + def get_qualifier_by_type(self, qualifier_type: QualifierType) -> "Qualifier": + """ + Find a :class:`~.Qualifier` in this Namespace by its type -class Formula(Constraint): - """ - A formula is used to describe constraints by a logical expression. + :raises KeyError: If no such :class:`~.Qualifier` can be found + """ + return super()._get_object(Qualifier, "type", qualifier_type) - :ivar depends_on: Unordered list of :class:`References <~.Reference>` to :class:`~.Referable` or even external - global elements that are used in the - logical expression. The value of the referenced elements needs to be accessible so that - it can be evaluated in the formula to true or false in the corresponding logical expression - it is used in. - """ + def add_qualifier(self, qualifier: "Qualifier") -> None: + """ + Add a :class:`~.Qualifier` to this Namespace - def __init__(self, - depends_on: Optional[Set[Reference]] = None): + :param qualifier: The :class:`~.Qualifier` to add + :raises KeyError: If a qualifier with the same type is already present in this namespace + :raises ValueError: If the passed object already has a parent namespace """ - TODO: Add instruction what to do after construction + return super()._add_object("type", qualifier) + + def remove_qualifier_by_type(self, qualifier_type: QualifierType) -> None: """ - super().__init__() - self.depends_on: Set[Reference] = set() if depends_on is None else depends_on + Remove a :class:`~.Qualifier` from this Namespace by its type + + :raises KeyError: If no such :class:`~.Qualifier` can be found + """ + return super()._remove_object(Qualifiable, "type", qualifier_type) -class Qualifier(Constraint, HasSemantics): +class Qualifier(HasSemantics): """ A qualifier is a type-value pair that makes additional statements w.r.t. the value of the element. - **Constraint AASd-006:** if both, the value and the valueId are present then the value needs to be - identical to the value of the referenced coded value in Qualifier/valueId. - - :ivar type: The type of the qualifier that is applied to the element. - :ivar value_type: Data type of the qualifier value - :ivar value: The value of the qualifier. - :ivar value_id: Reference to the global unique id of a coded value. - :ivar semantic_id: The semantic_id defined in the HasSemantics class. + *Constraint AASd-006:* If both, the value and the valueId of a Qualifier are present, the value needs + to be identical to the value of the referenced coded value in Qualifier/valueId. + *Constraint AASd-020:* The value of Qualifier/value shall be consistent with the + data type as defined in Qualifier/valueType. + + :ivar type: The type (:class:`~.QualifierType`) of the qualifier that is applied to the element. + :ivar value_type: Data type (:class:`~.DataTypeDefXsd`) of the qualifier value + :ivar value: The value (:class:`~.ValueDataType`) of the qualifier. + :ivar value_id: :class:`~.Reference` to the global unique id of a coded value. + :ivar semantic_id: The semantic_id defined in :class:`~.HasSemantics`. + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) """ def __init__(self, type_: QualifierType, - value_type: DataTypeDef, + value_type: DataTypeDefXsd, value: Optional[ValueDataType] = None, value_id: Optional[Reference] = None, - semantic_id: Optional[Reference] = None): + kind: QualifierKind = QualifierKind.CONCEPT_QUALIFIER, + semantic_id: Optional[Reference] = None, + supplemental_semantic_id: Iterable[Reference] = ()): """ TODO: Add instruction what to do after construction """ super().__init__() + self.parent: Optional[Qualifiable] = None + self._type: QualifierType self.type: QualifierType = type_ - self.value_type: Type[datatypes.AnyXSDType] = value_type + self.value_type: DataTypeDefXsd = value_type self._value: Optional[ValueDataType] = datatypes.trivial_cast(value, value_type) if value is not None else None self.value_id: Optional[Reference] = value_id + self.kind: QualifierKind = kind self.semantic_id: Optional[Reference] = semantic_id + self.supplemental_semantic_id: ConstrainedList[Reference] = ConstrainedList(supplemental_semantic_id) def __repr__(self) -> str: return "Qualifier(type={})".format(self.type) @@ -915,7 +1628,31 @@ def value(self, value) -> None: else: self._value = datatypes.trivial_cast(value, self.value_type) + @property + def type(self): + return self._type + @type.setter + def type(self, type_: QualifierType) -> None: + _string_constraints.check_qualifier_type(type_) + if self.parent is not None: + for set_ in self.parent.namespace_element_sets: + if set_.contains_id("type", type_): + raise KeyError("Object with type '{}' is already present in the parent Namespace" + .format(type_)) + set_add_list: List[NamespaceSet] = [] + for set_ in self.parent.namespace_element_sets: + if self in set_: + set_add_list.append(set_) + set_.discard(self) + self._type = type_ + for set_ in set_add_list: + set_.add(self) + # Redundant to the line above. However this way, we make sure that we really update the _type + self._type = type_ + + +@_string_constraints.constrain_value_type_iec61360("value") class ValueReferencePair: """ A value reference pair within a value list. Each value has a global unique id defining its semantic. @@ -927,43 +1664,21 @@ class ValueReferencePair: """ def __init__(self, - value_type: DataTypeDef, - value: ValueDataType, + value: ValueTypeIEC61360, value_id: Reference): """ - Initializer of ValueReferencePair - :param value: The value of the referenced concept definition of the value in value_id - :param value_id: Global unique id of the value. - :param value_type: XSD datatype of the value (this is not compliant to the DotAAS meta model) TODO: Add instruction what to do after construction """ - self.value_type: Type[datatypes.AnyXSDType] = value_type self.value_id: Reference = value_id - self._value: ValueDataType = datatypes.trivial_cast(value, value_type) - - @property - def value(self): - return self._value - - @value.setter - def value(self, value) -> None: - if value is None: - raise AttributeError('Value can not be None') - else: - self._value = datatypes.trivial_cast(value, self.value_type) + self.value: ValueTypeIEC61360 = value def __repr__(self) -> str: - return "ValueReferencePair(value_type={}, value={}, value_id={})".format(self.value_type, - self.value, - self.value_id) - - -ValueList = Set[ValueReferencePair] + return "ValueReferencePair(value={}, value_id={})".format(self.value, self.value_id) -class Namespace(metaclass=abc.ABCMeta): +class UniqueIdShortNamespace(Namespace, metaclass=abc.ABCMeta): """ Abstract baseclass for all objects which form a Namespace to hold :class:`~.Referable` objects and resolve them by their id_short. @@ -971,57 +1686,127 @@ class Namespace(metaclass=abc.ABCMeta): A Namespace can contain multiple :class:`NamespaceSets <~.NamespaceSet>`, which contain :class:`~.Referable` objects of different types. However, the id_short of each object must be unique across all NamespaceSets of one Namespace. - :ivar namespace_element_sets: A list of all NamespaceSets of this Namespace + + + :ivar namespace_element_sets: A list of all :class:`NamespaceSets <.NamespaceSet>` of this Namespace """ @abc.abstractmethod def __init__(self) -> None: super().__init__() self.namespace_element_sets: List[NamespaceSet] = [] - def get_referable(self, id_short: str) -> Referable: + def get_referable(self, id_short: NameType) -> Referable: """ - Find a :class:`~.Referable` in this Namespaces by its `id_short` + Find a :class:`~.Referable` in this Namespace by its id_short + :param id_short: id_short + :returns: :class:`~.Referable` :raises KeyError: If no such :class:`~.Referable` can be found """ - for dict_ in self.namespace_element_sets: - if id_short in dict_: - return dict_.get_referable(id_short) - raise KeyError("Referable with id_short {} not found in this namespace".format(id_short)) + return super()._get_object(Referable, "id_short", id_short) # type: ignore + + def add_referable(self, referable: Referable) -> None: + """ + Add a :class:`~.Referable` to this Namespace + + :param referable: The :class:`~.Referable` to add + :raises KeyError: If a :class:`~.Referable` with the same name is already present in this namespace + :raises ValueError: If the given :class:`~.Referable` already has a parent namespace + """ + return super()._add_object("id_short", referable) - def remove_referable(self, id_short: str) -> None: + def remove_referable(self, id_short: NameType) -> None: """ Remove a :class:`~.Referable` from this Namespace by its `id_short` + :param id_short: id_short :raises KeyError: If no such :class:`~.Referable` can be found """ - for dict_ in self.namespace_element_sets: - if id_short in dict_: - return dict_.remove(id_short) - raise KeyError("Referable with id_short {} not found in this namespace".format(id_short)) + return super()._remove_object(Referable, "id_short", id_short) + + def __iter__(self) -> Iterator[Referable]: + namespace_set_list: List[NamespaceSet] = [] + for namespace_set in self.namespace_element_sets: + if len(namespace_set) == 0: + namespace_set_list.append(namespace_set) + continue + if "id_short" in namespace_set.get_attribute_name_list(): + namespace_set_list.append(namespace_set) + return itertools.chain.from_iterable(namespace_set_list) + + +class UniqueSemanticIdNamespace(Namespace, metaclass=abc.ABCMeta): + """ + Abstract baseclass for all objects which form a Namespace to hold HasSemantics objects and resolve them by their + their semantic_id. + + A Namespace can contain multiple NamespaceSets, which contain HasSemantics objects of different types. However, the + the semantic_id of each object must be unique across all NamespaceSets of one Namespace. + + :ivar namespace_element_sets: A list of all NamespaceSets of this Namespace + """ + @abc.abstractmethod + def __init__(self) -> None: + super().__init__() + self.namespace_element_sets: List[NamespaceSet] = [] + + def get_object_by_semantic_id(self, semantic_id: Reference) -> HasSemantics: + """ + Find an HasSemantics in this Namespaces by its semantic_id + + :raises KeyError: If no such HasSemantics can be found + """ + return super()._get_object(HasSemantics, "semantic_id", semantic_id) # type: ignore + + def remove_object_by_semantic_id(self, semantic_id: Reference) -> None: + """ + Remove an HasSemantics from this Namespace by its semantic_id + + :raises KeyError: If no such HasSemantics can be found + """ + return super()._remove_object(HasSemantics, "semantic_id", semantic_id) + - def __iter__(self) -> Iterator[_RT]: - return itertools.chain.from_iterable(self.namespace_element_sets) +ATTRIBUTE_TYPES = Union[NameType, Reference, QualifierType] +# TODO: Find a better solution for providing constraint ids +ATTRIBUTES_CONSTRAINT_IDS = { + "id_short": 22, # Referable, + "type": 21, # Qualifier, + "name": 77, # Extension, + # "id_short": 134, # model.OperationVariable +} -class NamespaceSet(MutableSet[_RT], Generic[_RT]): + +class NamespaceSet(MutableSet[_NSO], Generic[_NSO]): """ - Helper class for storing :class:`~.Referable` objects of a given type in a :class:`~.Namespace` and find them by - their `id_short`. + Helper class for storing AAS objects of a given type in a Namespace and find them by their unique attribute. - This class behaves much like a set of :class:`~.Referable` objects of a defined type, but uses a dict internally to - rapidly - find those objects by their `id_short`. Additionally, it manages the `parent` attribute of the stored - :class:`Referables <~.Referable>` and - ensures the uniqueness of their id_short within the :class:`~.Namespace`. + This class behaves much like a set of AAS objects of a defined type, but uses dicts internally to rapidly + find those objects by their unique attribute. Additionally, it manages the `parent` attribute of the stored + AAS objects and ensures the uniqueness of their attribute within the Namespace. Use `add()`, `remove()`, `pop()`, `discard()`, `clear()`, `len()`, `x in` checks and iteration just like on a - normal set of :class:`Referables <~.Referable>`. To get a :class:`~.Referable` by its `id_short`, use - `get_referable()` or `get()` (the latter one + normal set of AAS objects. To get an AAS object by its attribute, use `get_object()` or `get()` (the latter one allows a default argument and returns None instead of raising a KeyError). As a bonus, the `x in` check supports - checking for existence of id_short *or* a concrete :class:`~.Referable` object. + checking for existence of attribute *or* a concrete AAS object. + + :ivar parent: The Namespace this set belongs to + + To initialize, use the following parameters: + + :param parent: The Namespace this set belongs to + :param attribute_names: List of attribute names, for which objects should be unique in the set. The bool flag + indicates if the attribute should be matched case-sensitive (true) or case-insensitive (false) + :param items: A given list of AAS items to be added to the set + + :raises KeyError: When `items` contains multiple objects with same unique attribute """ - def __init__(self, parent: Namespace, items: Iterable[_RT] = ()) -> None: + def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespace, Qualifiable, HasExtension], + attribute_names: List[Tuple[str, bool]], items: Iterable[_NSO] = (), + item_add_hook: Optional[Callable[[_NSO, Iterable[_NSO]], None]] = None, + item_id_set_hook: Optional[Callable[[_NSO], None]] = None, + item_id_del_hook: Optional[Callable[[_NSO], None]] = None) -> None: """ Initialize a new NamespaceSet. @@ -1029,12 +1814,28 @@ def __init__(self, parent: Namespace, items: Iterable[_RT] = ()) -> None: Namespace. :param parent: The Namespace this set belongs to - :param items: A given list of Referable items to be added to the set - :raises KeyError: When `items` contains multiple objects with same id_short + :attribute_names: List of attribute names, for which objects should be unique in the set. The bool flag + indicates if the attribute should be matched case-sensitive (true) or case-insensitive (false) + :param items: A given list of AAS items to be added to the set + :param item_add_hook: A function that is called for each item that is added to this NamespaceSet, even when + it is initialized. The first parameter is the item that is added while the second is + an iterator over all currently contained items. Useful for constraint checking. + :param item_id_set_hook: A function called to calculate the identifying attribute (e.g. id_short) of an object + on-the-fly when it is added. Used for the SubmodelElementList implementation. + :param item_id_del_hook: A function that is called for each item removed from this NamespaceSet. Used in + SubmodelElementList to unset id_shorts on removal. Should not be used for + constraint checking, as the hook is called after removal. + :raises AASConstraintViolation: When `items` contains multiple objects with same unique attribute or when an + item doesn't has an identifying attribute """ self.parent = parent parent.namespace_element_sets.append(self) - self._backend: Dict[str, _RT] = {} + self._backend: Dict[str, Tuple[Dict[ATTRIBUTE_TYPES, _NSO], bool]] = {} + self._item_add_hook: Optional[Callable[[_NSO, Iterable[_NSO]], None]] = item_add_hook + self._item_id_set_hook: Optional[Callable[[_NSO], None]] = item_id_set_hook + self._item_id_del_hook: Optional[Callable[[_NSO], None]] = item_id_del_hook + for name, case_sensitive in attribute_names: + self._backend[name] = ({}, case_sensitive) try: for i in items: self.add(i) @@ -1043,76 +1844,156 @@ def __init__(self, parent: Namespace, items: Iterable[_RT] = ()) -> None: self.clear() raise - def __contains__(self, x: object) -> bool: - if isinstance(x, str): - return x in self._backend - elif isinstance(x, Referable): - return self._backend.get(x.id_short) is x - else: + @staticmethod + def _get_attribute(x: object, attr_name: str, case_sensitive: bool): + attr_value = getattr(x, attr_name) + return attr_value if case_sensitive or not isinstance(attr_value, str) else attr_value.upper() + + def get_attribute_name_list(self) -> List[str]: + return list(self._backend.keys()) + + def contains_id(self, attribute_name: str, identifier: ATTRIBUTE_TYPES) -> bool: + try: + backend, case_sensitive = self._backend[attribute_name] + except KeyError: + return False + # if the identifier is not a string we ignore the case sensitivity + if case_sensitive or not isinstance(identifier, str): + return identifier in backend + return identifier.upper() in backend + + def __contains__(self, obj: object) -> bool: + attr_name = next(iter(self._backend)) + try: + attr_value = self._get_attribute(obj, attr_name, self._backend[attr_name][1]) + except AttributeError: return False + return self._backend[attr_name][0].get(attr_value) is obj def __len__(self) -> int: - return len(self._backend) + return len(next(iter(self._backend.values()))[0]) - def __iter__(self) -> Iterator[_RT]: - return iter(self._backend.values()) + def __iter__(self) -> Iterator[_NSO]: + return iter(next(iter(self._backend.values()))[0].values()) - def add(self, value: _RT): - for set_ in self.parent.namespace_element_sets: - if value.id_short in set_: - raise KeyError("Referable with id_short '{}' is already present in {}" - .format(value.id_short, - "this set of objects" - if set_ is self else "another set in the same namespace")) - if value.parent is not None and value.parent is not self.parent: - raise ValueError("Object has already a parent, but it must not be part of two namespaces.") + def add(self, element: _NSO): + if element.parent is not None and element.parent is not self.parent: + raise ValueError("Object has already a parent; it cannot belong to two namespaces.") # TODO remove from current parent instead (allow moving)? - value.parent = self.parent - self._backend[value.id_short] = value - def remove(self, item: Union[str, _RT]): - if isinstance(item, str): - del self._backend[item] - else: - item_in_dict = self._backend[item.id_short] - if item_in_dict is not item: - raise KeyError("Item not found in NamespaceDict (other item with same id_short exists)") - item.parent = None - del self._backend[item.id_short] + self._execute_item_id_set_hook(element) + self._validate_namespace_constraints(element) + self._execute_item_add_hook(element) - def discard(self, x: _RT) -> None: + element.parent = self.parent + for key_attr_name, (backend, case_sensitive) in self._backend.items(): + backend[self._get_attribute(element, key_attr_name, case_sensitive)] = element + + def _validate_namespace_constraints(self, element: _NSO): + for set_ in self.parent.namespace_element_sets: + for key_attr_name, (backend_dict, case_sensitive) in set_._backend.items(): + if hasattr(element, key_attr_name): + key_attr_value = self._get_attribute(element, key_attr_name, case_sensitive) + self._check_attr_is_not_none(element, key_attr_name, key_attr_value) + self._check_value_is_not_in_backend(element, key_attr_name, key_attr_value, backend_dict, set_) + + def _check_attr_is_not_none(self, element: _NSO, attr_name: str, attr): + if attr is None: + if attr_name == "id_short": + raise AASConstraintViolation(117, f"{element!r} has attribute {attr_name}=None, " + f"which is not allowed within a {self.parent.__class__.__name__}!") + else: + raise ValueError(f"{element!r} has attribute {attr_name}=None, which is not allowed!") + + def _check_value_is_not_in_backend(self, element: _NSO, attr_name: str, attr, + backend_dict: Dict[ATTRIBUTE_TYPES, _NSO], set_: "NamespaceSet"): + if attr in backend_dict: + if set_ is self: + text = f"Object with attribute (name='{attr_name}', value='{getattr(element, attr_name)}') " \ + f"is already present in this set of objects" + else: + text = f"Object with attribute (name='{attr_name}', value='{getattr(element, attr_name)}') " \ + f"is already present in another set in the same namespace" + raise AASConstraintViolation(ATTRIBUTES_CONSTRAINT_IDS.get(attr_name, 0), text) + + def _execute_item_id_set_hook(self, element: _NSO): + if self._item_id_set_hook is not None: + self._item_id_set_hook(element) + + def _execute_item_add_hook(self, element: _NSO): + if self._item_add_hook is not None: + try: + self._item_add_hook(element, self.__iter__()) + except Exception as e: + self._execute_item_del_hook(element) + raise + + def _execute_item_del_hook(self, element: _NSO): + # parent needs to be unset first, otherwise generated id_shorts cannot be unset + # see SubmodelElementList + if hasattr(element, "parent"): + element.parent = None + if self._item_id_del_hook is not None: + self._item_id_del_hook(element) + + def remove_by_id(self, attribute_name: str, identifier: ATTRIBUTE_TYPES) -> None: + item = self.get_object_by_attribute(attribute_name, identifier) + self.remove(item) + + def remove(self, item: _NSO) -> None: + item_found = False + for key_attr_name, (backend_dict, case_sensitive) in self._backend.items(): + key_attr_value = self._get_attribute(item, key_attr_name, case_sensitive) + if backend_dict[key_attr_value] is item: + # item has to be removed from backend before _item_del_hook() is called, + # as the hook may unset the id_short, as in SubmodelElementLists + del backend_dict[key_attr_value] + item_found = True + if not item_found: + raise KeyError("Object not found in NamespaceDict") + self._execute_item_del_hook(item) + + def discard(self, x: _NSO) -> None: if x not in self: return self.remove(x) - def pop(self) -> _RT: - _, value = self._backend.popitem() + def pop(self) -> _NSO: + _, value = next(iter(self._backend.values()))[0].popitem() + self._execute_item_del_hook(value) value.parent = None return value def clear(self) -> None: - for value in self._backend.values(): - value.parent = None - self._backend.clear() + for attr_name, (backend, case_sensitive) in self._backend.items(): + for value in backend.values(): + self._execute_item_del_hook(value) + for attr_name, (backend, case_sensitive) in self._backend.items(): + backend.clear() - def get_referable(self, key) -> _RT: + def get_object_by_attribute(self, attribute_name: str, attribute_value: ATTRIBUTE_TYPES) -> _NSO: """ - Find an object in this set by its `id_short` + Find an object in this set by its unique attribute :raises KeyError: If no such object can be found """ - return self._backend[key] + backend, case_sensitive = self._backend[attribute_name] + return backend[attribute_value if case_sensitive else attribute_value.upper()] # type: ignore - def get(self, key, default: Optional[_RT] = None) -> Optional[_RT]: + def get(self, attribute_name: str, attribute_value: str, default: Optional[_NSO] = None) -> Optional[_NSO]: """ - Find an object in this set by its `id_short`, with fallback parameter + Find an object in this set by its attribute, with fallback parameter - :param default: An object to be returned, if no object with the given id_short is found - :return: The :class:`~.Referable` object with the given id_short in the set. Otherwise the `default` object or - None, if none is given. + :param attribute_name: name of the attribute to search for + :param attribute_value: value of the attribute to search for + :param default: An object to be returned, if no object with the given attribute is found + :return: The AAS object with the given attribute in the set. Otherwise the `default` object or None, if + none is given. """ - return self._backend.get(key, default) + backend, case_sensitive = self._backend[attribute_name] + return backend.get(attribute_value if case_sensitive else attribute_value.upper(), default) + # Todo: Implement function including tests def update_nss_from(self, other: "NamespaceSet"): """ Update a NamespaceSet from a given NamespaceSet. @@ -1121,37 +2002,55 @@ def update_nss_from(self, other: "NamespaceSet"): :param other: The NamespaceSet to update from """ - referables_to_add: List[Referable] = [] # objects from the other nss to add to self - referables_to_remove: List[Referable] = [] # objects to remove from self - for other_referable in other: + objects_to_add: List[_NSO] = [] # objects from the other nss to add to self + objects_to_remove: List[_NSO] = [] # objects to remove from self + for other_object in other: try: - referable = self._backend[other_referable.id_short] - if type(referable) is type(other_referable): - # referable is the same as other referable - referable.update_from(other_referable, update_source=True) + if isinstance(other_object, Referable): + backend, case_sensitive = self._backend["id_short"] + referable = backend[other_object.id_short if case_sensitive else other_object.id_short.upper()] + referable.update_from(other_object, update_source=True) # type: ignore + elif isinstance(other_object, Qualifier): + backend, case_sensitive = self._backend["type"] + qualifier = backend[other_object.type if case_sensitive else other_object.type.upper()] + # qualifier.update_from(other_object, update_source=True) # TODO: What should happend here? + elif isinstance(other_object, Extension): + backend, case_sensitive = self._backend["name"] + extension = backend[other_object.name if case_sensitive else other_object.name.upper()] + # extension.update_from(other_object, update_source=True) # TODO: What should happend here? + else: + raise TypeError("Type not implemented") except KeyError: - # other referable is not in NamespaceSet - referables_to_add.append(other_referable) - for id_short, referable in self._backend.items(): - if not other.get(id_short): - # referable does not exist in the other NamespaceSet - referables_to_remove.append(referable) - for referable_to_add in referables_to_add: - other.remove(referable_to_add) - self.add(referable_to_add) # type: ignore - for referable_to_remove in referables_to_remove: - self.remove(referable_to_remove) # type: ignore - - -class OrderedNamespaceSet(NamespaceSet[_RT], MutableSequence[_RT], Generic[_RT]): + # other object is not in NamespaceSet + objects_to_add.append(other_object) + for attr_name, (backend, case_sensitive) in self._backend.items(): + for attr_name_other, (backend_other, case_sensitive_other) in other._backend.items(): + if attr_name is attr_name_other: + for item in backend.values(): + if not backend_other.get(self._get_attribute(item, attr_name, case_sensitive)): + # referable does not exist in the other NamespaceSet + objects_to_remove.append(item) + for object_to_add in objects_to_add: + other.remove(object_to_add) + self.add(object_to_add) # type: ignore + for object_to_remove in objects_to_remove: + self.remove(object_to_remove) # type: ignore + + +class OrderedNamespaceSet(NamespaceSet[_NSO], MutableSequence[_NSO], Generic[_NSO]): """ A specialized version of :class:`~.NamespaceSet`, that keeps track of the order of the stored :class:`~.Referable` objects. - Additionally to the MutableSet interface of NamespaceSet, this class provides a set-like interface (actually it - is derived from MutableSequence). However, we don't permit duplicate entries in the ordered list of objects. + Additionally to the MutableSet interface of :class:`~.NamespaceSet`, this class provides a set-like interface + (actually it is derived from MutableSequence). However, we don't permit duplicate entries in the ordered list of + objects. """ - def __init__(self, parent: Namespace, items: Iterable[_RT] = ()) -> None: + def __init__(self, parent: Union[UniqueIdShortNamespace, UniqueSemanticIdNamespace, Qualifiable, HasExtension], + attribute_names: List[Tuple[str, bool]], items: Iterable[_NSO] = (), + item_add_hook: Optional[Callable[[_NSO, Iterable[_NSO]], None]] = None, + item_id_set_hook: Optional[Callable[[_NSO], None]] = None, + item_id_del_hook: Optional[Callable[[_NSO], None]] = None) -> None: """ Initialize a new OrderedNamespaceSet. @@ -1159,26 +2058,37 @@ def __init__(self, parent: Namespace, items: Iterable[_RT] = ()) -> None: Namespace. :param parent: The Namespace this set belongs to + :attribute_names: Dict of attribute names, for which objects should be unique in the set. The bool flag + indicates if the attribute should be matched case-sensitive (true) or case-insensitive (false) :param items: A given list of Referable items to be added to the set - :raises KeyError: When `items` contains multiple objects with same id_short + :param item_add_hook: A function that is called for each item that is added to this NamespaceSet, even when + it is initialized. The first parameter is the item that is added while the second is + an iterator over all currently contained items. Useful for constraint checking. + :param item_id_set_hook: A function called to calculate the identifying attribute (e.g. id_short) of an object + on-the-fly when it is added. Used for the SubmodelElementList implementation. + :param item_id_del_hook: A function that is called for each item removed from this NamespaceSet. Used in + SubmodelElementList to unset id_shorts on removal. Should not be used for + constraint checking, as the hook is called after removal. + :raises AASConstraintViolation: When `items` contains multiple objects with same unique attribute or when an + item doesn't has an identifying attribute """ - self._order: List[_RT] = [] - super().__init__(parent, items) + self._order: List[_NSO] = [] + super().__init__(parent, attribute_names, items, item_add_hook, item_id_set_hook, item_id_del_hook) - def __iter__(self) -> Iterator[_RT]: + def __iter__(self) -> Iterator[_NSO]: return iter(self._order) - def add(self, value: _RT): - super().add(value) - self._order.append(value) + def add(self, element: _NSO): + super().add(element) + self._order.append(element) - def remove(self, item: Union[str, _RT]): - if isinstance(item, str): - item = self.get_referable(item) + def remove(self, item: Union[Tuple[str, ATTRIBUTE_TYPES], _NSO]): + if isinstance(item, tuple): + item = self.get_object_by_attribute(item[0], item[1]) super().remove(item) self._order.remove(item) - def pop(self, i: Optional[int] = None): + def pop(self, i: Optional[int] = None) -> _NSO: if i is None: value = super().pop() self._order.remove(value) @@ -1191,24 +2101,24 @@ def clear(self) -> None: super().clear() self._order.clear() - def insert(self, index: int, object_: _RT) -> None: + def insert(self, index: int, object_: _NSO) -> None: super().add(object_) self._order.insert(index, object_) @overload - def __getitem__(self, i: int) -> _RT: ... + def __getitem__(self, i: int) -> _NSO: ... @overload - def __getitem__(self, s: slice) -> MutableSequence[_RT]: ... + def __getitem__(self, s: slice) -> MutableSequence[_NSO]: ... - def __getitem__(self, s: Union[int, slice]) -> Union[_RT, MutableSequence[_RT]]: + def __getitem__(self, s: Union[int, slice]) -> Union[_NSO, MutableSequence[_NSO]]: return self._order[s] @overload - def __setitem__(self, i: int, o: _RT) -> None: ... + def __setitem__(self, i: int, o: _NSO) -> None: ... @overload - def __setitem__(self, s: slice, o: Iterable[_RT]) -> None: ... + def __setitem__(self, s: slice, o: Iterable[_NSO]) -> None: ... def __setitem__(self, s, o) -> None: if isinstance(s, int): @@ -1244,3 +2154,245 @@ def __delitem__(self, i: Union[int, slice]) -> None: for o in self._order[i]: super().remove(o) del self._order[i] + + +class SpecificAssetId(HasSemantics): + """ + A specific asset ID describes a generic supplementary identifying attribute of the asset. + The specific asset ID is not necessarily globally unique. + + *Constraint AASd-133:* SpecificAssetId/externalSubjectId shall be a global reference, + i.e. Reference/type = ExternalReference + + :ivar name: Key of the identifier + :ivar value: The value of the identifier with the corresponding key. + :ivar external_subject_id: The (external) subject the key belongs to or has meaning to. + :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + """ + + def __init__(self, + name: LabelType, + value: Identifier, + external_subject_id: Optional[ExternalReference] = None, + semantic_id: Optional[Reference] = None, + supplemental_semantic_id: Iterable[Reference] = ()): + super().__init__() + if value == "": + raise ValueError("value is not allowed to be an empty string") + _string_constraints.check_label_type(name) + _string_constraints.check_identifier(value) + self.name: LabelType + self.value: Identifier + self.external_subject_id: ExternalReference + + super().__setattr__('name', name) + super().__setattr__('value', value) + super().__setattr__('external_subject_id', external_subject_id) + super().__setattr__('semantic_id', semantic_id) + super().__setattr__('supplemental_semantic_id', supplemental_semantic_id) + + def __setattr__(self, key, value): + """Prevent modification of attributes.""" + # Hack to make the HasSemantics inheritance work + # HasSemantics.__init__ sets the parent attribute to None, so that has to be possible. It needs to be set + # because its value is checked in the semantic_id setter and since every subclass of HasSemantics is expected + # to have this attribute. Additionally, the protected _semantic_id attribute must be settable. + if key == '_semantic_id' or key == '_supplemental_semantic_id' or (key == 'parent' and value is None): + return super(HasSemantics, self).__setattr__(key, value) + raise AttributeError('SpecificAssetId is immutable') + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SpecificAssetId): + return NotImplemented + return (self.name == other.name + and self.value == other.value + and self.external_subject_id == other.external_subject_id + and self.semantic_id == other.semantic_id + and self.supplemental_semantic_id == other.supplemental_semantic_id) + + def __hash__(self): + return hash((self.name, self.value, self.external_subject_id)) + + def __repr__(self) -> str: + return "SpecificAssetId(key={}, value={}, external_subject_id={}, " \ + "semantic_id={}, supplemental_semantic_id={})".format( + self.name, self.value, self.external_subject_id, self.semantic_id, + self.supplemental_semantic_id) + + +class AASConstraintViolation(Exception): + """ + An Exception to be raised if an AASd-Constraint defined in the metamodel (Details of the Asset Administration Shell) + is violated + + :ivar constraint_id: The ID of the constraint that is violated + :ivar message: The error message of the Exception + """ + def __init__(self, constraint_id: int, message: str): + self.constraint_id: int = constraint_id + self.message: str = message + " (Constraint AASd-" + str(constraint_id).zfill(3) + ")" + super().__init__(self.message) + + +@unique +class DataTypeIEC61360(Enum): + """ + Data types for data_type in :class:`DataSpecificationIEC61360 <.IEC61360ConceptDescription>` + The data types are: + + :cvar DATE: + :cvar STRING: + :cvar STRING_TRANSLATABLE: + :cvar INTEGER_MEASURE: + :cvar INTEGER_COUNT: + :cvar INTEGER_CURRENCY: + :cvar REAL_MEASURE: + :cvar REAL_COUNT: + :cvar REAL_CURRENCY: + :cvar BOOLEAN: + :cvar IRI: + :cvar IRDI: + :cvar RATIONAL: + :cvar RATIONAL_MEASURE: + :cvar TIME: + :cvar TIMESTAMP: + :cvar HTML: + :cvar BLOB: + :cvar FILE: + """ + DATE = 0 + STRING = 1 + STRING_TRANSLATABLE = 2 + INTEGER_MEASURE = 3 + INTEGER_COUNT = 4 + INTEGER_CURRENCY = 5 + REAL_MEASURE = 6 + REAL_COUNT = 7 + REAL_CURRENCY = 8 + BOOLEAN = 9 + IRI = 10 + IRDI = 11 + RATIONAL = 12 + RATIONAL_MEASURE = 13 + TIME = 14 + TIMESTAMP = 15 + HTML = 16 + BLOB = 17 + FILE = 18 + + +@unique +class IEC61360LevelType(Enum): + """ + Level types for the level_type in :class:`DataSpecificationIEC61360 <.IEC61360ConceptDescription>` + The level types are: + + :cvar MIN: + :cvar MAX: + :cvar NOM: + :cvar TYP: + """ + MIN = 0 + MAX = 1 + NOM = 2 + TYP = 3 + + +@_string_constraints.constrain_value_type_iec61360("value") +class DataSpecificationIEC61360(DataSpecificationContent): + """ + A specialized :class:`~.DataSpecificationContent` to define specs according to IEC61360 + + :ivar preferred_name: Preferred name of the data object + :ivar short_name: Short name of the data object + :ivar data_type: Data type of the data object + :ivar definition: Definition of the data object + :ivar parent: Reference to the next referable parent element of the element. + (inherited from :class:`~aas.model.base.Referable`) + :ivar unit: Optional unit of the data object + :ivar unit_id: Optional reference to a unit id + :ivar source_of_definition: Optional source of the definition + :ivar symbol: Optional unit symbol + :ivar value_format: Optional format of the values + :ivar value_list: Optional list of values + :ivar value: Optional value data type object + :ivar level_types: Optional set of level types of the DataSpecificationContent + """ + def __init__(self, + preferred_name: PreferredNameTypeIEC61360, + data_type: Optional[DataTypeIEC61360] = None, + definition: Optional[DefinitionTypeIEC61360] = None, + short_name: Optional[ShortNameTypeIEC61360] = None, + unit: Optional[str] = None, + unit_id: Optional[Reference] = None, + source_of_definition: Optional[str] = None, + symbol: Optional[str] = None, + value_format: Optional[str] = None, + value_list: Optional[ValueList] = None, + value: Optional[ValueTypeIEC61360] = None, + level_types: Iterable[IEC61360LevelType] = ()): + + super().__init__() + self.preferred_name: PreferredNameTypeIEC61360 = preferred_name + self.short_name: Optional[ShortNameTypeIEC61360] = short_name + self.data_type: Optional[DataTypeIEC61360] = data_type + self.definition: Optional[DefinitionTypeIEC61360] = definition + self._unit: Optional[str] = unit + self.unit_id: Optional[Reference] = unit_id + self._source_of_definition: Optional[str] = source_of_definition + self._symbol: Optional[str] = symbol + self.value_list: Optional[ValueList] = value_list + self.level_types: Set[IEC61360LevelType] = set(level_types) + self.value_format: Optional[str] = value_format + self.value: Optional[ValueTypeIEC61360] = value + + def _set_unit(self, unit: Optional[str]): + """ + Check the input string + + :param unit: unit of the data object (optional) + :raises ValueError: if the constraint is not fulfilled + """ + self._unit = unit + + def _get_unit(self): + return self._unit + + unit = property(_get_unit, _set_unit) + + def _set_source_of_definition(self, source_of_definition: Optional[str]): + """ + Check the input string + + :param source_of_definition: source of the definition (optional) + :raises ValueError: if the constraint is not fulfilled + """ + self._source_of_definition = source_of_definition + + def _get_source_of_definition(self): + return self._source_of_definition + + source_of_definition = property(_get_source_of_definition, _set_source_of_definition) + + def _set_symbol(self, symbol: Optional[str]): + """ + Check the input string + + :param symbol: unit symbol (optional) + :raises ValueError: if the constraint is not fulfilled + """ + self._symbol = symbol + + def _get_symbol(self): + return self._symbol + + symbol = property(_get_symbol, _set_symbol) + + def __repr__(self): + return f"DataSpecificationIEC61360[unit={self.unit}]" diff --git a/basyx/aas/model/concept.py b/basyx/aas/model/concept.py index 0071fec8e..89a8e9b83 100644 --- a/basyx/aas/model/concept.py +++ b/basyx/aas/model/concept.py @@ -5,202 +5,91 @@ # # SPDX-License-Identifier: MIT """ -This module contains the classes :class:`~.ConceptDescription` and :class:`~.ConceptDictionary` from the AAS meta model -as well as specialized ConceptDescriptions like :class:`~.IEC61360ConceptDescription`. +This module contains the class :class:`~.ConceptDescription` from the AAS meta model +as well as specialized :class:`ConceptDescriptions <.ConceptDescription>` like :class:`~.IEC61360ConceptDescription`. """ -from enum import unique, Enum -from typing import Optional, Set, Type - -from . import base, datatypes - - -class ConceptDescription(base.Identifiable): +from typing import Optional, Set, Iterable, List + +from . import base + +ALLOWED_CONCEPT_DESCRIPTION_CATEGORIES: Set[str] = { + "VALUE", + "PROPERTY", + "REFERENCE", + "DOCUMENT", + "CAPABILITY", + "RELATIONSHIP", + "COLLECTION", + "FUNCTION", + "EVENT", + "ENTITY", + "APPLICATION_CLASS", + "QUALIFIER" +} + + +class ConceptDescription(base.Identifiable, base.HasDataSpecification): """ The semantics of a :class:`~.Property` or other elements that may have a semantic description is defined by a concept description. The description of the concept should follow a standardized schema (realized as data specification template). - :ivar ~.identification: The globally unique identification of the element. - (inherited from :class:`~aas.model.base.Identifiable`) + *Note:* Compare :attr:`~.ConceptDescription.is_case_of` to is-case-of relationship in ISO 13584-32 & IEC EN 61360 + + :ivar ~.id: The globally unique id of the element. (inherited from + :class:`~aas.model.base.Identifiable`) :ivar is_case_of: Unordered list of global :class:`References ` to external definitions - the concept is compatible to or was derived from. - *Note:* Compare to is-case-of relationship in ISO 13584-32 & IEC EN 61360 - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + the concept is compatible to or was derived from. + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next :class:`~aas.model.base.Referable` parent element of - the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar administration: Administrative information of an :class:`~aas.model.base.Identifiable` element. - (inherited from :class:`~aas.model.base.Identifiable`) - """ + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) + :ivar administration: Administrative information of an identifiable element. (inherited from + :class:`~aas.model.base.Identifiable`) + :ivar embedded_data_specifications: List of Embedded data specification. + :ivar extension: An extension of the element. (from + :class:`~aas.model.base.HasExtension`) +""" def __init__(self, - identification: base.Identifier, + id_: base.Identifier, is_case_of: Optional[Set[base.Reference]] = None, - id_short: str = "", - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, - administration: Optional[base.AdministrativeInformation] = None): + id_short: Optional[base.NameType] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, + administration: Optional[base.AdministrativeInformation] = None, + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] + = (), + extension: Iterable[base.Extension] = ()): + super().__init__() - self.identification: base.Identifier = identification + self.id: base.Identifier = id_ self.is_case_of: Set[base.Reference] = set() if is_case_of is None else is_case_of self.id_short = id_short - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent + self.display_name: Optional[base.MultiLanguageNameType] = display_name + self.category = category + self.description: Optional[base.MultiLanguageTextType] = description + self.parent: Optional[base.UniqueIdShortNamespace] = parent self.administration: Optional[base.AdministrativeInformation] = administration + self.embedded_data_specifications: List[base.EmbeddedDataSpecification] = list(embedded_data_specifications) + self.extension = base.NamespaceSet(self, [("name", True)], extension) - -class ConceptDictionary(base.Referable): - """ - A dictionary containing :class:`ConceptDescriptions <.ConceptDescription>`. - - Typically a concept description dictionary of an AAS contains only concept descriptions of elements used within - submodels of the AAS. - - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) - :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next :class:`~aas.model.base.Referable` parent element of - the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar concept_description: Unordered list of :class:`References ` to elements of class - :class:`~.ConceptDescription` - """ - def __init__(self, - id_short: str, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, - concept_description: Optional[Set[base.AASReference[ConceptDescription]]] = None): - """ - TODO: Add instruction what to do after construction - """ - super().__init__() - self.id_short = id_short - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent - self.concept_description: Set[base.AASReference[ConceptDescription]] = \ - set() if concept_description is None else concept_description - - -# ############################################################################# -# Helper types for -@unique -class IEC61360DataType(Enum): - """ - Data types for data_type in DataSpecificationIEC61360 - """ - DATE = 0 - STRING = 1 - STRING_TRANSLATABLE = 2 - REAL_MEASURE = 3 - REAL_COUNT = 4 - REAL_CURRENCY = 5 - BOOLEAN = 6 - URL = 7 - RATIONAL = 8 - RATIONAL_MEASURE = 9 - TIME = 10 - TIMESTAMP = 11 - - -@unique -class IEC61360LevelType(Enum): - """ - Level types for the level_type in DataSpecificationIEC61360 - """ - MIN = 0 - MAX = 1 - NOM = 2 - TYP = 3 - - -class IEC61360ConceptDescription(ConceptDescription): - """ - A specialized :class:`~.ConceptDescription` to define concepts according to IEC61360 - - :ivar ~.identification: The globally unique identification of the element. - (inherited from :class:`~aas.model.base.Identifiable`) - :ivar preferred_name: Preferred of the data object - :ivar data_type: Data type of the data object - :ivar definition: Definition of the data object - :ivar short_name: Short name of the data object - :ivar is_case_of: Unordered list of global :class:`References ` to external definitions - the concept is compatible to or was derived from. - *Note:* Compare to is-case-of relationship in ISO 13584-32 & IEC EN 61360 - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) - :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next :class:`~aas.model.base.Referable` parent element of - the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar administration: Administrative information of an :class:`~aas.model.base.Identifiable` element. - (inherited from :class:`~aas.model.base.Identifiable`) - :ivar unit_id: Reference to a unit id (optional) - :ivar source_of_definition: Source of the definition (optional) - :ivar symbol: Unit symbol (optional) - :ivar value_format: Format of the values (optional) - :ivar value_list: List of values (optional) - :ivar value: Value data type object (optional) - :ivar value_id: :class:`~aas.model.base.Reference` to the value (optional) - :ivar level_types: Set of level types of the DataSpecificationContent (optional) - """ - def __init__(self, - identification: base.Identifier, - preferred_name: base.LangStringSet, - data_type: Optional[IEC61360DataType] = None, - definition: Optional[base.LangStringSet] = None, - short_name: Optional[base.LangStringSet] = None, - is_case_of: Optional[Set[base.Reference]] = None, - id_short: str = "", - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, - administration: Optional[base.AdministrativeInformation] = None, - unit: Optional[str] = None, - unit_id: Optional[base.Reference] = None, - source_of_definition: Optional[str] = None, - symbol: Optional[str] = None, - value_format: Optional[base.DataTypeDef] = None, - value_list: Optional[base.ValueList] = None, - value: Optional[base.ValueDataType] = None, - value_id: Optional[base.Reference] = None, - level_types: Optional[Set[IEC61360LevelType]] = None, - ): - super().__init__(identification, is_case_of, id_short, category, description, parent, administration) - self.preferred_name: base.LangStringSet = preferred_name - self.short_name: Optional[base.LangStringSet] = short_name - self.data_type: Optional[IEC61360DataType] = data_type - self.definition: Optional[base.LangStringSet] = definition - self.unit: Optional[str] = unit - self.unit_id: Optional[base.Reference] = unit_id - self.source_of_definition: Optional[str] = source_of_definition - self.symbol: Optional[str] = symbol - self.value_list: Optional[base.ValueList] = value_list - self.value_id: Optional[base.Reference] = value_id - self.level_types: Set[IEC61360LevelType] = level_types if level_types else set() - self.value_format: Optional[Type[datatypes.AnyXSDType]] = value_format - self._value: Optional[base.ValueDataType] = (datatypes.trivial_cast(value, self.value_format) - if (value is not None and self.value_format is not None) else None) - - @property - def value(self): - return self._value - - @value.setter - def value(self, value) -> None: - if value is None or self.value_format is None: - self._value = None + def _set_category(self, category: Optional[str]): + if category is None: + self._category = "PROPERTY" else: - self._value = datatypes.trivial_cast(value, self.value_format) + if category not in ALLOWED_CONCEPT_DESCRIPTION_CATEGORIES: + raise base.AASConstraintViolation( + 51, + "ConceptDescription must have one of the following " + "categories: " + str(ALLOWED_CONCEPT_DESCRIPTION_CATEGORIES) + ) + self._category = category diff --git a/basyx/aas/model/datatypes.py b/basyx/aas/model/datatypes.py index 0d02e25f3..f3960fa0e 100644 --- a/basyx/aas/model/datatypes.py +++ b/basyx/aas/model/datatypes.py @@ -8,8 +8,8 @@ This module defines native Python types for all simple built-in XSD datatypes, as well as functions to (de)serialize them from/into their lexical XML representation. -See https://www.w3.org/TR/xmlschema11-2/#built-in-datatypes for the XSD simple type hierarchy and more information on -the datatypes. All types from this type hierarchy (except for `token` and its descendants) are implemented or aliased in +See https://www.w3.org/TR/xmlschema-2/#built-in-datatypes for the XSD simple type hierarchy and more information on the +datatypes. All types from this type hierarchy (except for `token` and its descendants) are implemented or aliased in this module using their pythonized: Duration, DateTime, GMonthDay, String, Integer, Decimal, Short …. These types are meant to be used directly for data values in the context of Asset Administration Shells. @@ -19,13 +19,14 @@ * :meth:`~aas.model.datatypes.from_xsd` parses an XSD type from its lexical representation (its required to name the type for unambiguous conversion) * :meth:`~aas.model.datatypes.trivial_cast` type-cast a python value into an XSD type, if this is trivially possible. - Meant for fixing the type of Properties' values automatically, esp. for literal values. + Meant for fixing the type of :class:`Properties' ` values automatically, esp. for literal + values. """ import base64 import datetime import decimal import re -from typing import Type, TypeVar, Union, Dict, Optional +from typing import Type, Union, Dict, Optional import dateutil.relativedelta @@ -39,33 +40,6 @@ String = str -class DayTimeDuration(Duration): - """ - A duration without years and months. The class is not constrained by itself, the constraints are only checked on - serialization. - """ - pass - - -class YearMonthDuration(Duration): - """ - A duration with just years and months. The class is not constrained by itself, the constraints are only checked on - serialization. - """ - pass - - -class DateTimeStamp(DateTime): - """ - A variant of :class:`~DateTime` where the timezone is required. - """ - def __new__(cls, years, months=None, days=None, hours=0, minutes=0, seconds=0, microseconds=0, tzinfo=None, - **kwargs): - if tzinfo is None: - raise ValueError("A DateTimeStamp requires a timezone!") - return super().__new__(cls, years, months, days, hours, minutes, seconds, microseconds, tzinfo, **kwargs) - - class Date(datetime.date): __slots__ = '_tzinfo' @@ -375,18 +349,15 @@ def from_string(cls, value: str) -> "NormalizedString": AnyXSDType = Union[ - Duration, DayTimeDuration, YearMonthDuration, DateTime, DateTimeStamp, Date, Time, GYearMonth, GYear, GMonthDay, - GMonth, GDay, Boolean, Base64Binary, HexBinary, Float, Double, Decimal, Integer, Long, Int, Short, Byte, - NonPositiveInteger, NegativeInteger, NonNegativeInteger, PositiveInteger, UnsignedLong, UnsignedInt, UnsignedShort, - UnsignedByte, AnyURI, String, NormalizedString] + Duration, DateTime, Date, Time, GYearMonth, GYear, GMonthDay, GMonth, GDay, Boolean, Base64Binary, + HexBinary, Float, Double, Decimal, Integer, Long, Int, Short, Byte, NonPositiveInteger, NegativeInteger, + NonNegativeInteger, PositiveInteger, UnsignedLong, UnsignedInt, UnsignedShort, UnsignedByte, AnyURI, String, + NormalizedString] -XSD_TYPE_NAMES: Dict[Type[AnyXSDType], str] = { +XSD_TYPE_NAMES: Dict[Type[AnyXSDType], str] = {k: "xs:" + v for k, v in { Duration: "duration", - DayTimeDuration: "dayTimeDuration", - YearMonthDuration: "yearMonthDuration", DateTime: "dateTime", - DateTimeStamp: "dateTimeStamp", Date: "date", Time: "time", GYearMonth: "gYearMonth", @@ -415,7 +386,7 @@ def from_string(cls, value: str) -> "NormalizedString": AnyURI: "anyURI", String: "string", NormalizedString: "normalizedString", -} +}.items()} XSD_TYPE_CLASSES: Dict[str, Type[AnyXSDType]] = {v: k for k, v in XSD_TYPE_NAMES.items()} @@ -423,15 +394,16 @@ def trivial_cast(value, type_: Type[AnyXSDType]) -> AnyXSDType: # workaround. W """ Type-cast a python value into an XSD type, if this is a trivial conversion - The main purpose of this function is to allow AAS Properties (and similar objects with XSD-type values) to take - Python literal values and convert them to their XSD type. However, we want to stay strongly typed, so we only allow - this type-cast if it is trivial to do, i.e. does not change the value's semantics. Examples, where this holds true: + The main purpose of this function is to allow AAS :class:`Properties ` + (and similar objects with XSD-type values) to take Python literal values and convert them to their XSD type. + However, we want to stay strongly typed, so we only allow this type-cast if it is trivial to do, i.e. does not + change the value's semantics. Examples, where this holds true: - * int → datatypes.Int (if the value is in the expected range) - * bytes → datatypes.Base64Binary - * datetime.date → datatypes.Date + * int → :class:`aas.model.datatypes.Int` (if the value is in the expected range) + * bytes → :class:`aas.model.datatypes.Base64Binary` + * datetime.date → :class:`aas.model.datatypes.Date` - Yet, it is not allowed to cast float → datatypes.Integer. + Yet, it is not allowed to cast float → :class:`aas.model.datatypes.Int`. :param value: The value to cast :param type_: Target type to cast into. Must be an XSD type from this module @@ -451,6 +423,9 @@ def trivial_cast(value, type_: Type[AnyXSDType]) -> AnyXSDType: # workaround. W def xsd_repr(value: AnyXSDType) -> str: """ Serialize an XSD type value into it's lexical representation + + :param value: Any XSD type (from this module) + :returns: Lexical representation as string """ if isinstance(value, Duration): return _serialize_duration(value) @@ -509,13 +484,6 @@ def _serialize_duration(value: Duration) -> str: elif len(signs) == 0: return "P0D" - if isinstance(value, DayTimeDuration) and (value.years or value.months): - raise ValueError("{} doesn't allow the serialization of years and months!".format(value.__class__.__name__)) - - if isinstance(value, YearMonthDuration) and (value.days or value.hours or value.minutes or value.seconds - or value.microseconds): - raise ValueError("{} only allows the serialization of years and months!".format(value.__class__.__name__)) - result = "-" if signs.pop() else "" result += "P" if value.years: @@ -542,6 +510,7 @@ def from_xsd(value: str, type_: Type[AnyXSDType]) -> AnyXSDType: # workaround. """ Parse an XSD type value from its lexical representation + :param value: Lexical representation :param type_: The expected XSD type (from this module). It is required to chose the correct conversion. """ if type_ is Boolean: @@ -560,12 +529,8 @@ def from_xsd(value: str, type_: Type[AnyXSDType]) -> AnyXSDType: # workaround. raise ValueError(f"Cannot convert '{value}' to Decimal!") from e elif type_ is Duration: return _parse_xsd_duration(value) - elif type_ is YearMonthDuration: - return _parse_xsd_year_month_duration(value) - elif type_ is DayTimeDuration: - return _parse_xsd_day_time_duration(value) - elif issubclass(type_, DateTime): - return _parse_xsd_datetime(value, type_) + elif type_ is DateTime: + return _parse_xsd_datetime(value) elif type_ is Date: return _parse_xsd_date(value) elif type_ is Time: @@ -588,10 +553,7 @@ def from_xsd(value: str, type_: Type[AnyXSDType]) -> AnyXSDType: # workaround. DURATION_RE = re.compile(r'^(-?)P(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?((\d+)(\.\d+)?S)?)?$') -YEAR_MONTH_DURATION_RE = re.compile(r'^(-?)P(\d+Y)?(\d+M)?$') -DAY_TIME_DURATION_RE = re.compile(r'^(-?)P(\d+D)?(T(\d+H)?(\d+M)?((\d+)(\.\d+)?S)?)?$') DATETIME_RE = re.compile(r'^(-?)(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d+)?([+\-](\d\d):(\d\d)|Z)?$') -DATETIMESTAMP_RE = re.compile(r'^(-?)(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d+)?([+\-](\d\d):(\d\d)|Z)$') TIME_RE = re.compile(r'^(\d\d):(\d\d):(\d\d)(\.\d+)?([+\-](\d\d):(\d\d)|Z)?$') DATE_RE = re.compile(r'^(-?)(\d\d\d\d)-(\d\d)-(\d\d)([+\-](\d\d):(\d\d)|Z)?$') @@ -612,31 +574,6 @@ def _parse_xsd_duration(value: str) -> Duration: return res -def _parse_xsd_year_month_duration(value: str) -> YearMonthDuration: - match = YEAR_MONTH_DURATION_RE.match(value) - if not match: - raise ValueError("Value is not a valid XSD yearMonthDuration string") - res = YearMonthDuration(years=int(match[2][:-1]) if match[2] else 0, - months=int(match[3][:-1]) if match[3] else 0) - if match[1]: - res = -res - return res - - -def _parse_xsd_day_time_duration(value: str) -> DayTimeDuration: - match = DAY_TIME_DURATION_RE.match(value) - if not match: - raise ValueError("Value is not a valid XSD dayTimeDuraion string") - res = DayTimeDuration(days=int(match[2][:-1]) if match[2] else 0, - hours=int(match[4][:-1]) if match[4] else 0, - minutes=int(match[5][:-1]) if match[5] else 0, - seconds=int(match[7]) if match[6] else 0, - microseconds=int(float(match[8])*1e6) if match[8] else 0) - if match[1]: - res = -res - return res - - def _parse_xsd_date_tzinfo(value: str) -> Optional[datetime.tzinfo]: if not value: return None @@ -655,18 +592,15 @@ def _parse_xsd_date(value: str) -> Date: return Date(int(match[2]), int(match[3]), int(match[4]), _parse_xsd_date_tzinfo(match[5])) -_DT = TypeVar("_DT", bound=DateTime) - - -def _parse_xsd_datetime(value: str, type_: Type[_DT]) -> _DT: - match = (DATETIMESTAMP_RE if type_ is DateTimeStamp else DATETIME_RE).match(value) +def _parse_xsd_datetime(value: str) -> DateTime: + match = DATETIME_RE.match(value) if not match: - raise ValueError(f"Value is not a valid XSD {type_.__name__} string") + raise ValueError("Value is not a valid XSD datetime string") if match[1]: raise ValueError("Negative Dates are not supported by Python") microseconds = int(float(match[8]) * 1e6) if match[8] else 0 - return type_(int(match[2]), int(match[3]), int(match[4]), int(match[5]), int(match[6]), int(match[7]), - microseconds, _parse_xsd_date_tzinfo(match[9])) + return DateTime(int(match[2]), int(match[3]), int(match[4]), int(match[5]), int(match[6]), int(match[7]), + microseconds, _parse_xsd_date_tzinfo(match[9])) def _parse_xsd_time(value: str) -> Time: diff --git a/basyx/aas/model/provider.py b/basyx/aas/model/provider.py index a165ff620..311618fea 100644 --- a/basyx/aas/model/provider.py +++ b/basyx/aas/model/provider.py @@ -32,22 +32,23 @@ def get_identifiable(self, identifier: Identifier) -> Identifiable: This may include looking up the object's endpoint in a registry and fetching it from an HTTP server or a database. - :param identifier: The :class:`~aas.model.base.Identifier` of the object to return + :param identifier: :class:`~aas.model.base.Identifier` of the object to return :return: The :class:`~aas.model.base.Identifiable` object (or a proxy object for a remote - :class:`~aas.model.base.Identifiable` object) - :raises KeyError: If no such :class:`~aas.model.base.Identifiable` can be found + :class:`~aas.model.base.Identifiable` object) + :raises KeyError: If no such :class:`~.aas.model.base.Identifiable` can be found """ pass def get(self, identifier: Identifier, default: Optional[Identifiable] = None) -> Optional[Identifiable]: """ - Find an object in this set by its identification, with fallback parameter - - :param identifier: The :class:`~aas.model.base.Identifier` of the object to return - :param default: An object to be returned, if no object with the given identification is found - :return: The :class:`~aas.model.base.Identifiable` object with the given identification in the provider. - Otherwise the `default` object - or `None`, if none is given. + Find an object in this set by its :class:`id `, with fallback parameter + + :param identifier: :class:`~aas.model.base.Identifier` of the object to return + :param default: An object to be returned, if no object with the given + :class:`id ` is found + :return: The :class:`~aas.model.base.Identifiable` object with the given + :class:`id ` in the provider. Otherwise the `default` object + or None, if none is given. """ try: return self.get_identifiable(identifier) @@ -62,10 +63,13 @@ class AbstractObjectStore(AbstractObjectProvider, MutableSet[_IT], Generic[_IT], """ Abstract baseclass of for container-like objects for storage of :class:`~aas.model.base.Identifiable` objects. - ObjectStores are special :class:`ObjectProvides <.AbstractObjectProvider` that – in addition to retrieving objects - by :class:`~aas.model.base.Identifier` – allow to add and - delete objects (i.e. behave like a Python set). This includes local object stores (like :class:`~.DictObjectStore`) - and database clients. + ObjectStores are special ObjectProvides that – in addition to retrieving objects by + :class:`~aas.model.base.Identifier` – allow to add and delete objects (i.e. behave like a Python set). + This includes local object stores (like :class:`~.DictObjectStore`) and database + :class:`Backends `. + + The AbstractObjectStore inherits from the `MutableSet` abstract collections class and therefore implements all the + functions of this class. """ @abc.abstractmethod def __init__(self): @@ -91,21 +95,21 @@ def get_identifiable(self, identifier: Identifier) -> _IT: return self._backend[identifier] def add(self, x: _IT) -> None: - if x.identification in self._backend and self._backend.get(x.identification) is not x: - raise KeyError("Identifiable object with same identification {} is already stored in this store" - .format(x.identification)) - self._backend[x.identification] = x + if x.id in self._backend and self._backend.get(x.id) is not x: + raise KeyError("Identifiable object with same id {} is already stored in this store" + .format(x.id)) + self._backend[x.id] = x def discard(self, x: _IT) -> None: - if self._backend.get(x.identification) is x: - del self._backend[x.identification] + if self._backend.get(x.id) is x: + del self._backend[x.id] def __contains__(self, x: object) -> bool: if isinstance(x, Identifier): return x in self._backend if not isinstance(x, Identifiable): return False - return self._backend.get(x.identification) is x + return self._backend.get(x.id) is x def __len__(self) -> int: return len(self._backend) @@ -118,11 +122,12 @@ class ObjectProviderMultiplexer(AbstractObjectProvider): """ A multiplexer for Providers of :class:`~aas.model.base.Identifiable` objects. - This class combines multiple Registries of :class:`~aas.model.base.Identifiable` objects into a single one to allow - retrieving :class:`~aas.model.base.Identifiable` objects from different sources. It implements the - :class:`~.AbstractObjectProvider` interface to be used as registry itself. + This class combines multiple registries of :class:`~aas.model.base.Identifiable` objects into a single one to allow + retrieving :class:`~aas.model.base.Identifiable` objects from different sources. + It implements the :class:`~.AbstractObjectProvider` interface to be used as registry itself. - :ivar registries: A list of registries to query when looking up an object + :ivar registries: A list of :class:`AbstractObjectProviders <.AbstractObjectProvider>` to query when looking up an + object """ def __init__(self, registries: Optional[List[AbstractObjectProvider]] = None): self.providers: List[AbstractObjectProvider] = registries if registries is not None else [] diff --git a/basyx/aas/model/security.py b/basyx/aas/model/security.py deleted file mode 100644 index c640be161..000000000 --- a/basyx/aas/model/security.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2019 the Eclipse BaSyx Authors -# -# This program and the accompanying materials are made available under the terms of the MIT License, available in -# the LICENSE file of this project. -# -# SPDX-License-Identifier: MIT -""" -This module contains the security aspects of the AAS metamodel. Currently, the security model is not ready yet, so this -module doesn't do anything. -""" - - -class Security: - """ - Security model is not ready yet. This is just a placeholder class. - """ - pass diff --git a/basyx/aas/model/submodel.py b/basyx/aas/model/submodel.py index a7dfea17e..4dc2e5297 100644 --- a/basyx/aas/model/submodel.py +++ b/basyx/aas/model/submodel.py @@ -9,183 +9,272 @@ """ import abc -from typing import Optional, Set, Iterable, TYPE_CHECKING, List, Type +import uuid +from typing import Optional, Set, Iterable, TYPE_CHECKING, List, Type, TypeVar, Generic, Union -from . import base, datatypes +from . import base, datatypes, _string_constraints if TYPE_CHECKING: from . import aas -class SubmodelElement(base.Referable, base.Qualifiable, base.HasSemantics, base.HasKind, metaclass=abc.ABCMeta): +class SubmodelElement(base.Referable, base.Qualifiable, base.HasSemantics, + base.HasDataSpecification, metaclass=abc.ABCMeta): """ A submodel element is an element suitable for the description and differentiation of assets. - NOTE: The concept of type and instance applies to submodel elements. Properties are special submodel elements. - The property types are defined in dictionaries (like the IEC Common Data Dictionary or eCl@ss), - they do not have a value. The property type (kind=Type) is also called data element type in some standards. - The property instances (kind=Instance) typically have a value. A property instance is also called + *Note:* The concept of type and instance applies to submodel elements. :class:`Properties <.Property>` are special + submodel elements. The property types are defined in dictionaries (like the IEC Common Data Dictionary or eCl\\@ss), + they do not have a value. The property type (`kind=Type`) is also called data element type in some standards. + The property instances (`kind=Instance`) typically have a value. A property instance is also called property-value pair in certain standards. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) + :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) + :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) + :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ @abc.abstractmethod def __init__(self, - id_short: str, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ super().__init__() self.id_short = id_short - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent + self.display_name: Optional[base.MultiLanguageNameType] = display_name + self.category = category + self.description: Optional[base.MultiLanguageTextType] = description + self.parent: Optional[base.UniqueIdShortNamespace] = parent self.semantic_id: Optional[base.Reference] = semantic_id - self.qualifier: Set[base.Constraint] = set() if qualifier is None else qualifier - self._kind: base.ModelingKind = kind + self.qualifier = base.NamespaceSet(self, [("type", True)], qualifier) + self.extension = base.NamespaceSet(self, [("name", True)], extension) + self.supplemental_semantic_id: base.ConstrainedList[base.Reference] = \ + base.ConstrainedList(supplemental_semantic_id) + self.embedded_data_specifications: List[base.EmbeddedDataSpecification] = list(embedded_data_specifications) -class Submodel(base.Identifiable, base.HasSemantics, base.HasKind, base.Qualifiable, base.Namespace): +class Submodel(base.Identifiable, base.HasSemantics, base.HasKind, base.Qualifiable, + base.UniqueIdShortNamespace, base.HasDataSpecification): """ A Submodel defines a specific aspect of the asset represented by the AAS. A submodel is used to structure the virtual representation and technical functionality of an Administration Shell into distinguishable parts. Each submodel refers to a well-defined domain or subject matter. Submodels can become - standardized and thus become submodels types. Submodels can have different life-cycles. + standardized and thus become submodel types. Submodels can have different life-cycles. - :ivar ~.identification: The globally unique :class:`~aas.model.base.Identification` of the element. - (inherited from :class:`~aas.model.base.Identifiable`) + :ivar ~.id: The globally unique id of the element. + (inherited from :class:`~aas.model.base.Identifiable`) :ivar submodel_element: Unordered list of :class:`SubmodelElements <.SubmodelElement>` - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) - :ivar administration: :class:`~aas.model.base.AdministrativeInformation` of an :class:`~aas.model.base.Identifiable` - element. (inherited from :class:`~aas.model.base.Identifiable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) + :ivar administration: Administrative information of an identifiable element. (inherited from + :class:`~aas.model.base.Identifiable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar kind: Kind of the element: Either `TYPE` or `INSTANCE`. Default is `INSTANCE`. (inherited from + :class:`aas.model.base.HasKind`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - identification: base.Identifier, + id_: base.Identifier, submodel_element: Iterable[SubmodelElement] = (), - id_short: str = "", - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, administration: Optional[base.AdministrativeInformation] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + kind: base.ModellingKind = base.ModellingKind.INSTANCE, + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): super().__init__() - self.identification: base.Identifier = identification - self.submodel_element = base.NamespaceSet(self, submodel_element) + self.id: base.Identifier = id_ + self.submodel_element = base.NamespaceSet(self, [("id_short", True)], submodel_element) self.id_short = id_short - self.category: Optional[str] = category - self.description: Optional[base.LangStringSet] = dict() if description is None else description - self.parent: Optional[base.Namespace] = parent + self.display_name: Optional[base.MultiLanguageNameType] = display_name + self.category = category + self.description: Optional[base.MultiLanguageTextType] = description + self.parent: Optional[base.UniqueIdShortNamespace] = parent self.administration: Optional[base.AdministrativeInformation] = administration self.semantic_id: Optional[base.Reference] = semantic_id - self.qualifier: Set[base.Constraint] = set() if qualifier is None else qualifier - self._kind: base.ModelingKind = kind + self.qualifier = base.NamespaceSet(self, [("type", True)], qualifier) + self._kind: base.ModellingKind = kind + self.extension = base.NamespaceSet(self, [("name", True)], extension) + self.supplemental_semantic_id: base.ConstrainedList[base.Reference] = \ + base.ConstrainedList(supplemental_semantic_id) + self.embedded_data_specifications: List[base.EmbeddedDataSpecification] = list(embedded_data_specifications) + + +ALLOWED_DATA_ELEMENT_CATEGORIES: Set[str] = { + "CONSTANT", + "PARAMETER", + "VARIABLE" +} class DataElement(SubmodelElement, metaclass=abc.ABCMeta): """ - A data element is a submodel element that is not further composed out of other submodel elements. - A data element is a submodel element that has a value. The type of value differs for different subtypes + A data element is a :class:`~.SubmodelElement` that is not further composed out of other + :class:`SubmodelElements <.SubmodelElement>`. + A data element is a :class:`~.SubmodelElement` that has a value. The type of value differs for different subtypes of data elements. <> - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ @abc.abstractmethod def __init__(self, - id_short: str, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + + def _set_category(self, category: Optional[str]): + if category == "": + raise base.AASConstraintViolation(100, + "category is not allowed to be an empty string") + if category is None: + self._category = None + else: + if category not in ALLOWED_DATA_ELEMENT_CATEGORIES: + if not (isinstance(self, File) or isinstance(self, Blob)): + raise base.AASConstraintViolation( + 90, + "DataElement.category must be one of the following: " + + ", ".join(ALLOWED_DATA_ELEMENT_CATEGORIES)) + self._category = category class Property(DataElement): """ - A property is a :class:`~.DataElement` that has a single value. + A property is a :class:`DataElement` that has a single value. - **Constraint AASd-007:** if both, the value and the valueId are present then the value needs to be - identical to the value of the referenced coded value in valueId + *Constraint AASd-007:* If both, the value and the valueId of a Qualifier are present, + the value needs to be identical to the value of the referenced coded value in Qualifier/valueId. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) :ivar value_type: Data type of the value :ivar value: The value of the property instance. :ivar value_id: :class:`~aas.model.base.Reference` to the global unique id of a coded value + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - value_type: base.DataTypeDef, + id_short: Optional[base.NameType], + value_type: base.DataTypeDefXsd, value: Optional[base.ValueDataType] = None, value_id: Optional[base.Reference] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.value_type: Type[datatypes.AnyXSDType] = value_type + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.value_type: base.DataTypeDefXsd = value_type self._value: Optional[base.ValueDataType] = (datatypes.trivial_cast(value, value_type) if value is not None else None) self.value_id: Optional[base.Reference] = value_id @@ -204,97 +293,115 @@ def value(self, value) -> None: class MultiLanguageProperty(DataElement): """ - A property is a data element that has a multi language value. + A multi language property is a :class:`~.DataElement` that has a multi language value. - **Constraint AASd-012:** if both, the value and the valueId are present then for each string in a - specific language the meaning must be the same as specified in valueId. + *Constraint AASd-012*: if both the MultiLanguageProperty/value and the MultiLanguageProperty/valueId are present, + the meaning must be the same for each string in a specific language, + as specified inMultiLanguageProperty/valueId. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) :ivar value: The value of the property instance. - :ivar value_id: :class:`~aas.model.base.Reference` to the global unique id of a coded value. - + :ivar value_id: :class:`~aas.model.base.Reference` to the global unique id of a coded value + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - value: Optional[base.LangStringSet] = None, + id_short: Optional[base.NameType], + value: Optional[base.MultiLanguageTextType] = None, value_id: Optional[base.Reference] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.value: base.LangStringSet = dict() if value is None else value + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.value: Optional[base.MultiLanguageTextType] = value self.value_id: Optional[base.Reference] = value_id class Range(DataElement): """ - A range data element is a data element that defines a range with min and max. + A range is a :class:`~.DataElement` that has a range value. - **Constraint AASd-013:** In case of a range with kind=Instance either the min or the max value or both need - to be defined + *Constraint AASd-013:* In case of a range with `kind=Instance` either the min or the max value or both + need to be defined - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) :ivar value_type: Data type of the min and max :ivar min: The minimum value of the range. If the min value is missing then the value is assumed to be negative - infinite. + infinite :ivar max: The maximum of the range. If the max value is missing then the value is assumed to be positive infinite + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - value_type: base.DataTypeDef, + id_short: Optional[base.NameType], + value_type: base.DataTypeDefXsd, min: Optional[base.ValueDataType] = None, max: Optional[base.ValueDataType] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.value_type: base.DataTypeDef = value_type + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.value_type: base.DataTypeDefXsd = value_type self._min: Optional[base.ValueDataType] = datatypes.trivial_cast(min, value_type) if min is not None else None self._max: Optional[base.ValueDataType] = datatypes.trivial_cast(max, value_type) if max is not None else None @@ -321,426 +428,571 @@ def max(self, value) -> None: self._max = datatypes.trivial_cast(value, self.value_type) +@_string_constraints.constrain_content_type("content_type") class Blob(DataElement): """ - A BLOB is a data element that represents a file that is contained with its source code in the value attribute. + A BLOB is a :class:`~.DataElement` that represents a file that is contained with its source code in the value + attribute. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar value: The value of the BLOB instance of a blob data element. - *Note:* In contrast to the file property the file content is stored directly as value in - the Blob data element. - :ivar mime_type: Mime type of the content of the BLOB. The mime type states which file extension the file has. + *Note:* In contrast to the file property the file content is stored directly as value in the Blob data element. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar content_type: Mime type of the content of the BLOB. The mime type states which file extension the file has. Valid values are e.g. “application/json”, “application/xls”, ”image/jpg”. The allowed values are defined as in RFC2046. + :ivar value: The value of the BLOB instance of a blob data element. + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) - + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - mime_type: base.MimeType, + id_short: Optional[base.NameType], + content_type: base.ContentType, value: Optional[base.BlobType] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) self.value: Optional[base.BlobType] = value - self.mime_type: base.MimeType = mime_type + self.content_type: base.ContentType = content_type +@_string_constraints.constrain_content_type("content_type") +@_string_constraints.constrain_path_type("value") class File(DataElement): """ - A File is a data element that represents a file via its path description. + A File is a :class:`~.DataElement` that represents a file via its path description. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar mime_type: Mime type of the content of the File. - :ivar value: Path and name of the referenced file (without file extension). The path can be absolute or relative. - *Note:* The file extension is defined by using a qualifier of type “MimeType”. + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar content_type: Mime type of the content of the File. + :ivar value: Path and name of the referenced file (with file extension). The path can be absolute or relative. + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - mime_type: base.MimeType, + id_short: Optional[base.NameType], + content_type: base.ContentType, value: Optional[base.PathType] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) self.value: Optional[base.PathType] = value - self.mime_type: base.MimeType = mime_type + self.content_type: base.ContentType = content_type class ReferenceElement(DataElement): """ - A reference element is a data element that defines a :class:`~aas.model.base.Reference` to another element within - the same or another AAS or a reference to an external object or entity. + A reference element is a :class:`DataElement` that defines a :class:`~aas.model.base.Reference` to another element + within the same or another AAS or a :class:`~aas.model.base.Reference` to an external object or entity. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) :ivar value: :class:`~aas.model.base.Reference` to any other :class:`~aas.model.base.Referable` element of the same - of any other AAS or a reference to an external object or entity. + or any other AAS or a :class:`~aas.model.base.Reference` to an external object or entity. + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, + id_short: Optional[base.NameType], value: Optional[base.Reference] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) self.value: Optional[base.Reference] = value -class SubmodelElementCollection(SubmodelElement, base.Namespace, metaclass=abc.ABCMeta): +class SubmodelElementCollection(SubmodelElement, base.UniqueIdShortNamespace): """ - A submodel element collection is a set or list of submodel elements. - - <> + A submodel element collection is a set or list of :class:`SubmodelElements <.SubmodelElement>`. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar value: Ordered or unordered list of :class:`SubmodelElements <.SubmodelElement>` - :ivar ordered: If `ordered=False` then the elements in the property collection are not ordered. If `ordered=True` - then - the elements in the collection are ordered. - `ordered` shall not be set directly, instead one of the subclasses - :class:`~.SubmodelElementCollectionOrdered` or :class:`~.SubmodelElementCollectionUnordered` shall - be used. + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar value: list of :class:`SubmodelElements <.SubmodelElement>` + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ - @abc.abstractmethod def __init__(self, - id_short: str, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + value: Iterable[SubmodelElement] = (), + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): - """ - TODO: Add instruction what to do after construction - """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.value: base.NamespaceSet[SubmodelElement] = None # type: ignore + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): - @property - @abc.abstractmethod - def ordered(self) -> bool: - pass + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.value: base.NamespaceSet[SubmodelElement] = base.NamespaceSet(self, [("id_short", True)], value) -class SubmodelElementCollectionOrdered(SubmodelElementCollection): - """ - A SubmodelElementCollectionOrdered is an ordered list of :class:`SubmodelElements <.SubmodelElement>`. +_SE = TypeVar("_SE", bound=SubmodelElement) + - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar value: Ordered or unordered list of :class:`SubmodelElements <.SubmodelElement>` +class SubmodelElementList(SubmodelElement, base.UniqueIdShortNamespace, Generic[_SE]): + """ + A submodel element list is an ordered list of :class:`SubmodelElements <.SubmodelElement>`. + The numbering starts with Zero (0). + + *Constraint AASd-107:* If a first level child element in a :class:`SubmodelElementList` has a semanticId it shall be + identical to SubmodelElementList/semanticIdListElement. + *Constraint AASd-114:* If two first level child elements in a :class:`SubmodelElementList` have a semanticId then + they shall be identical. + *Constraint AASd-115:* If a first level child element in a :class:`SubmodelElementList` does not specify a + semanticId, the value is assumed to be identical to SubmodelElementList/semanticIdListElement. + *Constraint AASd-108:* All first level child elements in a :class:`SubmodelElementList` shall have the same + submodel element type as specified in SubmodelElementList/typeValueListElement. + *Constraint AASd-109:* If SubmodelElementList/typeValueListElement is equal to Property or Range, + SubmodelElementList/valueTypeListElement shall be set and all first level child elements in the + :class:`SubmodelElementList` shall have the value type as specified in SubmodelElementList/valueTypeListElement. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar type_value_list_element: The :class:`SubmodelElement` type of the submodel elements contained in the list. + :ivar value: :class:`SubmodelElements <.SubmodelElement>` contained in the list. The list is ordered. + :ivar semantic_id_list_element: Semantic ID of the :class:`SubmodelElements <.SubmodelElement>` contained in the + list to match to. + :ivar value_type_list_element: The value type of the submodel element contained in the list. + :ivar order_relevant: Defines whether order in list is relevant. If False the list is representing a set or a bag. + Default: True + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ - def __init__(self, - id_short: str, - value: Iterable[SubmodelElement] = (), - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + type_value_list_element: Type[_SE], + value: Iterable[_SE] = (), + semantic_id_list_element: Optional[base.Reference] = None, + value_type_list_element: Optional[base.DataTypeDefXsd] = None, + order_relevant: bool = True, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): - """ - TODO: Add instruction what to do after construction - """ - - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.value = base.OrderedNamespaceSet(self, value) + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + # Counter to generate a unique idShort whenever a SubmodelElement is added + self._uuid_seq: int = 0 + + # It doesn't really make sense to change any of these properties. thus they are immutable here. + self._type_value_list_element: Type[_SE] = type_value_list_element + self._order_relevant: bool = order_relevant + self._semantic_id_list_element: Optional[base.Reference] = semantic_id_list_element + self._value_type_list_element: Optional[base.DataTypeDefXsd] = value_type_list_element + + if self.type_value_list_element in (Property, Range) and self.value_type_list_element is None: + raise base.AASConstraintViolation(109, f"type_value_list_element={self.type_value_list_element.__name__}, " + "but value_type_list_element is not set!") + + # Items must be added after the above contraint has been checked. Otherwise, it can lead to errors, since the + # constraints in _check_constraints() assume that this constraint has been checked. + self._value: base.OrderedNamespaceSet[_SE] = base.OrderedNamespaceSet(self, [("id_short", True)], (), + item_add_hook=self._check_constraints, + item_id_set_hook=self._generate_id_short, + item_id_del_hook=self._unset_id_short) + # SubmodelElements need to be added after the assignment of the ordered NamespaceSet, otherwise, if a constraint + # check fails, Referable.__repr__ may be called for an already-contained item during the AASd-114 check, which + # in turn tries to access the SubmodelElementLists value / _value attribute, which wouldn't be set yet if all + # elements are passed to the OrderedNamespaceSet initializer. + try: + for i in value: + self._value.add(i) + except Exception: + # Remove all SubmodelElements if an exception occurs during initialization of the SubmodelElementList + self._value.clear() + raise + + def _generate_id_short(self, new: _SE) -> None: + if new.id_short is not None: + raise base.AASConstraintViolation(120, "Objects with an id_short may not be added to a " + f"SubmodelElementList, got {new!r} with id_short={new.id_short}") + # Generate a unique id_short when a SubmodelElement is added, because children of a SubmodelElementList may not + # have an id_short. The alternative would be making SubmodelElementList a special kind of base.Namespace without + # a unique attribute for child-elements (which contradicts the definition of a Namespace). + new.id_short = "generated_submodel_list_hack_" + uuid.uuid1(clock_seq=self._uuid_seq).hex + self._uuid_seq += 1 + + def _unset_id_short(self, old: _SE) -> None: + old.id_short = None + + def _check_constraints(self, new: _SE, existing: Iterable[_SE]) -> None: + # Since the id_short contains randomness, unset it temporarily for pretty and predictable error messages. + # This also prevents the random id_short from remaining set in case a constraint violation is encountered. + saved_id_short = new.id_short + new.id_short = None + + # We can't use isinstance(new, self.type_value_list_element) here, because each subclass of + # self.type_value_list_element wouldn't raise a ConstraintViolation, when it should. + # Example: AnnotatedRelationshipElement is a subclass of RelationshipElement + if type(new) is not self.type_value_list_element: + raise base.AASConstraintViolation(108, "All first level elements must be of the type specified in " + f"type_value_list_element={self.type_value_list_element.__name__}, " + f"got {new!r}") + + if self.semantic_id_list_element is not None and new.semantic_id is not None \ + and new.semantic_id != self.semantic_id_list_element: + # Constraint AASd-115 specifies that if the semantic_id of an item is not specified + # but semantic_id_list_element is, the semantic_id of the new is assumed to be identical. + # Not really a constraint... + # TODO: maybe set the semantic_id of new to semantic_id_list_element if it is None + raise base.AASConstraintViolation(107, f"If semantic_id_list_element={self.semantic_id_list_element!r} " + "is specified all first level children must have the same " + f"semantic_id, got {new!r} with semantic_id={new.semantic_id!r}") + + # If we got here we know that `new` is an instance of type_value_list_element and that type_value_list_element + # is either Property or Range. Thus, `new` must have the value_type property. Ignore the type here because + # the typechecker doesn't get it. + if self.type_value_list_element in (Property, Range) \ + and new.value_type is not self.value_type_list_element: # type: ignore + raise base.AASConstraintViolation(109, "All first level elements must have the value_type " # type: ignore + "specified by value_type_list_element=" + f"{self.value_type_list_element.__name__}, got {new!r} with " + f"value_type={new.value_type.__name__}") # type: ignore + + # If semantic_id_list_element is not None that would already enforce the semantic_id for all first level + # elements. Thus, we only need to perform this check if semantic_id_list_element is None. + if new.semantic_id is not None and self.semantic_id_list_element is None: + for item in existing: + if item.semantic_id is not None and new.semantic_id != item.semantic_id: + raise base.AASConstraintViolation(114, f"Element to be added {new!r} has semantic_id " + f"{new.semantic_id!r}, while already contained element " + f"{item!r} has semantic_id {item.semantic_id!r}, which " + "aren't equal.") + + # Re-assign id_short + new.id_short = saved_id_short @property - def ordered(self) -> bool: - return True + def value(self) -> base.OrderedNamespaceSet[_SE]: + return self._value + @value.setter + def value(self, value: Iterable[_SE]): + del self._value[:] + self._value.extend(value) -class SubmodelElementCollectionUnordered(SubmodelElementCollection): - """ - A SubmodelElementCollectionOrdered is an unordered list of :class:`SubmodelElements <.SubmodelElement>`. + @property + def type_value_list_element(self) -> Type[_SE]: + return self._type_value_list_element - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar value: Ordered or unordered list of :class:`SubmodelElements <.SubmodelElement>` - :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) - :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) - :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) - """ + @property + def order_relevant(self) -> bool: + return self._order_relevant - def __init__(self, - id_short: str, - value: Iterable[SubmodelElement] = (), - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, - semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): - """ - TODO: Add instruction what to do after construction - """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.value = base.NamespaceSet(self, value) + @property + def semantic_id_list_element(self) -> Optional[base.Reference]: + return self._semantic_id_list_element @property - def ordered(self) -> bool: - return False + def value_type_list_element(self) -> Optional[base.DataTypeDefXsd]: + return self._value_type_list_element class RelationshipElement(SubmodelElement): """ - A relationship element is used to define a relationship between two referable elements. - - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar first: :class:`~aas.model.base.Reference` to the first element in the relationship taking the role of the - subject which have to be of class :class:`~aas.model.base.Referable`. - :ivar second: :class:`~aas.model.base.Reference` to the second element in the relationship taking the role of the - object which have to be of class :class:`~aas.model.base.Referable`. + A relationship element is used to define a relationship between two :class:`~aas.model.base.Referable` elements. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar first: Reference to the first element in the relationship taking the role of the subject which have to + be of class Referable. (inherited from :class:`~.RelationshipElement`) + :ivar second: Reference to the second element in the relationship taking the role of the object which have to + be of class Referable. (inherited from :class:`~.RelationshipElement`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - first: base.AASReference, - second: base.AASReference, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + first: base.Reference, + second: base.Reference, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.first: base.AASReference = first - self.second: base.AASReference = second + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.first: base.Reference = first + self.second: base.Reference = second -class AnnotatedRelationshipElement(RelationshipElement, base.Namespace): +class AnnotatedRelationshipElement(RelationshipElement, base.UniqueIdShortNamespace): """ - An annotated relationship element is a relationship element that can be annotated with additional data elements. - - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar annotation: Unordered list of annotations that hold for the relationship between to elements + An annotated relationship element is a :class:`~.RelationshipElement` that can be annotated + with additional :class:`DataElements <.DataElement>`. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar first: Reference to the first element in the relationship taking the role of the subject which have to + be of class Referable. (inherited from :class:`~.RelationshipElement`) + :ivar second: Reference to the second element in the relationship taking the role of the object which have to + be of class Referable. (inherited from :class:`~.RelationshipElement`) + :ivar annotation: Unordered list of :class:`DataElements <.DataElement>` that hold for the relationship between two + elements + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - first: base.AASReference, - second: base.AASReference, + id_short: Optional[base.NameType], + first: base.Reference, + second: base.Reference, + display_name: Optional[base.MultiLanguageNameType] = None, annotation: Iterable[DataElement] = (), - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, first, second, category, description, parent, semantic_id, qualifier, kind) - self.annotation = base.NamespaceSet(self, annotation) - + super().__init__(id_short, first, second, display_name, category, description, parent, semantic_id, qualifier, + extension, supplemental_semantic_id, embedded_data_specifications) + self.annotation = base.NamespaceSet(self, [("id_short", True)], annotation) -class OperationVariable: - """ - An operation variable is a submodel element that is used as input or output variable of an operation. - :ivar value: Describes the needed argument for an operation via a submodel element of kind=Type. - Constraint AASd-008: The submodel element value of an operation variable shall be of kind=Template. - """ - - def __init__(self, - value: SubmodelElement): - """ - TODO: Add instruction what to do after construction - """ - # Constraint AASd-008: The submodel element shall be of kind=Template. - self.value: SubmodelElement = value # TODO check the kind of the object in value - - -class Operation(SubmodelElement): +class Operation(SubmodelElement, base.UniqueIdShortNamespace): """ An operation is a :class:`~.SubmodelElement` with input and output variables. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar input_variable: list of input :class:`OperationVariables <.OperationVariable>` of the operation - :ivar output_variable: of output :class:`OperationVariables <.OperationVariable>` of the operation - :ivar in_output_variable: List of :class:`OperationVariables <.OperationVariable>` that are input and output - of the operation + In- and output variables are implemented as :class:`SubmodelElements <.SubmodelElement>` directly without the + wrapping `OperationVariable`. This makes implementing *Constraint AASd-134* much easier since we can just use normal + :class:`NamespaceSets <~aas.model.base.NamespaceSet>`. Furthermore, an `OperationVariable` contains nothing besides + a single :class:`~.SubmodelElement` anyway, so implementing it would just make using `Operations` more tedious + for no reason. + + *Constraint AASd-134:* For an Operation, the idShort of all inputVariable/value, outputVariable/value, + and inoutputVariable/value shall be unique. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar input_variable: List of input parameters (:class:`SubmodelElements <.SubmodelElement>`) of the operation + :ivar output_variable: List of output parameters (:class:`SubmodelElements <.SubmodelElement>`) of the operation + :ivar in_output_variable: List of parameters (:class:`SubmodelElements <.SubmodelElement>`) that are input and + output of the operation + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - input_variable: Optional[List[OperationVariable]] = None, - output_variable: Optional[List[OperationVariable]] = None, - in_output_variable: Optional[List[OperationVariable]] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + input_variable: Iterable[SubmodelElement] = (), + output_variable: Iterable[SubmodelElement] = (), + in_output_variable: Iterable[SubmodelElement] = (), + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.input_variable = input_variable if input_variable is not None else [] - self.output_variable = output_variable if output_variable is not None else [] - self.in_output_variable = in_output_variable if in_output_variable is not None else [] + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.input_variable = base.NamespaceSet(self, [("id_short", True)], input_variable) + self.output_variable = base.NamespaceSet(self, [("id_short", True)], output_variable) + self.in_output_variable = base.NamespaceSet(self, [("id_short", True)], in_output_variable) class Capability(SubmodelElement): @@ -748,164 +1000,335 @@ class Capability(SubmodelElement): A capability is the implementation-independent description of the potential of an asset to achieve a certain effect in the physical or virtual world - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) -class Entity(SubmodelElement, base.Namespace): +class Entity(SubmodelElement, base.UniqueIdShortNamespace): """ - An entity is a submodel element that is used to model entities + An entity is a :class:`~.SubmodelElement` that is used to model entities - **Constraint AASd-014:** The asset attribute must be set if entityType is set to “SelfManagedEntity”. It - is empty otherwise. + *Constraint AASd-014:* global_asset_id or specific_asset_id must be set if :attr:`~.entity_type` is set to + :attr:`~.EntityType.SELF_MANAGED_ENTITY`. They must be empty otherwise. - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) :ivar entity_type: Describes whether the entity is a co-managed or a self-managed entity. - :ivar statement: Unordered list of statements applicable to the entity, typically with a qualified value. - :ivar asset: Reference to the asset the entity is representing. - + :ivar statement: Unordered list of statements (:class:`SubmodelElements <.SubmodelElement>`) applicable to the + entity, typically with a qualified value. + :ivar global_asset_id: Global :class:`~aas.model.base.Identifier` of the asset the entity is representing. + :ivar specific_asset_id: :class:`~aas.model.base.Reference` to an identifier key value pair representing a specific + identifier of the asset represented by the asset administration shell. + See Constraint AASd-014 + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, + id_short: Optional[base.NameType], entity_type: base.EntityType, statement: Iterable[SubmodelElement] = (), - asset: Optional[base.AASReference["aas.Asset"]] = None, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + global_asset_id: Optional[base.Identifier] = None, + specific_asset_id: Iterable[base.SpecificAssetId] = (), + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.statement = base.NamespaceSet(self, [("id_short", True)], statement) + # assign private attributes, bypassing setters, as constraints will be checked below + self._entity_type: base.EntityType = entity_type + self._global_asset_id: Optional[base.Identifier] = global_asset_id + self._specific_asset_id: base.ConstrainedList[base.SpecificAssetId] = base.ConstrainedList( + specific_asset_id, + item_add_hook=self._check_constraint_add_spec_asset_id, + item_set_hook=self._check_constraint_set_spec_asset_id, + item_del_hook=self._check_constraint_del_spec_asset_id + ) + self._validate_global_asset_id(global_asset_id) + self._validate_aasd_014(entity_type, global_asset_id, bool(specific_asset_id)) - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.entity_type: base.EntityType = entity_type - self.statement = base.NamespaceSet(self, statement) - if self.entity_type == base.EntityType.SELF_MANAGED_ENTITY and asset is None: - raise ValueError("A self-managed entity has to have an asset-reference") - if self.entity_type == base.EntityType.SELF_MANAGED_ENTITY: - self.asset: Optional[base.AASReference["aas.Asset"]] = asset - else: - self.asset = None + @property + def entity_type(self) -> base.EntityType: + return self._entity_type + @entity_type.setter + def entity_type(self, entity_type: base.EntityType) -> None: + self._validate_aasd_014(entity_type, self.global_asset_id, bool(self.specific_asset_id)) + self._entity_type = entity_type -class Event(SubmodelElement, metaclass=abc.ABCMeta): - """ - An event + @property + def global_asset_id(self) -> Optional[base.Identifier]: + return self._global_asset_id + @global_asset_id.setter + def global_asset_id(self, global_asset_id: Optional[base.Identifier]) -> None: + self._validate_global_asset_id(global_asset_id) + self._validate_aasd_014(self.entity_type, global_asset_id, bool(self.specific_asset_id)) + self._global_asset_id = global_asset_id + + @property + def specific_asset_id(self) -> base.ConstrainedList[base.SpecificAssetId]: + return self._specific_asset_id + + @specific_asset_id.setter + def specific_asset_id(self, specific_asset_id: Iterable[base.SpecificAssetId]) -> None: + # constraints are checked via _check_constraint_set_spec_asset_id() in this case + self._specific_asset_id[:] = specific_asset_id + + def _check_constraint_add_spec_asset_id(self, _new_item: base.SpecificAssetId, + _old_list: List[base.SpecificAssetId]) -> None: + self._validate_aasd_014(self.entity_type, self.global_asset_id, True) + + def _check_constraint_set_spec_asset_id(self, items_to_replace: List[base.SpecificAssetId], + new_items: List[base.SpecificAssetId], + old_list: List[base.SpecificAssetId]) -> None: + self._validate_aasd_014(self.entity_type, self.global_asset_id, + len(old_list) - len(items_to_replace) + len(new_items) > 0) + + def _check_constraint_del_spec_asset_id(self, _item_to_del: base.SpecificAssetId, + old_list: List[base.SpecificAssetId]) -> None: + self._validate_aasd_014(self.entity_type, self.global_asset_id, len(old_list) > 1) + + @staticmethod + def _validate_global_asset_id(global_asset_id: Optional[base.Identifier]) -> None: + if global_asset_id is not None: + _string_constraints.check_identifier(global_asset_id) + + @staticmethod + def _validate_aasd_014(entity_type: base.EntityType, + global_asset_id: Optional[base.Identifier], + specific_asset_id_nonempty: bool) -> None: + if entity_type == base.EntityType.SELF_MANAGED_ENTITY and global_asset_id is None \ + and not specific_asset_id_nonempty: + raise base.AASConstraintViolation( + 14, "A self-managed entity has to have a globalAssetId or a specificAssetId") + elif entity_type == base.EntityType.CO_MANAGED_ENTITY and (global_asset_id is not None + or specific_asset_id_nonempty): + raise base.AASConstraintViolation( + 14, "A co-managed entity has to have neither a globalAssetId nor a specificAssetId") + + +class EventElement(SubmodelElement, metaclass=abc.ABCMeta): + """ + An event element. <> - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from + :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ @abc.abstractmethod def __init__(self, - id_short: str, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) -class BasicEvent(Event): +@_string_constraints.constrain_message_topic_type("message_topic") +class BasicEventElement(EventElement): """ - An event - - :ivar id_short: Identifying string of the element within its name space. - (inherited from :class:`~aas.model.base.Referable`) - :ivar observed: :class:`~aas.model.base.AASReference` to the data or other elements that are being observed + A basic event element. + + :ivar id_short: Identifying string of the element within its name space. (inherited from + :class:`~aas.model.base.Referable`) + :ivar observed: :class:`~aas.model.base.ModelReference` to the Referable, which defines the scope of the event. + Can be :class:`~aas.model.aas.AssetAdministrationShell`, :class:`~aas.model.submodel.Submodel` + or :class:`~aas.model.submodel.SubmodelElement`. Reference to a referable, e.g. a data element + or a submodel, that is being observed. + :ivar direction: Direction of event as :class:`~aas.model.base.Direction`. + :ivar state: State of event as :class:`~aas.model.base.StateOfEvent`. + :ivar message_topic: Information for the outer message infrastructure for scheduling the event to the respective + communication channel. + :ivar message_broker: Information, which outer message infrastructure shall handle messages for the EventElement. + Refers to a :class:`~aas.model.submodel.Submodel`, + :class:`~aas.model.submodel.SubmodelElementList`, + :class:`~aas.model.submodel.SubmodelElementCollection` or :class:`~aas.model.submodel.Entity`, + which contains DataElements describing the proprietary specification for the message broker. + Note: for different message infrastructure, e.g. OPC UA or MQTT or AMQP, this proprietary + specification could be standardized by having respective Submodels. + :ivar last_update: Timestamp in UTC, when the last event was received (input direction) or sent (output direction). + :ivar min_interval: For input direction, reports on the maximum frequency, the software entity behind the respective + Referable can handle input events. For output events, specifies the maximum frequency of + outputting this event to an outer infrastructure. + :ivar max_interval: For input direction: not applicable. + For output direction: maximum interval in time, the respective Referable shall send an update of + the status of the event, even if no other trigger condition for the event was not met. + :ivar display_name: Can be provided in several languages. (inherited from :class:`~aas.model.base.Referable`) :ivar category: The category is a value that gives further meta information w.r.t. to the class of the element. - It affects the expected existence of attributes and the applicability of constraints. - (inherited from :class:`~aas.model.base.Referable`) + It affects the expected existence of attributes and the applicability of constraints. + (inherited from :class:`~aas.model.base.Referable`) :ivar description: Description or comments on the element. (inherited from :class:`~aas.model.base.Referable`) - :ivar parent: :class:`~aas.model.base.Reference` to the next referable parent element of the element. - (inherited from :class:`~aas.model.base.Referable`) + :ivar parent: Reference to the next referable parent element of the element. (inherited from + :class:`~aas.model.base.Referable`) :ivar semantic_id: Identifier of the semantic definition of the element. It is called semantic id of the - element. The semantic id may either reference an external global id or it may reference a - referable model element of kind=Type that defines the semantics of the element. - (inherited from :class:`~aas.model.base.HasSemantics`) - :ivar qualifier: Unordered list of Constraints that gives additional qualification of a qualifiable element. - (inherited from :class:`~aas.model.base.Qualifiable`) - :ivar kind: Kind of the element: either type or instance. Default = Instance. - (inherited from :class:`~aas.model.base.HasKind`) + element. The semantic id may either reference an external global id or it may reference a + referable model element of kind=Type that defines the semantics of the element. + (inherited from :class:`~aas.model.base.HasSemantics`) + :ivar qualifier: Unordered list of Qualifiers that gives additional qualification of a qualifiable element. + (from :class:`~aas.model.base.Qualifiable`) + :ivar extension: An extension of the element. (inherited from :class:`aas.model.base.HasExtension`) + :ivar supplemental_semantic_id: Identifier of a supplemental semantic definition of the element. It is called + supplemental semantic ID of the element. (inherited from + :class:`~aas.model.base.HasSemantics`) + :ivar embedded_data_specifications: List of Embedded data specification. """ def __init__(self, - id_short: str, - observed: base.AASReference, - category: Optional[str] = None, - description: Optional[base.LangStringSet] = None, - parent: Optional[base.Namespace] = None, + id_short: Optional[base.NameType], + observed: base.ModelReference[Union["aas.AssetAdministrationShell", Submodel, SubmodelElement]], + direction: base.Direction, + state: base.StateOfEvent, + message_topic: Optional[base.MessageTopicType] = None, + message_broker: Optional[base.ModelReference[Union[Submodel, SubmodelElementList, + SubmodelElementCollection, Entity]]] = None, + last_update: Optional[datatypes.DateTime] = None, + min_interval: Optional[datatypes.Duration] = None, + max_interval: Optional[datatypes.Duration] = None, + display_name: Optional[base.MultiLanguageNameType] = None, + category: Optional[base.NameType] = None, + description: Optional[base.MultiLanguageTextType] = None, + parent: Optional[base.UniqueIdShortNamespace] = None, semantic_id: Optional[base.Reference] = None, - qualifier: Optional[Set[base.Constraint]] = None, - kind: base.ModelingKind = base.ModelingKind.INSTANCE): + qualifier: Iterable[base.Qualifier] = (), + extension: Iterable[base.Extension] = (), + supplemental_semantic_id: Iterable[base.Reference] = (), + embedded_data_specifications: Iterable[base.EmbeddedDataSpecification] = ()): """ TODO: Add instruction what to do after construction """ - super().__init__(id_short, category, description, parent, semantic_id, qualifier, kind) - self.observed: base.AASReference = observed + super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, + supplemental_semantic_id, embedded_data_specifications) + self.observed: base.ModelReference[Union["aas.AssetAdministrationShell", Submodel, SubmodelElement]] = observed + # max_interval must be set here because the direction setter attempts to read it + self.max_interval: Optional[datatypes.Duration] = None + self.direction: base.Direction = direction + self.state: base.StateOfEvent = state + self.message_topic: Optional[base.MessageTopicType] = message_topic + self.message_broker: Optional[base.ModelReference[Union[Submodel, SubmodelElementList, + SubmodelElementCollection, Entity]]] = message_broker + self.last_update: Optional[datatypes.DateTime] = last_update + self.min_interval: Optional[datatypes.Duration] = min_interval + self.max_interval: Optional[datatypes.Duration] = max_interval + + @property + def direction(self) -> base.Direction: + return self._direction + + @direction.setter + def direction(self, direction: base.Direction) -> None: + if direction is base.Direction.INPUT and self.max_interval is not None: + raise ValueError("max_interval is not applicable if direction = input!") + self._direction: base.Direction = direction + + @property + def last_update(self) -> Optional[datatypes.DateTime]: + return self._last_update + + @last_update.setter + def last_update(self, last_update: Optional[datatypes.DateTime]) -> None: + if last_update is not None and last_update.tzname() != "UTC": + raise ValueError("last_update must be specified in UTC!") + self._last_update: Optional[datatypes.DateTime] = last_update + + @property + def max_interval(self) -> Optional[datatypes.Duration]: + return self._max_interval + + @max_interval.setter + def max_interval(self, max_interval: Optional[datatypes.Duration]) -> None: + if max_interval is not None and self.direction is base.Direction.INPUT: + raise ValueError("max_interval is not applicable if direction = input!") + self._max_interval: Optional[datatypes.Duration] = max_interval diff --git a/basyx/aas/util/identification.py b/basyx/aas/util/identification.py index 0e9811d86..803eede1c 100644 --- a/basyx/aas/util/identification.py +++ b/basyx/aas/util/identification.py @@ -37,7 +37,7 @@ def generate_id(self, proposal: Optional[str] = None) -> model.Identifier: """ Generate a new Identifier for an Identifiable object. - :param proposal: An optional string for a proposed suffix of the Identification (e.g. the last path part or + :param proposal: An optional string for a proposed suffix of the Identifier (e.g. the last path part or fragment of an IRI). It may be ignored by some implementations of or be changed if the resulting id is already existing. """ @@ -55,7 +55,7 @@ def __init__(self): def generate_id(self, proposal: Optional[str] = None) -> model.Identifier: uuid_ = uuid.uuid1(clock_seq=self._sequence) self._sequence += 1 - return model.Identifier("urn:uuid:{}".format(uuid_), model.IdentifierType.IRI) + return "urn:uuid:{}".format(uuid_) class NamespaceIRIGenerator(AbstractIdentifierGenerator): @@ -64,10 +64,10 @@ class NamespaceIRIGenerator(AbstractIdentifierGenerator): :class:`Identifiers ` are generated by concatenating a fixed namespace with the proposed suffix. To verify uniqueness, the - existence of the identification is checked by querying the given Registry. If a collision + existence of the id is checked by querying the given Registry. If a collision is detected, a number is prepended - :ivar namespace: The IRI Namespace to generate Identifications in. It must be a valid IRI (starting with a + :ivar namespace: The IRI Namespace to generate Identifiers in. It must be a valid IRI (starting with a scheme) and end on either #, /, or = to form a reasonable namespace. :ivar ~.provider: An :class:`~aas.model.provider.AbstractObjectProvider` to check existence of :class:`Identifiers ` @@ -75,7 +75,7 @@ class NamespaceIRIGenerator(AbstractIdentifierGenerator): def __init__(self, namespace: str, provider: model.AbstractObjectProvider): """ Create a new NamespaceIRIGenerator - :param namespace: The IRI Namespace to generate Identifications in. It must be a valid IRI (starting with a + :param namespace: The IRI Namespace to generate Identifiers in. It must be a valid IRI (starting with a scheme) and end on either #, /, or = to form a reasonable namespace. :param provider: An AbstractObjectProvider to check existence of Identifiers """ @@ -102,10 +102,10 @@ def generate_id(self, proposal: Optional[str] = None) -> model.Identifier: iri = "{}{}".format(self._namespace, proposal) # Try to find iri in provider. If it does not exist (KeyError), we found a unique one to return try: - self.provider.get_identifiable(model.Identifier(iri, model.IdentifierType.IRI)) + self.provider.get_identifiable(iri) except KeyError: self._counter_cache[proposal] = counter - return model.Identifier(iri, model.IdentifierType.IRI) + return iri counter += 1 diff --git a/basyx/aas/util/traversal.py b/basyx/aas/util/traversal.py index 45b1e8a8f..921bdb81a 100644 --- a/basyx/aas/util/traversal.py +++ b/basyx/aas/util/traversal.py @@ -5,7 +5,7 @@ # # SPDX-License-Identifier: MIT """ -A module with helper functions for traversing AAS object strcutures. +A module with helper functions for traversing AAS object structures. """ from typing import Union, Iterator @@ -13,19 +13,42 @@ from .. import model -def walk_submodel(collection: Union[model.Submodel, model.SubmodelElementCollection]) \ +def walk_submodel(collection: Union[model.Submodel, model.SubmodelElementCollection, model.SubmodelElementList]) \ -> Iterator[model.SubmodelElement]: """ Traverse the :class:`SubmodelElements ` in a - :class:`~aas.model.submodel.Submodel` or a :class:`~aas.model.submodel.SubmodelElementCollection` recursively in - post-order tree-traversal. + :class:`~aas.model.submodel.Submodel`, :class:`~aas.model.submodel.SubmodelElementCollection` or a + :class:`~aas.model.submodel.SubmodelElementList` recursively in post-order tree-traversal. - This is a generator function, yielding all the :class:`SubmodelElements `. No - :class:`SubmodelElements ` should be added, removed or + This is a generator function, yielding all the :class:`SubmodelElements `. + No :class:`SubmodelElements ` should be added, removed or moved while iterating, as this could result in undefined behaviour. """ elements = collection.submodel_element if isinstance(collection, model.Submodel) else collection.value for element in elements: - if isinstance(element, model.SubmodelElementCollection): + if isinstance(element, (model.SubmodelElementCollection, model.SubmodelElementList)): yield from walk_submodel(element) yield element + + +def walk_semantic_ids_recursive(root: model.Referable) -> Iterator[model.Reference]: + """ + Traverse an AAS object hierarchy (e.g. a :class:`~aas.model.submodel.Submodel` with all recursively contained + :class:`SubmodelElements `) recursively and return all non-empty (!= None) + semanticIds. + + This is a generator function, yielding all the semanticIds. No :class:`~aas.model.base.Referable` objects should be + added, removed or moved to/from/in the AAS object hierarchy while iterating, as this could result in undefined + behaviour. + """ + if isinstance(root, model.HasSemantics): + if root.semantic_id is not None: + yield root.semantic_id + # Qualifier is the only non-Referable class which HasSemantics + if isinstance(root, model.Qualifiable): + for qualifier in root.qualifier: + if isinstance(qualifier, model.Qualifier) and qualifier.semantic_id is not None: + yield qualifier.semantic_id + if isinstance(root, model.UniqueIdShortNamespace): + for element in root: # iterates Referable objects in Namespace + yield from walk_semantic_ids_recursive(element) diff --git a/docs/source/adapter/index.rst b/docs/source/adapter/index.rst index 1784db014..f24ad4960 100644 --- a/docs/source/adapter/index.rst +++ b/docs/source/adapter/index.rst @@ -10,4 +10,4 @@ adapter: Adapter of AAS-objects from and to different file-formats json xml - aasx \ No newline at end of file + aasx diff --git a/docs/source/constraints.rst b/docs/source/constraints.rst new file mode 100644 index 000000000..25680ab32 --- /dev/null +++ b/docs/source/constraints.rst @@ -0,0 +1,111 @@ +Metamodel-Constraints +===================== + +Here is a quick reference of the constraints as defined in Details of the AssetAdministrationShell Part 1 +and how they are implemented in the Eclipse BaSyx Python SDK. + + +The status information means the following: + +* ✅: the Constraint is enforced in the current version +* ❌: the Constraint cannot be enforced in the current version +* WIP: The Constraint enforcement will be implemented in the future + +In most cases, if a constraint violation is detected, +an :class:`~aas.model.base.AASConstraintViolation` will be raised + +.. |aasd002| replace:: ``idShort`` of ``Referable`` s shall only feature letters, digits, underscore ("_"); starting mandatory with a letter, i.e. [a-zA-Z][a-zA-Z0-9_]* . +.. |aasd005| replace:: If ``AdministrativeInformation/version`` is not specified, ``AdministrativeInformation/revision`` shall also be unspecified. This means that a revision requires a version. If there is no version, there is no revision. Revision is optional. +.. |aasd006| replace:: If both, the ``value`` and the ``valueId`` of a ``Qualifier`` are present, the value needs to be identical to the value of the referenced coded value in ``Qualifier/valueId``. +.. |aasd007| replace:: If both the ``Property/value`` and the ``Property/valueId`` are present, the value of ``Property/value`` needs to be identical to the value of the referenced coded value in ``Property/valueId``. +.. |aasd012| replace:: if both the ``MultiLanguageProperty/value`` and the ``MultiLanguageProperty/valueId`` are present, the meaning must be the same for each string in a specific language, as specified in ``MultiLanguageProperty/valueId``. +.. |aasd014| replace:: Either the attribute ``globalAssetId`` or ``specificAssetId`` of an ``Entity`` must be set if ``Entity/entityType`` is set to "``SelfManagedEntity``". Otherwise, they do not exist. +.. |aasd020| replace:: The value of ``Qualifier/value`` shall be consistent with the data type as defined in ``Qualifier/valueType``. +.. |aasd021| replace:: Every qualifiable can only have one qualifier with the same ``Qualifier/type.`` +.. |aasd022| replace:: ``idShort`` of non-identifiable referables within the same name space shall be unique (case-sensitive). +.. |aasd077| replace:: The name of an extension (``Extension/name``) within ``HasExtensions`` needs to be unique. +.. |aasd080| replace:: In case ``Key/type`` == ``GlobalReference`` ``idType`` shall not be any LocalKeyType (``IdShort, FragmentId``). +.. |aasd081| replace:: In case Key/type==AssetAdministrationShell Key/idType shall not be any LocalKeyType (IdShort, FragmentId). +.. |aasd090| replace:: for data elements, ``category`` (inherited by ``Referable``) shall be one of the following values: CONSTANT, PARAMETER or VARIABLE. Default: VARIABLE +.. |aasd107| replace:: If a first level child element in a ``SubmodelElementList`` has a semanticId, it shall be identical to ``SubmodelElementList/semanticIdListElement``. +.. |aasd108| replace:: All first level child elements in a ``SubmodelElementList`` shall have the same submodel element type as specified in ``SubmodelElementList/typeValueListElement``. +.. |aasd109| replace:: If ``SubmodelElementList/typeValueListElement`` is equal to ``Property`` or ``Range,`` ``SubmodelElementList/valueTypeListElement`` shall be set and all first level child elements in the ``SubmodelElementList`` shall have the value type as specified in ``SubmodelElementList/valueTypeListElement``. +.. |aasd114| replace:: If two first level child elements in a ``SubmodelElementList`` have a ``semanticId``, they shall be identical. +.. |aasd115| replace:: If a first level child element in a ``SubmodelElementList`` does not specify a ``semanticId``, the value is assumed to be identical to ``SubmodelElementList/semanticIdListElement``. +.. |aasd116| replace:: "``globalAssetId``" (case-insensitive) is a reserved key. If used as value for ``SpecificAssetId/name,`` ``SpecificAssetId/value`` shall be identical to ``AssetInformation/globalAssetId``. +.. |aasd117| replace:: ``idShort`` of non-identifiable ``Referable``s not being a direct child of a ``SubmodelElementList`` shall be specified. +.. |aasd118| replace:: If a supplemental semantic ID (``HasSemantics/supplementalSemanticId``) is defined, there shall also be a main semantic ID (``HasSemantics/semanticId``). +.. |aasd119| replace:: If any ``Qualifier/kind`` value of a ``Qualifiable/qualifier`` is equal to ``TemplateQualifier`` and the qualified element inherits from "``hasKind"``, the qualified element shall be of kind ``Template`` (``HasKind/kind = "Template"``). +.. |aasd120| replace:: ``idShort`` of submodel elements being a direct child of a ``SubmodelElementList`` shall not be specified. +.. |aasd121| replace:: For ``Reference``s, the value of ``Key/type`` of the first ``key`` of ``Reference/keys`` shall be one of ``GloballyIdentifiables``. +.. |aasd122| replace:: For external references, i.e. ``Reference``s with ``Reference/type = ExternalReference``, the value of ``Key/type`` of the first key of ``Reference/keys`` shall be one of ``GenericGloballyIdentifiables``. +.. |aasd123| replace:: For model references, i.e. ``Reference``s with ``Reference/type = ModellReference``, the value of ``Key/type`` of the first ``key`` of ``Reference/keys`` shall be one of ``AasIdentifiables.`` +.. |aasd124| replace:: For external references, i.e. ``Reference``s with ``Reference/type = ExternalReference``, the last ``key`` of ``Reference/keys`` shall be either one of ``GenericGloballyIdentifiables`` or one of ``GenericFragmentKeys.`` +.. |aasd125| replace:: For model references, i.e. ``Reference``s with ``Reference/type`` = ``ModelReference`` with more than one key in ``Reference/keys,`` the value of ``Key/type`` of each of the keys following the first key of ``Reference/keys`` shall be one of ``FragmentKeys``. +.. |aasd126| replace:: For model references, i.e. ``Reference``s with ``Reference/type = ModelReference`` with more than one key in ``Reference/keys,`` the value of ``Key/type`` of the last ``Key`` in the reference key chain may be one of ``GenericFragmentKeys`` or no key at all shall have a value out of ``GenericFragmentKeys.`` +.. |aasd127| replace:: For model references, i.e. ``Reference``s with ``Reference/type = ModelReference`` with more than one key in ``Reference/keys,`` a key with ``Key/type`` ``FragmentReference`` shall be preceded by a key with ``Key/type`` ``File`` or ``Blob``. All other Asset Administration Shell fragments, i.e. ``Key/type`` values out of ``AasSubmodelElements,`` do not support fragments. +.. |aasd128| replace:: For model references, i.e. ``Reference``s with ``Reference/type = ModelReference``, the ``Key/value`` of a ``Key`` preceded by a ``Key`` with ``Key/type=SubmodelElementList`` is an integer number denoting the position in the array of the submodel element list. +.. |aasd129| replace:: If any ``Qualifier/kind`` value of a ``SubmodelElement/qualifier`` (attribute ``qualifier`` inherited via ``Qualifiable``) is equal to ``TemplateQualifier``, the submodel element shall be part of a submodel template, i.e. a ``Submodel`` with ``Submodel/kind`` (attribute ``kind`` inherited via ``HasKind``) value equal to ``Template.`` +.. |aasd130| replace:: an attribute with data type "string" shall consist of these characters only: ^[\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u00010000-\u0010FFFF]*$. +.. |aasd131| replace:: The ``globalAssetId`` or at least one ``specificAssetId`` shall be defined for ``AssetInformation``. +.. |aasd133| replace:: ``SpecificAssetId/externalSubjectId`` shall be a global reference, i.e. ``Reference/type = ExternalReference``. +.. |aasd134| replace:: For an ``Operation,`` the ``idShort`` of all ``inputVariable/value``, ``outputVariable/value,`` and ``inoutputVariable/value`` shall be unique. + +.. |aasc003| replace:: For a ``ConceptDescription`` with ``category`` VALUE using data specification template IEC61360 ``DataSpecificationIEC61360/value`` shall be set. +.. |aasc004| replace:: For a ``ConceptDescription`` with ``category`` PROPERTY or VALUE using data specification template IEC61360 - ``DataSpecificationIEC61360/dataType`` is mandatory and shall be defined. +.. |aasc005| replace:: For a ``ConceptDescription`` with ``category`` REFERENCE using data specification template IEC61360 - ``DataSpecificationIEC61360/dataType`` is STRING by default. +.. |aasc006| replace:: For a ``ConceptDescription`` with ``category`` DOCUMENT using data specification template IEC61360 - ``DataSpecificationIEC61360/dataType`` shall be one of the following values: STRING or URL. +.. |aasc007| replace:: For a ``ConceptDescription`` with ``category`` QUALIFIER_TYPE using data specification template IEC61360 - ``DataSpecificationIEC61360/dataType`` is mandatory and shall be defined. +.. |aasc008| replace:: For a ConceptDescriptions except for a ``ConceptDescription`` of ``category`` VALUE using data specification template IEC61360 - ``DataSpecificationIEC61360/definition`` is mandatory and shall be defined at least in English. +.. |aasc009| replace:: If ``DataSpecificationIEC61360/dataType`` one of: INTEGER_MEASURE, REAL_MEASURE, RATIONAL_MEASURE, INTEGER_CURRENCY, REAL_CURRENCY, then ``DataSpecificationIEC61360/unit`` or ``DataSpecificationIEC61360/unitId`` shall be defined. +.. |aasc010| replace:: If ``DataSpecificationIEC61360/value`` is not empty then ``DataSpecificationIEC61360/valueList`` shall be empty and vice versa. + + +.. csv-table:: + :header: "Constraint", "Description", "Status", "Comment" + + AASd-002, |aasd002|, ✅, + AASd-005, |aasd005|, ✅, + AASd-006, |aasd006|, ❌, Uncheckable; cannot check the value of what value_id points to + AASd-007, |aasd007|, ❌, Uncheckable; cannot check the value of what value_id points to + AASd-012, |aasd012|, ❌, Uncheckable + AASd-014, |aasd014|, ✅, + AASd-020, |aasd020|, ✅, + AASd-021, |aasd021|, ✅, + AASd-022, |aasd022|, ✅, + AASd-077, |aasd077|, ✅, + AASd-080, |aasd080|, ✅, + AASd-081, |aasd081|, ✅, + AASd-090, |aasd090|, ✅, + AASd-107, |aasd107|, ✅, + AASd-108, |aasd108|, ✅, + AASd-109, |aasd109|, ✅, + AASd-114, |aasd114|, ✅, + AASd-115, |aasd115|, ❌, postponed + AASd-116, |aasd116|, ❌, postponed + AASd-117, |aasd117|, ✅, + AASd-118, |aasd118|, ✅, + AASd-119, |aasd119|, ❌, See `#119 `_ + AASd-120, |aasd120|, ✅, + AASd-121, |aasd121|, ✅, + AASd-122, |aasd122|, ✅, + AASd-123, |aasd123|, ✅, + AASd-124, |aasd124|, ✅, + AASd-125, |aasd125|, ✅, + AASd-126, |aasd126|, ✅, + AASd-127, |aasd127|, ✅, + AASd-128, |aasd128|, ✅, + AASd-129, |aasd129|, ❌, See `#119 `_ + AASd-130, |aasd130|, ✅, Here a :class:`ValueError` instead of :class:`~aas.model.base.AASConstraintViolation` will be raised. + AASd-131, |aasd131|, ✅, + AASd-133, |aasd133|, ✅, Enforced by the typechecker. See `#119 `_ + AASd-134, |aasd134|, ✅, + + AASc-003, |aasc003|, tbd + AASc-004, |aasc004|, tbd + AASc-005, |aasc005|, tbd + AASc-006, |aasc006|, tbd + AASc-007, |aasc007|, tbd + AASc-008, |aasc008|, tbd + AASc-009, |aasc009|, tbd + AASc-010, |aasc010|, tbd diff --git a/docs/source/index.rst b/docs/source/index.rst index 3cd408e62..065c778ed 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,6 +18,7 @@ Welcome to the Eclipse BaSyx Python SDK's documentation! examples/index compliance_tool/index util/index + constraints Indices and tables diff --git a/docs/source/model/index.rst b/docs/source/model/index.rst index 71601c761..ba8bc8c4d 100644 --- a/docs/source/model/index.rst +++ b/docs/source/model/index.rst @@ -17,5 +17,4 @@ initiating the class. If there is discrepancy between the two, it should be stat concept datatypes provider - security submodel diff --git a/docs/source/model/security.rst b/docs/source/model/security.rst deleted file mode 100644 index 83ea90f0d..000000000 --- a/docs/source/model/security.rst +++ /dev/null @@ -1,5 +0,0 @@ -aas.model.security - Security model of the AAS (currently not existing) -======================================================================= - -.. automodule:: basyx.aas.model.security - :members: diff --git a/docs/source/util/traversal.rst b/docs/source/util/traversal.rst index 32d0ac201..f0ade547b 100644 --- a/docs/source/util/traversal.rst +++ b/docs/source/util/traversal.rst @@ -3,4 +3,4 @@ aas.util.traversal - Functions for Traversing AAS Object structures .. automodule:: basyx.aas.util.traversal - :members: \ No newline at end of file + :members: diff --git a/requirements.txt b/requirements.txt index 4a7e355a5..311a756ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,6 @@ types-python-dateutil pyecma376-2>=0.2.4 psutil>=5.4.8 urllib3>=1.26,<2.0 +Sphinx~=3.5.3 +sphinx-rtd-theme~=0.5.1 +sphinx-argparse~=0.2.3 diff --git a/setup.py b/setup.py index c677112a0..29f8d6e8f 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ package_data={ "basyx": ["py.typed"], "basyx.aas.adapter.json": ["aasJSONSchema.json"], - "basyx.aas.adapter.xml": ["AAS.xsd", "AAS_ABAC.xsd", "IEC61360.xsd"], + "basyx.aas.adapter.xml": ["AAS.xsd"], "basyx.aas.examples.data": ["TestFile.pdf"], }, classifiers=[ diff --git a/test/adapter/aasx/test_aasx.py b/test/adapter/aasx/test_aasx.py index 7584b40aa..9a3111574 100644 --- a/test/adapter/aasx/test_aasx.py +++ b/test/adapter/aasx/test_aasx.py @@ -21,9 +21,9 @@ class TestAASXUtils(unittest.TestCase): def test_name_friendlyfier(self) -> None: friendlyfier = aasx.NameFriendlyfier() - name1 = friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS-a", model.IdentifierType.IRI)) + name1 = friendlyfier.get_friendly_name("http://example.com/AAS-a") self.assertEqual("http___example_com_AAS_a", name1) - name2 = friendlyfier.get_friendly_name(model.Identifier("http://example.com/AAS+a", model.IdentifierType.IRI)) + name2 = friendlyfier.get_friendly_name("http://example.com/AAS+a") self.assertEqual("http___example_com_AAS_a_1", name2) def test_supplementary_file_container(self) -> None: @@ -69,79 +69,50 @@ def test_writing_reading_example_aas(self) -> None: cp.created = datetime.datetime.now() cp.creator = "Eclipse BaSyx Python Testing Framework" - # Write AASX file - for write_json in (False, True): - for submodel_split_parts in (False, True): - with self.subTest(write_json=write_json, submodel_split_parts=submodel_split_parts): - fd, filename = tempfile.mkstemp(suffix=".aasx") - os.close(fd) - - # Write AASX file - # the zipfile library reports errors as UserWarnings via the warnings library. Let's check for - # warnings - with warnings.catch_warnings(record=True) as w: - with aasx.AASXWriter(filename) as writer: - writer.write_aas(model.Identifier(id_='https://acplt.org/Test_AssetAdministrationShell', - id_type=model.IdentifierType.IRI), - data, files, write_json=write_json, - submodel_split_parts=submodel_split_parts) - writer.write_core_properties(cp) - - assert isinstance(w, list) # This should be True due to the record=True parameter - self.assertEqual(0, len(w), f"Warnings were issued while writing the AASX file: " - f"{[warning.message for warning in w]}") - - # Read AASX file - new_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - new_files = aasx.DictSupplementaryFileContainer() - with aasx.AASXReader(filename) as reader: - reader.read_into(new_data, new_files) - new_cp = reader.get_core_properties() - - # Check AAS objects - checker = _helper.AASDataChecker(raise_immediately=True) - example_aas.check_full_example(checker, new_data) - - # Check core properties - assert isinstance(cp.created, datetime.datetime) # to make mypy happy - self.assertIsInstance(new_cp.created, datetime.datetime) - assert isinstance(new_cp.created, datetime.datetime) # to make mypy happy - self.assertAlmostEqual(new_cp.created, cp.created, delta=datetime.timedelta(milliseconds=20)) - self.assertEqual(new_cp.creator, "Eclipse BaSyx Python Testing Framework") - self.assertIsNone(new_cp.lastModifiedBy) - - # Check files - self.assertEqual(new_files.get_content_type("/TestFile.pdf"), "application/pdf") - file_content = io.BytesIO() - new_files.write_file("/TestFile.pdf", file_content) - self.assertEqual(hashlib.sha1(file_content.getvalue()).hexdigest(), - "78450a66f59d74c073bf6858db340090ea72a8b1") - - os.unlink(filename) - - def test_writing_reading_objects_single_part(self) -> None: - # Create example data and file_store - data = example_aas_mandatory_attributes.create_full_example() - files = aasx.DictSupplementaryFileContainer() - # Write AASX file for write_json in (False, True): with self.subTest(write_json=write_json): fd, filename = tempfile.mkstemp(suffix=".aasx") os.close(fd) - with aasx.AASXWriter(filename) as writer: - writer.write_aas_objects('/aasx/aasx.{}'.format('json' if write_json else 'xml'), - [obj.identification for obj in data], - data, files, write_json) + + # Write AASX file + # the zipfile library reports errors as UserWarnings via the warnings library. Let's check for + # warnings + with warnings.catch_warnings(record=True) as w: + with aasx.AASXWriter(filename) as writer: + # TODO test writing multiple AAS + writer.write_aas('https://acplt.org/Test_AssetAdministrationShell', + data, files, write_json=write_json) + writer.write_core_properties(cp) + + assert isinstance(w, list) # This should be True due to the record=True parameter + self.assertEqual(0, len(w), f"Warnings were issued while writing the AASX file: " + f"{[warning.message for warning in w]}") # Read AASX file new_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() new_files = aasx.DictSupplementaryFileContainer() with aasx.AASXReader(filename) as reader: reader.read_into(new_data, new_files) + new_cp = reader.get_core_properties() # Check AAS objects checker = _helper.AASDataChecker(raise_immediately=True) - example_aas_mandatory_attributes.check_full_example(checker, new_data) + example_aas.check_full_example(checker, new_data) + + # Check core properties + assert isinstance(cp.created, datetime.datetime) # to make mypy happy + self.assertIsInstance(new_cp.created, datetime.datetime) + assert isinstance(new_cp.created, datetime.datetime) # to make mypy happy + self.assertAlmostEqual(new_cp.created, cp.created, delta=datetime.timedelta(milliseconds=20)) + self.assertEqual(new_cp.creator, "Eclipse BaSyx Python Testing Framework") + self.assertIsNone(new_cp.lastModifiedBy) + + # Check files + self.assertEqual(new_files.get_content_type("/TestFile.pdf"), "application/pdf") + file_content = io.BytesIO() + new_files.write_file("/TestFile.pdf", file_content) + self.assertEqual(hashlib.sha1(file_content.getvalue()).hexdigest(), + "78450a66f59d74c073bf6858db340090ea72a8b1") os.unlink(filename) diff --git a/test/adapter/json/test_json_deserialization.py b/test/adapter/json/test_json_deserialization.py index 30b920145..7f127be93 100644 --- a/test/adapter/json/test_json_deserialization.py +++ b/test/adapter/json/test_json_deserialization.py @@ -21,44 +21,28 @@ class JsonDeserializationTest(unittest.TestCase): - def test_file_format_missing_list(self) -> None: - data = """ - { - "assetAdministrationShells": [], - "assets": [], - "conceptDescriptions": [] - }""" - with self.assertRaisesRegex(KeyError, r"submodels"): - read_aas_json_file(io.StringIO(data), failsafe=False) - with self.assertLogs(logging.getLogger(), level=logging.WARNING) as cm: - read_aas_json_file(io.StringIO(data), failsafe=True) - self.assertIn("submodels", cm.output[0]) # type: ignore - def test_file_format_wrong_list(self) -> None: data = """ { "assetAdministrationShells": [], - "assets": [], "conceptDescriptions": [], "submodels": [ { - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset", - "idType": "IRI" - }, - "kind": "Instance" + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_Asset", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "https://acplt.org/Test_AssetId" + } } ] }""" - with self.assertRaisesRegex(TypeError, r"submodels.*Asset"): + with self.assertRaisesRegex(TypeError, r"submodels.*AssetAdministrationShell"): read_aas_json_file(io.StringIO(data), failsafe=False) with self.assertLogs(logging.getLogger(), level=logging.WARNING) as cm: read_aas_json_file(io.StringIO(data), failsafe=True) self.assertIn("submodels", cm.output[0]) # type: ignore - self.assertIn("Asset", cm.output[0]) # type: ignore + self.assertIn("AssetAdministrationShell", cm.output[0]) # type: ignore def test_file_format_unknown_object(self) -> None: data = """ @@ -77,69 +61,64 @@ def test_file_format_unknown_object(self) -> None: self.assertIn("submodels", cm.output[0]) # type: ignore self.assertIn("'foo'", cm.output[0]) # type: ignore - def test_broken_asset(self) -> None: + def test_broken_submodel(self) -> None: data = """ [ { - "modelType": {"name": "Asset"}, - "kind": "Instance" + "modelType": "Submodel" }, { - "modelType": {"name": "Asset"}, - "identification": ["https://acplt.org/Test_Asset_broken_id", "IRI"], - "kind": "Instance" + "modelType": "Submodel", + "id": ["https://acplt.org/Test_Submodel_broken_id", "IRI"] }, { - "modelType": {"name": "Asset"}, - "identification": {"id": "https://acplt.org/Test_Asset", "idType": "IRI"}, - "kind": "Instance" + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel" } ]""" # In strict mode, we should catch an exception - with self.assertRaisesRegex(KeyError, r"identification"): + with self.assertRaisesRegex(KeyError, r"id"): json.loads(data, cls=StrictAASFromJsonDecoder) - # In failsafe mode, we should get a log entry and the first Asset entry should be returned as untouched dict + # In failsafe mode, we should get a log entry and the first Submodel entry should be returned as untouched dict with self.assertLogs(logging.getLogger(), level=logging.WARNING) as cm: parsed_data = json.loads(data, cls=AASFromJsonDecoder) - self.assertIn("identification", cm.output[0]) # type: ignore + self.assertIn("id", cm.output[0]) # type: ignore self.assertIsInstance(parsed_data, list) self.assertEqual(3, len(parsed_data)) self.assertIsInstance(parsed_data[0], dict) self.assertIsInstance(parsed_data[1], dict) - self.assertIsInstance(parsed_data[2], model.Asset) - self.assertEqual("https://acplt.org/Test_Asset", parsed_data[2].identification.id) + self.assertIsInstance(parsed_data[2], model.Submodel) + self.assertEqual("https://acplt.org/Test_Submodel", parsed_data[2].id) def test_wrong_submodel_element_type(self) -> None: data = """ [ { - "modelType": {"name": "Submodel"}, - "identification": { - "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", "submodelElements": [ { - "modelType": {"name": "Asset"}, - "identification": {"id": "https://acplt.org/Test_Asset", "idType": "IRI"}, - "kind": "Instance" + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel" }, { - "modelType": "Broken modelType" + "modelType": { + "name": "Broken modelType" + } }, { - "modelType": {"name": "Capability"}, + "modelType": "Capability", "idShort": "TestCapability" } ] } ]""" - # In strict mode, we should catch an exception for the unexpected Asset within the Submodel + # In strict mode, we should catch an exception for the unexpected Submodel within the Submodel # The broken object should not raise an exception, but log a warning, even in strict mode. with self.assertLogs(logging.getLogger(), level=logging.WARNING) as cm: - with self.assertRaisesRegex(TypeError, r"SubmodelElement.*Asset"): + with self.assertRaisesRegex(TypeError, r"SubmodelElement.*Submodel"): json.loads(data, cls=StrictAASFromJsonDecoder) self.assertIn("modelType", cm.output[0]) # type: ignore @@ -161,22 +140,17 @@ def test_duplicate_identifier(self) -> None: data = """ { "assetAdministrationShells": [{ - "modelType": {"name": "AssetAdministrationShell"}, - "identification": {"idType": "IRI", "id": "http://acplt.org/test_aas"}, - "asset": { - "keys": [{ - "idType": "IRI", - "local": false, - "type": "Asset", - "value": "http://acplt.org/test_aas" - }] + "modelType": "AssetAdministrationShell", + "id": "http://acplt.org/test_aas", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "https://acplt.org/Test_AssetId" } }], "submodels": [{ - "modelType": {"name": "Submodel"}, - "identification": {"idType": "IRI", "id": "http://acplt.org/test_aas"} + "modelType": "Submodel", + "id": "http://acplt.org/test_aas" }], - "assets": [], "conceptDescriptions": [] }""" string_io = io.StringIO(data) @@ -188,7 +162,7 @@ def test_duplicate_identifier(self) -> None: read_aas_json_file(string_io, failsafe=False) def test_duplicate_identifier_object_store(self) -> None: - sm_id = model.Identifier("http://acplt.org/test_submodel", model.IdentifierType.IRI) + sm_id = "http://acplt.org/test_submodel" def get_clean_store() -> model.DictObjectStore: store: model.DictObjectStore = model.DictObjectStore() @@ -199,12 +173,11 @@ def get_clean_store() -> model.DictObjectStore: data = """ { "submodels": [{ - "modelType": {"name": "Submodel"}, - "identification": {"idType": "IRI", "id": "http://acplt.org/test_submodel"}, + "modelType": "Submodel", + "id": "http://acplt.org/test_submodel", "idShort": "test456" }], "assetAdministrationShells": [], - "assets": [], "conceptDescriptions": [] }""" @@ -242,27 +215,26 @@ def get_clean_store() -> model.DictObjectStore: class JsonDeserializationDerivingTest(unittest.TestCase): def test_asset_constructor_overriding(self) -> None: - class EnhancedAsset(model.Asset): + class EnhancedSubmodel(model.Submodel): def __init__(self, **kwargs): super().__init__(**kwargs) self.enhanced_attribute = "fancy!" - class EnhancedAASDecoder(AASFromJsonDecoder): + class EnhancedAASDecoder(StrictAASFromJsonDecoder): @classmethod - def _construct_asset(cls, dct): - return super()._construct_asset(dct, object_class=EnhancedAsset) + def _construct_submodel(cls, dct, object_class=EnhancedSubmodel): + return super()._construct_submodel(dct, object_class=object_class) data = """ [ { - "modelType": {"name": "Asset"}, - "identification": {"id": "https://acplt.org/Test_Asset", "idType": "IRI"}, - "kind": "Instance" + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel" } ]""" parsed_data = json.loads(data, cls=EnhancedAASDecoder) self.assertEqual(1, len(parsed_data)) - self.assertIsInstance(parsed_data[0], EnhancedAsset) + self.assertIsInstance(parsed_data[0], EnhancedSubmodel) self.assertEqual(parsed_data[0].enhanced_attribute, "fancy!") @@ -270,25 +242,23 @@ class JsonDeserializationStrippedObjectsTest(unittest.TestCase): def test_stripped_qualifiable(self) -> None: data = """ { - "modelType": {"name": "Submodel"}, - "identification": {"idType": "IRI", "id": "http://acplt.org/test_stripped_submodel"}, + "modelType": "Submodel", + "id": "http://acplt.org/test_stripped_submodel", "submodelElements": [{ - "modelType": {"name": "Operation"}, + "modelType": "Operation", "idShort": "test_operation", "qualifiers": [{ - "modelType": {"name": "Qualifier"}, "type": "test_qualifier", - "valueType": "string" + "valueType": "xs:string" }] }], "qualifiers": [{ - "modelType": {"name": "Qualifier"}, "type": "test_qualifier", - "valueType": "string" + "valueType": "xs:string" }] }""" - # check if JSON with constraints can be parsed successfully + # check if JSON with qualifiers can be parsed successfully submodel = json.loads(data, cls=StrictAASFromJsonDecoder) self.assertIsInstance(submodel, model.Submodel) assert isinstance(submodel, model.Submodel) @@ -296,7 +266,7 @@ def test_stripped_qualifiable(self) -> None: operation = submodel.submodel_element.pop() self.assertEqual(len(operation.qualifier), 1) - # check if constraints are ignored in stripped mode + # check if qualifiers are ignored in stripped mode submodel = json.loads(data, cls=StrictStrippedAASFromJsonDecoder) self.assertIsInstance(submodel, model.Submodel) assert isinstance(submodel, model.Submodel) @@ -306,27 +276,39 @@ def test_stripped_qualifiable(self) -> None: def test_stripped_annotated_relationship_element(self) -> None: data = """ { - "modelType": {"name": "AnnotatedRelationshipElement"}, + "modelType": "AnnotatedRelationshipElement", "idShort": "test_annotated_relationship_element", + "category": "PARAMETER", "first": { - "keys": [{ - "idType": "IdShort", - "local": true, - "type": "AnnotatedRelationshipElement", - "value": "test_ref" - }] + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "AnnotatedRelationshipElement", + "value": "test_ref" + } + ] }, "second": { - "keys": [{ - "idType": "IdShort", - "local": true, - "type": "AnnotatedRelationshipElement", - "value": "test_ref" - }] + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "AnnotatedRelationshipElement", + "value": "test_ref" + } + ] }, - "annotation": [{ - "modelType": {"name": "MultiLanguageProperty"}, - "idShort": "test_multi_language_property" + "annotations": [{ + "modelType": "MultiLanguageProperty", + "idShort": "test_multi_language_property", + "category": "CONSTANT" }] }""" @@ -345,11 +327,12 @@ def test_stripped_annotated_relationship_element(self) -> None: def test_stripped_entity(self) -> None: data = """ { - "modelType": {"name": "Entity"}, + "modelType": "Entity", "idShort": "test_entity", - "entityType": "CoManagedEntity", + "entityType": "SelfManagedEntity", + "globalAssetId": "test_asset", "statements": [{ - "modelType": {"name": "MultiLanguageProperty"}, + "modelType": "MultiLanguageProperty", "idShort": "test_multi_language_property" }] }""" @@ -369,64 +352,51 @@ def test_stripped_entity(self) -> None: def test_stripped_submodel_element_collection(self) -> None: data = """ { - "modelType": {"name": "SubmodelElementCollection"}, + "modelType": "SubmodelElementCollection", "idShort": "test_submodel_element_collection", - "ordered": false, "value": [{ - "modelType": {"name": "MultiLanguageProperty"}, + "modelType": "MultiLanguageProperty", "idShort": "test_multi_language_property" }] }""" # check if JSON with value can be parsed successfully sec = json.loads(data, cls=StrictAASFromJsonDecoder) - self.assertIsInstance(sec, model.SubmodelElementCollectionUnordered) - assert isinstance(sec, model.SubmodelElementCollectionUnordered) + self.assertIsInstance(sec, model.SubmodelElementCollection) + assert isinstance(sec, model.SubmodelElementCollection) self.assertEqual(len(sec.value), 1) # check if value is ignored in stripped mode sec = json.loads(data, cls=StrictStrippedAASFromJsonDecoder) - self.assertIsInstance(sec, model.SubmodelElementCollectionUnordered) - assert isinstance(sec, model.SubmodelElementCollectionUnordered) + self.assertIsInstance(sec, model.SubmodelElementCollection) + assert isinstance(sec, model.SubmodelElementCollection) self.assertEqual(len(sec.value), 0) def test_stripped_asset_administration_shell(self) -> None: data = """ { - "modelType": {"name": "AssetAdministrationShell"}, - "identification": {"idType": "IRI", "id": "http://acplt.org/test_aas"}, - "asset": { - "keys": [{ - "idType": "IRI", - "local": false, - "type": "Asset", - "value": "http://acplt.org/test_aas" - }] + "modelType": "AssetAdministrationShell", + "id": "http://acplt.org/test_aas", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "test_asset" }, "submodels": [{ + "type": "ModelReference", "keys": [{ - "idType": "IRI", - "local": false, "type": "Submodel", "value": "http://acplt.org/test_submodel" }] - }], - "views": [{ - "modelType": {"name": "View"}, - "idShort": "test_view" }] }""" - - # check if JSON with submodels and views can be parsed successfully + # check if JSON with submodels can be parsed successfully aas = json.loads(data, cls=StrictAASFromJsonDecoder) self.assertIsInstance(aas, model.AssetAdministrationShell) assert isinstance(aas, model.AssetAdministrationShell) self.assertEqual(len(aas.submodel), 1) - self.assertEqual(len(aas.view), 1) - # check if submodels and views are ignored in stripped mode + # check if submodels are ignored in stripped mode aas = json.loads(data, cls=StrictStrippedAASFromJsonDecoder) self.assertIsInstance(aas, model.AssetAdministrationShell) assert isinstance(aas, model.AssetAdministrationShell) self.assertEqual(len(aas.submodel), 0) - self.assertEqual(len(aas.view), 0) diff --git a/test/adapter/json/test_json_serialization.py b/test/adapter/json/test_json_serialization.py index 430b7cedd..3195c8a06 100644 --- a/test/adapter/json/test_json_serialization.py +++ b/test/adapter/json/test_json_serialization.py @@ -14,26 +14,25 @@ from jsonschema import validate # type: ignore from typing import Set, Union -from basyx.aas.examples.data import example_concept_description, example_aas_missing_attributes, example_aas, \ +from basyx.aas.examples.data import example_aas_missing_attributes, example_aas, \ example_aas_mandatory_attributes, example_submodel_template, create_example class JsonSerializationTest(unittest.TestCase): def test_serialize_object(self) -> None: test_object = model.Property("test_id_short", model.datatypes.String, category="PARAMETER", - description={"en-us": "Germany", "de": "Deutschland"}) + description=model.MultiLanguageTextType({"en-US": "Germany", "de": "Deutschland"})) json_data = json.dumps(test_object, cls=AASToJsonEncoder) def test_random_object_serialization(self) -> None: - asset_key = (model.Key(model.KeyElements.ASSET, True, "asset", model.KeyType.CUSTOM),) - asset_reference = model.AASReference(asset_key, model.Asset) - aas_identifier = model.Identifier("AAS1", model.IdentifierType.CUSTOM) - submodel_key = (model.Key(model.KeyElements.SUBMODEL, True, "SM1", model.KeyType.CUSTOM),) + aas_identifier = "AAS1" + submodel_key = (model.Key(model.KeyTypes.SUBMODEL, "SM1"),) submodel_identifier = submodel_key[0].get_identifier() assert submodel_identifier is not None - submodel_reference = model.AASReference(submodel_key, model.Submodel) + submodel_reference = model.ModelReference(submodel_key, model.Submodel) submodel = model.Submodel(submodel_identifier) - test_aas = model.AssetAdministrationShell(asset_reference, aas_identifier, submodel={submodel_reference}) + test_aas = model.AssetAdministrationShell(model.AssetInformation(global_asset_id="test"), + aas_identifier, submodel={submodel_reference}) # serialize object to json json_data = json.dumps({ @@ -47,25 +46,23 @@ def test_random_object_serialization(self) -> None: class JsonSerializationSchemaTest(unittest.TestCase): def test_random_object_serialization(self) -> None: - asset_key = (model.Key(model.KeyElements.ASSET, True, "asset", model.KeyType.CUSTOM),) - asset_reference = model.AASReference(asset_key, model.Asset) - aas_identifier = model.Identifier("AAS1", model.IdentifierType.CUSTOM) - submodel_key = (model.Key(model.KeyElements.SUBMODEL, True, "SM1", model.KeyType.CUSTOM),) + aas_identifier = "AAS1" + submodel_key = (model.Key(model.KeyTypes.SUBMODEL, "SM1"),) submodel_identifier = submodel_key[0].get_identifier() assert submodel_identifier is not None - submodel_reference = model.AASReference(submodel_key, model.Submodel) + submodel_reference = model.ModelReference(submodel_key, model.Submodel) # The JSONSchema expects every object with HasSemnatics (like Submodels) to have a `semanticId` Reference, which # must be a Reference. (This seems to be a bug in the JSONSchema.) - submodel = model.Submodel(submodel_identifier, semantic_id=model.Reference((model.Key( - model.KeyElements.GLOBAL_REFERENCE, False, "http://acplt.org/TestSemanticId", model.KeyType.IRI),))) - test_aas = model.AssetAdministrationShell(asset_reference, aas_identifier, submodel={submodel_reference}) + submodel = model.Submodel(submodel_identifier, + semantic_id=model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, + "http://acplt.org/TestSemanticId"),))) + test_aas = model.AssetAdministrationShell(model.AssetInformation(global_asset_id="test"), + aas_identifier, submodel={submodel_reference}) # serialize object to json json_data = json.dumps({ 'assetAdministrationShells': [test_aas], - 'submodels': [submodel], - 'assets': [], - 'conceptDescriptions': [], + 'submodels': [submodel] }, cls=AASToJsonEncoder) json_data_new = json.loads(json_data) @@ -135,7 +132,7 @@ def test_missing_serialization(self) -> None: def test_concept_description_serialization(self) -> None: data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - data.add(example_concept_description.create_iec61360_concept_description()) + data.add(example_aas.create_example_concept_description()) file = io.StringIO() write_aas_json_file(file=file, data=data) @@ -177,20 +174,21 @@ def _checkNormalAndStripped(self, attributes: Union[Set[str], str], obj: object) def test_stripped_qualifiable(self) -> None: qualifier = model.Qualifier("test_qualifier", str) + qualifier2 = model.Qualifier("test_qualifier2", str) operation = model.Operation("test_operation", qualifier={qualifier}) submodel = model.Submodel( - model.Identifier("http://acplt.org/test_submodel", model.IdentifierType.IRI), + "http://acplt.org/test_submodel", submodel_element=[operation], - qualifier={qualifier} + qualifier={qualifier2} ) self._checkNormalAndStripped({"submodelElements", "qualifiers"}, submodel) self._checkNormalAndStripped("qualifiers", operation) def test_stripped_annotated_relationship_element(self) -> None: - mlp = model.MultiLanguageProperty("test_multi_language_property") - ref = model.AASReference( - (model.Key(model.KeyElements.SUBMODEL, False, "http://acplt.org/test_ref", model.KeyType.IRI),), + mlp = model.MultiLanguageProperty("test_multi_language_property", category="PARAMETER") + ref = model.ModelReference( + (model.Key(model.KeyTypes.SUBMODEL, "http://acplt.org/test_ref"),), model.Submodel ) are = model.AnnotatedRelationshipElement( @@ -200,34 +198,29 @@ def test_stripped_annotated_relationship_element(self) -> None: annotation=[mlp] ) - self._checkNormalAndStripped("annotation", are) + self._checkNormalAndStripped("annotations", are) def test_stripped_entity(self) -> None: - mlp = model.MultiLanguageProperty("test_multi_language_property") + mlp = model.MultiLanguageProperty("test_multi_language_property", category="PARAMETER") entity = model.Entity("test_entity", model.EntityType.CO_MANAGED_ENTITY, statement=[mlp]) self._checkNormalAndStripped("statements", entity) def test_stripped_submodel_element_collection(self) -> None: - mlp = model.MultiLanguageProperty("test_multi_language_property") - sec = model.SubmodelElementCollectionOrdered("test_submodel_element_collection", value=[mlp]) + mlp = model.MultiLanguageProperty("test_multi_language_property", category="PARAMETER") + sec = model.SubmodelElementCollection("test_submodel_element_collection", value=[mlp]) self._checkNormalAndStripped("value", sec) def test_stripped_asset_administration_shell(self) -> None: - asset_ref = model.AASReference( - (model.Key(model.KeyElements.ASSET, False, "http://acplt.org/test_ref", model.KeyType.IRI),), - model.Asset - ) - submodel_ref = model.AASReference( - (model.Key(model.KeyElements.SUBMODEL, False, "http://acplt.org/test_ref", model.KeyType.IRI),), + submodel_ref = model.ModelReference( + (model.Key(model.KeyTypes.SUBMODEL, "http://acplt.org/test_ref"),), model.Submodel ) aas = model.AssetAdministrationShell( - asset_ref, - model.Identifier("http://acplt.org/test_aas", model.IdentifierType.IRI), - submodel={submodel_ref}, - view=[model.View("test_view")] + model.AssetInformation(global_asset_id="http://acplt.org/test_ref"), + "http://acplt.org/test_aas", + submodel={submodel_ref} ) - self._checkNormalAndStripped({"submodels", "views"}, aas) + self._checkNormalAndStripped({"submodels"}, aas) diff --git a/test/adapter/json/test_json_serialization_deserialization.py b/test/adapter/json/test_json_serialization_deserialization.py index d85228eb1..2d64af353 100644 --- a/test/adapter/json/test_json_serialization_deserialization.py +++ b/test/adapter/json/test_json_serialization_deserialization.py @@ -12,22 +12,21 @@ from basyx.aas import model from basyx.aas.adapter.json import AASToJsonEncoder, write_aas_json_file, read_aas_json_file -from basyx.aas.examples.data import example_concept_description, example_aas_missing_attributes, example_aas, \ +from basyx.aas.examples.data import example_aas_missing_attributes, example_aas, \ example_aas_mandatory_attributes, example_submodel_template, create_example from basyx.aas.examples.data._helper import AASDataChecker class JsonSerializationDeserializationTest(unittest.TestCase): def test_random_object_serialization_deserialization(self) -> None: - asset_key = (model.Key(model.KeyElements.ASSET, True, "asset", model.KeyType.CUSTOM),) - asset_reference = model.AASReference(asset_key, model.Asset) - aas_identifier = model.Identifier("AAS1", model.IdentifierType.CUSTOM) - submodel_key = (model.Key(model.KeyElements.SUBMODEL, True, "SM1", model.KeyType.CUSTOM),) + aas_identifier = "AAS1" + submodel_key = (model.Key(model.KeyTypes.SUBMODEL, "SM1"),) submodel_identifier = submodel_key[0].get_identifier() assert submodel_identifier is not None - submodel_reference = model.AASReference(submodel_key, model.Submodel) + submodel_reference = model.ModelReference(submodel_key, model.Submodel) submodel = model.Submodel(submodel_identifier) - test_aas = model.AssetAdministrationShell(asset_reference, aas_identifier, submodel={submodel_reference}) + test_aas = model.AssetAdministrationShell(model.AssetInformation(global_asset_id="test"), + aas_identifier, submodel={submodel_reference}) # serialize object to json json_data = json.dumps({ @@ -92,19 +91,6 @@ def test_example_submodel_template_serialization_deserialization(self) -> None: class JsonSerializationDeserializationTest5(unittest.TestCase): - def test_example_iec61360_concept_description_serialization_deserialization(self) -> None: - data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - data.add(example_concept_description.create_iec61360_concept_description()) - file = io.StringIO() - write_aas_json_file(file=file, data=data) - # try deserializing the json string into a DictObjectStore of AAS objects with help of the json module - file.seek(0) - json_object_store = read_aas_json_file(file, failsafe=False) - checker = AASDataChecker(raise_immediately=True) - example_concept_description.check_full_example(checker, json_object_store) - - -class JsonSerializationDeserializationTest6(unittest.TestCase): def test_example_all_examples_serialization_deserialization(self) -> None: data: model.DictObjectStore[model.Identifiable] = create_example() file = io.StringIO() diff --git a/test/adapter/xml/test_xml_deserialization.py b/test/adapter/xml/test_xml_deserialization.py index 714dee132..4ff06aa60 100644 --- a/test/adapter/xml/test_xml_deserialization.py +++ b/test/adapter/xml/test_xml_deserialization.py @@ -12,6 +12,7 @@ from basyx.aas import model from basyx.aas.adapter.xml import StrictAASFromXmlDecoder, XMLConstructables, read_aas_xml_file, \ read_aas_xml_file_into, read_aas_xml_element +from basyx.aas.adapter._generic import XML_NS_MAP from lxml import etree # type: ignore from typing import Iterable, Type, Union @@ -19,11 +20,7 @@ def _xml_wrap(xml: str) -> str: return \ """""" \ - """""" \ + f""" """ \ + xml + """""" @@ -72,145 +69,137 @@ def test_invalid_list_name(self) -> None: def test_invalid_element_in_list(self) -> None: xml = _xml_wrap(""" - + - - """) - self._assertInExceptionAndLog(xml, ["aas:invalidElement", "aas:assets"], KeyError, logging.WARNING) - - def test_missing_identification_attribute(self) -> None: - xml = _xml_wrap(""" - - - http://acplt.org/test_asset - Instance - - - """) - self._assertInExceptionAndLog(xml, "idType", KeyError, logging.ERROR) - - def test_invalid_identification_attribute_value(self) -> None: - xml = _xml_wrap(""" - - - http://acplt.org/test_asset - Instance - - + """) - self._assertInExceptionAndLog(xml, ["idType", "invalid"], ValueError, logging.ERROR) + self._assertInExceptionAndLog(xml, ["aas:invalidElement", "aas:submodels"], KeyError, logging.WARNING) def test_missing_asset_kind(self) -> None: xml = _xml_wrap(""" - - - - + + + http://acplt.org/test_aas + + http://acplt.org/TestAsset/ + + + """) - self._assertInExceptionAndLog(xml, "aas:kind", KeyError, logging.ERROR) + self._assertInExceptionAndLog(xml, "aas:assetKind", KeyError, logging.ERROR) def test_missing_asset_kind_text(self) -> None: xml = _xml_wrap(""" - - - - - + + + http://acplt.org/test_aas + + + http://acplt.org/TestAsset/ + + + """) - self._assertInExceptionAndLog(xml, "aas:kind", KeyError, logging.ERROR) + self._assertInExceptionAndLog(xml, "aas:assetKind", KeyError, logging.ERROR) def test_invalid_asset_kind_text(self) -> None: xml = _xml_wrap(""" - - - invalidKind - - + + + http://acplt.org/test_aas + + invalidKind + http://acplt.org/TestAsset/ + + + """) - self._assertInExceptionAndLog(xml, ["aas:kind", "invalidKind"], ValueError, logging.ERROR) + self._assertInExceptionAndLog(xml, ["aas:assetKind", "invalidKind"], ValueError, logging.ERROR) def test_invalid_boolean(self) -> None: xml = _xml_wrap(""" - - - http://acplt.org/test_asset - - - http://acplt.org/test_ref - - - - + + + http://acplt.org/test_submodel + + + False + collection + Capability + + + + """) self._assertInExceptionAndLog(xml, "False", ValueError, logging.ERROR) - def test_no_modeling_kind(self) -> None: + def test_no_modelling_kind(self) -> None: xml = _xml_wrap(""" - http://acplt.org/test_submodel - + http://acplt.org/test_submodel """) # should get parsed successfully object_store = read_aas_xml_file(io.BytesIO(xml.encode("utf-8")), failsafe=False) - # modeling kind should default to INSTANCE + # modelling kind should default to INSTANCE submodel = object_store.pop() self.assertIsInstance(submodel, model.Submodel) assert isinstance(submodel, model.Submodel) # to make mypy happy - self.assertEqual(submodel.kind, model.ModelingKind.INSTANCE) + self.assertEqual(submodel.kind, model.ModellingKind.INSTANCE) def test_reference_kind_mismatch(self) -> None: xml = _xml_wrap(""" - http://acplt.org/test_aas - + http://acplt.org/test_aas + + Instance + http://acplt.org/TestAsset/ + + + ModelReference - http://acplt.org/test_ref + + Submodel + http://acplt.org/test_ref + - + """) with self.assertLogs(logging.getLogger(), level=logging.WARNING) as context: read_aas_xml_file(io.BytesIO(xml.encode("utf-8")), failsafe=False) - for s in ("GLOBAL_REFERENCE", "IRI=http://acplt.org/test_ref", "Asset"): + for s in ("SUBMODEL", "http://acplt.org/test_ref", "AssetAdministrationShell"): self.assertIn(s, context.output[0]) def test_invalid_submodel_element(self) -> None: - # TODO: simplify this should our suggestion regarding the XML schema get accepted - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 xml = _xml_wrap(""" - http://acplt.org/test_submodel + http://acplt.org/test_submodel - - - + """) self._assertInExceptionAndLog(xml, "aas:invalidSubmodelElement", KeyError, logging.ERROR) - def test_invalid_constraint(self) -> None: - # TODO: simplify this should our suggestion regarding the XML schema get accepted - # https://git.rwth-aachen.de/acplt/pyi40aas/-/issues/57 + def test_empty_qualifier(self) -> None: xml = _xml_wrap(""" - http://acplt.org/test_submodel - - - - + http://acplt.org/test_submodel + + + """) - self._assertInExceptionAndLog(xml, "aas:invalidConstraint", KeyError, logging.ERROR) + self._assertInExceptionAndLog(xml, ["aas:qualifier", "has no child aas:type"], KeyError, logging.ERROR) def test_operation_variable_no_submodel_element(self) -> None: # TODO: simplify this should our suggestion regarding the XML schema get accepted @@ -218,16 +207,16 @@ def test_operation_variable_no_submodel_element(self) -> None: xml = _xml_wrap(""" - http://acplt.org/test_submodel + http://acplt.org/test_submodel - - - test_operation - + + test_operation + + - - - + + + @@ -240,25 +229,26 @@ def test_operation_variable_too_many_submodel_elements(self) -> None: xml = _xml_wrap(""" - http://acplt.org/test_submodel + http://acplt.org/test_submodel - - - test_operation - + + test_operation + + + Template test_file - application/problem+xml + application/problem+xml test_file2 - application/problem+xml + application/problem+xml - - - + + + @@ -272,25 +262,23 @@ def test_duplicate_identifier(self) -> None: xml = _xml_wrap(""" - http://acplt.org/test_aas - - - http://acplt.org/asset_ref - - + http://acplt.org/test_aas + + Instance + http://acplt.org/TestAsset/ + - http://acplt.org/test_aas - + http://acplt.org/test_aas """) self._assertInExceptionAndLog(xml, "duplicate identifier", KeyError, logging.ERROR) def test_duplicate_identifier_object_store(self) -> None: - sm_id = model.Identifier("http://acplt.org/test_submodel", model.IdentifierType.IRI) + sm_id = "http://acplt.org/test_submodel" def get_clean_store() -> model.DictObjectStore: store: model.DictObjectStore = model.DictObjectStore() @@ -301,9 +289,8 @@ def get_clean_store() -> model.DictObjectStore: xml = _xml_wrap(""" - http://acplt.org/test_submodel + http://acplt.org/test_submodel test456 - """) @@ -336,10 +323,9 @@ def get_clean_store() -> model.DictObjectStore: self.assertEqual(submodel.id_short, "test123") def test_read_aas_xml_element(self) -> None: - xml = """ - - http://acplt.org/test_submodel - + xml = f""" + + http://acplt.org/test_submodel """ bytes_io = io.BytesIO(xml.encode("utf-8")) @@ -350,33 +336,31 @@ def test_read_aas_xml_element(self) -> None: class XmlDeserializationStrippedObjectsTest(unittest.TestCase): def test_stripped_qualifiable(self) -> None: - xml = """ - - http://acplt.org/test_stripped_submodel + xml = f""" + + http://acplt.org/test_stripped_submodel - - - test_operation + + test_operation + - - test_qualifier - string - + test_qualifier + xs:string - - + + - + test_qualifier - string + xs:string - + """ bytes_io = io.BytesIO(xml.encode("utf-8")) - # check if XML with constraints can be parsed successfully + # check if XML with qualifiers can be parsed successfully submodel = read_aas_xml_element(bytes_io, XMLConstructables.SUBMODEL, failsafe=False) self.assertIsInstance(submodel, model.Submodel) assert isinstance(submodel, model.Submodel) @@ -384,109 +368,48 @@ def test_stripped_qualifiable(self) -> None: operation = submodel.submodel_element.pop() self.assertEqual(len(operation.qualifier), 1) - # check if constraints are ignored in stripped mode + # check if qualifiers are ignored in stripped mode submodel = read_aas_xml_element(bytes_io, XMLConstructables.SUBMODEL, failsafe=False, stripped=True) self.assertIsInstance(submodel, model.Submodel) assert isinstance(submodel, model.Submodel) self.assertEqual(len(submodel.qualifier), 0) self.assertEqual(len(submodel.submodel_element), 0) - def test_stripped_annotated_relationship_element(self) -> None: - xml = """ - - test_annotated_relationship_element - - - test_ref - - - - - test_ref - - - - """ - bytes_io = io.BytesIO(xml.encode("utf-8")) - - # XML schema requires annotations to be present, so parsing should fail - with self.assertRaises(KeyError): - read_aas_xml_element(bytes_io, XMLConstructables.ANNOTATED_RELATIONSHIP_ELEMENT, failsafe=False) - - # check if it can be parsed in stripped mode - read_aas_xml_element(bytes_io, XMLConstructables.ANNOTATED_RELATIONSHIP_ELEMENT, failsafe=False, stripped=True) - - def test_stripped_entity(self) -> None: - xml = """ - - test_entity - CoManagedEntity - - """ - bytes_io = io.BytesIO(xml.encode("utf-8")) - - # XML schema requires statements to be present, so parsing should fail - with self.assertRaises(KeyError): - read_aas_xml_element(bytes_io, XMLConstructables.ENTITY, failsafe=False) - - # check if it can be parsed in stripped mode - read_aas_xml_element(bytes_io, XMLConstructables.ENTITY, failsafe=False, stripped=True) - - def test_stripped_submodel_element_collection(self) -> None: - xml = """ - - test_collection - false - - """ - bytes_io = io.BytesIO(xml.encode("utf-8")) - - # XML schema requires value to be present, so parsing should fail - with self.assertRaises(KeyError): - read_aas_xml_element(bytes_io, XMLConstructables.SUBMODEL_ELEMENT_COLLECTION, failsafe=False) - - # check if it can be parsed in stripped mode - read_aas_xml_element(bytes_io, XMLConstructables.SUBMODEL_ELEMENT_COLLECTION, failsafe=False, stripped=True) - def test_stripped_asset_administration_shell(self) -> None: - xml = """ - - http://acplt.org/test_aas - - - http://acplt.org/test_ref - - - - + xml = f""" + + http://acplt.org/test_aas + + Instance + http://acplt.org/TestAsset/ + + + + ModelReference - http://acplt.org/test_ref + + Submodel + http://acplt.org/test_ref + - - - - - test_view - - + + """ bytes_io = io.BytesIO(xml.encode("utf-8")) - # check if XML with submodelRef and views can be parsed successfully + # check if XML with submodels can be parsed successfully aas = read_aas_xml_element(bytes_io, XMLConstructables.ASSET_ADMINISTRATION_SHELL, failsafe=False) self.assertIsInstance(aas, model.AssetAdministrationShell) assert isinstance(aas, model.AssetAdministrationShell) self.assertEqual(len(aas.submodel), 1) - self.assertEqual(len(aas.view), 1) - # check if submodelRef and views are ignored in stripped mode + # check if submodels are ignored in stripped mode aas = read_aas_xml_element(bytes_io, XMLConstructables.ASSET_ADMINISTRATION_SHELL, failsafe=False, stripped=True) self.assertIsInstance(aas, model.AssetAdministrationShell) assert isinstance(aas, model.AssetAdministrationShell) self.assertEqual(len(aas.submodel), 0) - self.assertEqual(len(aas.view), 0) class XmlDeserializationDerivingTest(unittest.TestCase): @@ -502,10 +425,9 @@ def construct_submodel(cls, element: etree.Element, object_class=EnhancedSubmode -> model.Submodel: return super().construct_submodel(element, object_class=object_class, **kwargs) - xml = """ - - http://acplt.org/test_stripped_submodel - + xml = f""" + + http://acplt.org/test_stripped_submodel """ bytes_io = io.BytesIO(xml.encode("utf-8")) diff --git a/test/adapter/xml/test_xml_serialization.py b/test/adapter/xml/test_xml_serialization.py index 30dbc4966..c75bfeaa8 100644 --- a/test/adapter/xml/test_xml_serialization.py +++ b/test/adapter/xml/test_xml_serialization.py @@ -12,7 +12,7 @@ from basyx.aas import model from basyx.aas.adapter.xml import write_aas_xml_file, xml_serialization, XML_SCHEMA_FILE -from basyx.aas.examples.data import example_concept_description, example_aas_missing_attributes, example_aas, \ +from basyx.aas.examples.data import example_aas_missing_attributes, example_aas, \ example_submodel_template, example_aas_mandatory_attributes @@ -21,20 +21,19 @@ def test_serialize_object(self) -> None: test_object = model.Property("test_id_short", model.datatypes.String, category="PARAMETER", - description={"en-us": "Germany", "de": "Deutschland"}) + description=model.MultiLanguageTextType({"en-US": "Germany", "de": "Deutschland"})) xml_data = xml_serialization.property_to_xml(test_object, xml_serialization.NS_AAS+"test_object") # todo: is this a correct way to test it? def test_random_object_serialization(self) -> None: - asset_key = (model.Key(model.KeyElements.ASSET, True, "asset", model.KeyType.CUSTOM),) - asset_reference = model.AASReference(asset_key, model.Asset) - aas_identifier = model.Identifier("AAS1", model.IdentifierType.CUSTOM) - submodel_key = (model.Key(model.KeyElements.SUBMODEL, True, "SM1", model.KeyType.CUSTOM),) + aas_identifier = "AAS1" + submodel_key = (model.Key(model.KeyTypes.SUBMODEL, "SM1"),) submodel_identifier = submodel_key[0].get_identifier() assert (submodel_identifier is not None) - submodel_reference = model.AASReference(submodel_key, model.Submodel) + submodel_reference = model.ModelReference(submodel_key, model.Submodel) submodel = model.Submodel(submodel_identifier) - test_aas = model.AssetAdministrationShell(asset_reference, aas_identifier, submodel={submodel_reference}) + test_aas = model.AssetAdministrationShell(model.AssetInformation(global_asset_id="Test"), + aas_identifier, submodel={submodel_reference}) test_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() test_data.add(test_aas) @@ -46,17 +45,16 @@ def test_random_object_serialization(self) -> None: class XMLSerializationSchemaTest(unittest.TestCase): def test_random_object_serialization(self) -> None: - asset_key = (model.Key(model.KeyElements.ASSET, True, "asset", model.KeyType.CUSTOM),) - asset_reference = model.AASReference(asset_key, model.Asset) - aas_identifier = model.Identifier("AAS1", model.IdentifierType.CUSTOM) - submodel_key = (model.Key(model.KeyElements.SUBMODEL, True, "SM1", model.KeyType.CUSTOM),) + aas_identifier = "AAS1" + submodel_key = (model.Key(model.KeyTypes.SUBMODEL, "SM1"),) submodel_identifier = submodel_key[0].get_identifier() assert submodel_identifier is not None - submodel_reference = model.AASReference(submodel_key, model.Submodel) - submodel = model.Submodel(submodel_identifier, semantic_id=model.Reference((model.Key( - model.KeyElements.GLOBAL_REFERENCE, False, "http://acplt.org/TestSemanticId", model.KeyType.IRI),))) - test_aas = model.AssetAdministrationShell(asset_reference, aas_identifier, submodel={submodel_reference}) - + submodel_reference = model.ModelReference(submodel_key, model.Submodel) + submodel = model.Submodel(submodel_identifier, + semantic_id=model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, + "http://acplt.org/TestSemanticId"),))) + test_aas = model.AssetAdministrationShell(model.AssetInformation(global_asset_id="Test"), + aas_identifier, submodel={submodel_reference}) # serialize object to xml test_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() test_data.add(test_aas) @@ -116,7 +114,7 @@ def test_full_empty_example_serialization(self) -> None: def test_missing_serialization(self) -> None: data = example_aas_missing_attributes.create_full_example() file = io.BytesIO() - write_aas_xml_file(file=file, data=data) + write_aas_xml_file(file=file, data=data, pretty_print=True) # load schema aas_schema = etree.XMLSchema(file=XML_SCHEMA_FILE) @@ -128,7 +126,7 @@ def test_missing_serialization(self) -> None: def test_concept_description(self) -> None: data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - data.add(example_concept_description.create_iec61360_concept_description()) + data.add(example_aas.create_example_concept_description()) file = io.BytesIO() write_aas_xml_file(file=file, data=data) diff --git a/test/adapter/xml/test_xml_serialization_deserialization.py b/test/adapter/xml/test_xml_serialization_deserialization.py index 66931e8f8..c32653914 100644 --- a/test/adapter/xml/test_xml_serialization_deserialization.py +++ b/test/adapter/xml/test_xml_serialization_deserialization.py @@ -11,7 +11,7 @@ from basyx.aas import model from basyx.aas.adapter.xml import write_aas_xml_file, read_aas_xml_file -from basyx.aas.examples.data import example_concept_description, example_aas_missing_attributes, example_aas, \ +from basyx.aas.examples.data import example_aas_missing_attributes, example_aas, \ example_aas_mandatory_attributes, example_submodel_template, create_example from basyx.aas.examples.data._helper import AASDataChecker @@ -48,13 +48,6 @@ def test_example_submodel_template_serialization_deserialization(self) -> None: checker = AASDataChecker(raise_immediately=True) example_submodel_template.check_full_example(checker, object_store) - def test_example_iec61360_concept_description_serialization_deserialization(self) -> None: - data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - data.add(example_concept_description.create_iec61360_concept_description()) - object_store = _serialize_and_deserialize(data) - checker = AASDataChecker(raise_immediately=True) - example_concept_description.check_full_example(checker, object_store) - def test_example_all_examples_serialization_deserialization(self) -> None: data: model.DictObjectStore[model.Identifiable] = create_example() object_store = _serialize_and_deserialize(data) diff --git a/test/backend/test_couchdb.py b/test/backend/test_couchdb.py index ca0af6e1b..06e364bbe 100644 --- a/test/backend/test_couchdb.py +++ b/test/backend/test_couchdb.py @@ -62,27 +62,24 @@ def tearDown(self) -> None: def test_object_store_add(self): test_object = create_example_submodel() self.object_store.add(test_object) - self.assertEqual(test_object.source, source_core+"IRI-https%3A%2F%2Facplt.org%2FTest_Submodel") + self.assertEqual(test_object.source, source_core+"https%3A%2F%2Facplt.org%2FTest_Submodel") def test_retrieval(self): test_object = create_example_submodel() self.object_store.add(test_object) # When retrieving the object, we should get the *same* instance as we added - test_object_retrieved = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + test_object_retrieved = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.assertIs(test_object, test_object_retrieved) # When retrieving it again, we should still get the same object del test_object - test_object_retrieved_again = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + test_object_retrieved_again = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.assertIs(test_object_retrieved, test_object_retrieved_again) # However, a changed source should invalidate the cached object, so we should get a new copy - test_object_retrieved.source = "couchdb://example.com/example/IRI-https%3A%2F%2Facplt.org%2FTest_Submodel" - test_object_retrieved_third = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + test_object_retrieved.source = "couchdb://example.com/example/https%3A%2F%2Facplt.org%2FTest_Submodel" + test_object_retrieved_third = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.assertIsNot(test_object_retrieved, test_object_retrieved_third) def test_example_submodel_storing(self) -> None: @@ -94,8 +91,7 @@ def test_example_submodel_storing(self) -> None: self.assertIn(example_submodel, self.object_store) # Restore example submodel and check data - submodel_restored = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + submodel_restored = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') assert (isinstance(submodel_restored, model.Submodel)) checker = AASDataChecker(raise_immediately=True) check_example_submodel(checker, submodel_restored) @@ -111,7 +107,7 @@ def test_iterating(self) -> None: for item in example_data: self.object_store.add(item) - self.assertEqual(6, len(self.object_store)) + self.assertEqual(5, len(self.object_store)) # Iterate objects, add them to a DictObjectStore and check them retrieved_data_store: model.provider.DictObjectStore[model.Identifiable] = model.provider.DictObjectStore() @@ -126,31 +122,28 @@ def test_key_errors(self) -> None: self.object_store.add(example_submodel) with self.assertRaises(KeyError) as cm: self.object_store.add(example_submodel) - self.assertEqual("'Identifiable with id Identifier(IRI=https://acplt.org/Test_Submodel) already exists in " + self.assertEqual("'Identifiable with id https://acplt.org/Test_Submodel already exists in " "CouchDB database'", str(cm.exception)) # Querying a deleted object should raise a KeyError - retrieved_submodel = self.object_store.get_identifiable( - model.Identifier('https://acplt.org/Test_Submodel', model.IdentifierType.IRI)) + retrieved_submodel = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.object_store.discard(example_submodel) with self.assertRaises(KeyError) as cm: - self.object_store.get_identifiable(model.Identifier('https://acplt.org/Test_Submodel', - model.IdentifierType.IRI)) - self.assertEqual("'No Identifiable with id IRI-https://acplt.org/Test_Submodel found in CouchDB database'", + self.object_store.get_identifiable('https://acplt.org/Test_Submodel') + self.assertEqual("'No Identifiable with id https://acplt.org/Test_Submodel found in CouchDB database'", str(cm.exception)) # Double deleting should also raise a KeyError with self.assertRaises(KeyError) as cm: self.object_store.discard(retrieved_submodel) - self.assertEqual("'No AAS object with id Identifier(IRI=https://acplt.org/Test_Submodel) exists in " + self.assertEqual("'No AAS object with id https://acplt.org/Test_Submodel exists in " "CouchDB database'", str(cm.exception)) def test_conflict_errors(self): # Preperation: add object and retrieve it from the database example_submodel = create_example_submodel() self.object_store.add(example_submodel) - retrieved_submodel = self.object_store.get_identifiable( - model.Identifier('https://acplt.org/Test_Submodel', model.IdentifierType.IRI)) + retrieved_submodel = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') # Simulate a concurrent modification (Commit submodel, while preventing that the couchdb revision store is # updated) @@ -161,14 +154,14 @@ def test_conflict_errors(self): retrieved_submodel.id_short = "myOtherNewIdShort" with self.assertRaises(couchdb.CouchDBConflictError) as cm: retrieved_submodel.commit() - self.assertEqual("Could not commit changes to id Identifier(IRI=https://acplt.org/Test_Submodel) due to a " + self.assertEqual("Could not commit changes to id https://acplt.org/Test_Submodel due to a " "concurrent modification in the database.", str(cm.exception)) # Deleting the submodel with safe_delete should also raise a conflict error. Deletion without safe_delete should # work with self.assertRaises(couchdb.CouchDBConflictError) as cm: self.object_store.discard(retrieved_submodel, True) - self.assertEqual("Object with id Identifier(IRI=https://acplt.org/Test_Submodel) has been modified in the " + self.assertEqual("Object with id https://acplt.org/Test_Submodel has been modified in the " "database since the version requested to be deleted.", str(cm.exception)) self.object_store.discard(retrieved_submodel, False) self.assertEqual(0, len(self.object_store)) diff --git a/test/backend/test_local_file.py b/test/backend/test_local_file.py index 9ca24ec12..4a8186ac3 100644 --- a/test/backend/test_local_file.py +++ b/test/backend/test_local_file.py @@ -33,7 +33,7 @@ def test_object_store_add(self): self.object_store.add(test_object) self.assertEqual( test_object.source, - source_core+"bfe69a634a188d106286585170ba06dfbbd26dd000c641cab5b0f374e94c9611.json" + source_core+"fd787262b2743360f7ad03a3b4e9187e4c088aa37303448c9c43fe4c973dac53.json" ) def test_retrieval(self): @@ -41,20 +41,17 @@ def test_retrieval(self): self.object_store.add(test_object) # When retrieving the object, we should get the *same* instance as we added - test_object_retrieved = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + test_object_retrieved = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.assertIs(test_object, test_object_retrieved) # When retrieving it again, we should still get the same object del test_object - test_object_retrieved_again = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + test_object_retrieved_again = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.assertIs(test_object_retrieved, test_object_retrieved_again) # However, a changed source should invalidate the cached object, so we should get a new copy test_object_retrieved.source = "couchdb://example.com/example/IRI-https%3A%2F%2Facplt.org%2FTest_Submodel" - test_object_retrieved_third = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + test_object_retrieved_third = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.assertIsNot(test_object_retrieved, test_object_retrieved_third) def test_example_submodel_storing(self) -> None: @@ -66,8 +63,7 @@ def test_example_submodel_storing(self) -> None: self.assertIn(example_submodel, self.object_store) # Restore example submodel and check data - submodel_restored = self.object_store.get_identifiable( - model.Identifier(id_='https://acplt.org/Test_Submodel', id_type=model.IdentifierType.IRI)) + submodel_restored = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') assert (isinstance(submodel_restored, model.Submodel)) checker = AASDataChecker(raise_immediately=True) check_example_submodel(checker, submodel_restored) @@ -83,7 +79,7 @@ def test_iterating(self) -> None: for item in example_data: self.object_store.add(item) - self.assertEqual(6, len(self.object_store)) + self.assertEqual(5, len(self.object_store)) # Iterate objects, add them to a DictObjectStore and check them retrieved_data_store: model.provider.DictObjectStore[model.Identifiable] = model.provider.DictObjectStore() @@ -98,24 +94,22 @@ def test_key_errors(self) -> None: self.object_store.add(example_submodel) with self.assertRaises(KeyError) as cm: self.object_store.add(example_submodel) - self.assertEqual("'Identifiable with id Identifier(IRI=https://acplt.org/Test_Submodel) already exists in " + self.assertEqual("'Identifiable with id https://acplt.org/Test_Submodel already exists in " "local file database'", str(cm.exception)) # Querying a deleted object should raise a KeyError - retrieved_submodel = self.object_store.get_identifiable( - model.Identifier('https://acplt.org/Test_Submodel', model.IdentifierType.IRI)) + retrieved_submodel = self.object_store.get_identifiable('https://acplt.org/Test_Submodel') self.object_store.discard(example_submodel) with self.assertRaises(KeyError) as cm: - self.object_store.get_identifiable(model.Identifier('https://acplt.org/Test_Submodel', - model.IdentifierType.IRI)) - self.assertEqual("'No Identifiable with id Identifier(IRI=https://acplt.org/Test_Submodel) " + self.object_store.get_identifiable('https://acplt.org/Test_Submodel') + self.assertEqual("'No Identifiable with id https://acplt.org/Test_Submodel " "found in local file database'", str(cm.exception)) # Double deleting should also raise a KeyError with self.assertRaises(KeyError) as cm: self.object_store.discard(retrieved_submodel) - self.assertEqual("'No AAS object with id Identifier(IRI=https://acplt.org/Test_Submodel) exists in " + self.assertEqual("'No AAS object with id https://acplt.org/Test_Submodel exists in " "local file database'", str(cm.exception)) def test_editing(self): diff --git a/test/compliance_tool/__init__.py b/test/compliance_tool/__init__.py index e69de29bb..a0c327cb0 100644 --- a/test/compliance_tool/__init__.py +++ b/test/compliance_tool/__init__.py @@ -0,0 +1,28 @@ +import os +import zipfile + +AASX_FILES = ("test_demo_full_example_json_aasx", + "test_demo_full_example_xml_aasx", + "test_demo_full_example_xml_wrong_attribute_aasx", + "test_empty_aasx") + + +def _zip_directory(directory_path, zip_file_path): + """Zip a directory recursively.""" + with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, _, files in os.walk(directory_path): + for file in files: + file_path = os.path.join(root, file) + arcname = os.path.relpath(file_path, directory_path) + zipf.write(file_path, arcname=arcname) + + +def generate_aasx_files(): + """Zip dirs and create test AASX files.""" + script_dir = os.path.dirname(__file__) + for i in AASX_FILES: + _zip_directory(os.path.join(script_dir, "files", i), + os.path.join(script_dir, "files", i.rstrip("_aasx") + ".aasx")) + + +generate_aasx_files() diff --git a/test/compliance_tool/files/test_demo_full_example.aasx b/test/compliance_tool/files/test_demo_full_example.aasx deleted file mode 100644 index d8a676d16..000000000 Binary files a/test/compliance_tool/files/test_demo_full_example.aasx and /dev/null differ diff --git a/test/compliance_tool/files/test_demo_full_example.json b/test/compliance_tool/files/test_demo_full_example.json index 0879bce09..31fde424d 100644 --- a/test/compliance_tool/files/test_demo_full_example.json +++ b/test/compliance_tool/files/test_demo_full_example.json @@ -4,7 +4,7 @@ "idShort": "TestAssetAdministrationShell", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An Example Asset Administration Shell for the test application" }, { @@ -12,175 +12,257 @@ "text": "Ein Beispiel-Verwaltungsschale f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell", - "idType": "IRI" - }, + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell" }, "derivedFrom": { + "type": "ModelReference", "keys": [ { "type": "AssetAdministrationShell", - "idType": "IRI", - "value": "https://acplt.org/TestAssetAdministrationShell2", - "local": false + "value": "https://acplt.org/TestAssetAdministrationShell2" } ] }, - "asset": { - "keys": [ + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset/", + "specificAssetIds": [ { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset", - "local": false + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + }, + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + } } - ] + ], + "assetType": "http://acplt.org/TestAssetType/", + "defaultThumbnail": { + "path": "file:///path/to/thumbnail.png", + "contentType": "image/png" + } }, "submodels": [ { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", - "local": true + "value": "https://acplt.org/Test_Submodel" } - ] + ], + "referredSemanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" + } + ] + } }, { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel", - "local": true + "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial" } ] }, { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "local": true + "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification" } - ] + ], + "referredSemanticId": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/SubmodelTemplates/AssetIdentification" + } + ] + } } ], - "conceptDictionaries": [ + "embeddedDataSpecifications": [ { - "idShort": "TestConceptDictionary", - "description": [ - { - "language": "en-us", - "text": "An example concept dictionary for the test application" - }, - { - "language": "de", - "text": "Ein Beispiel-ConceptDictionary f\u00fcr eine Test-Anwendung" - } - ], - "modelType": { - "name": "ConceptDictionary" + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] }, - "conceptDescriptions": [ - { + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", "keys": [ { - "type": "ConceptDescription", - "idType": "IRI", - "value": "https://acplt.org/Test_ConceptDescription", - "local": false + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" } ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false } - ] + } } ] }, { - "idShort": "", - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell_Mandatory", - "idType": "IRI" - }, - "asset": { - "keys": [ - { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset_Mandatory", - "local": false - } - ] + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell_Mandatory", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset_Mandatory/" }, "submodels": [ { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel_Mandatory", - "local": true + "value": "https://acplt.org/Test_Submodel2_Mandatory" } ] }, { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel2_Mandatory", - "local": true + "value": "https://acplt.org/Test_Submodel_Mandatory" } ] } - ], - "conceptDictionaries": [ - { - "idShort": "TestConceptDictionary", - "modelType": { - "name": "ConceptDictionary" - } - } ] }, { - "idShort": "", - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell2_Mandatory", - "idType": "IRI" - }, - "asset": { - "keys": [ - { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset_Mandatory", - "local": false - } - ] + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell2_Mandatory", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset2_Mandatory/" } }, { "idShort": "TestAssetAdministrationShell", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An Example Asset Administration Shell for the test application" }, { @@ -188,91 +270,42 @@ "text": "Ein Beispiel-Verwaltungsschale f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell_Missing", - "idType": "IRI" - }, + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell_Missing", "administration": { - "version": "0.9", + "version": "9", "revision": "0" }, - "asset": { - "keys": [ + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset_Missing/", + "specificAssetIds": [ { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset_Missing", - "local": false - } - ] - }, - "submodels": [ - { - "keys": [ - { - "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel_Missing", - "local": true - } - ] - } - ], - "views": [ - { - "idShort": "ExampleView", - "modelType": { - "name": "View" - }, - "containedElements": [ - { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", "keys": [ { - "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel_Missing", - "local": false + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" } ] } - ] - }, - { - "idShort": "ExampleView2", - "modelType": { - "name": "View" } + ], + "defaultThumbnail": { + "path": "file:///TestFile.pdf", + "contentType": "application/pdf" } - ], - "conceptDictionaries": [ + }, + "submodels": [ { - "idShort": "TestConceptDictionary", - "description": [ - { - "language": "en-us", - "text": "An example concept dictionary for the test application" - }, - { - "language": "de", - "text": "Ein Beispiel-ConceptDictionary f\u00fcr eine Test-Anwendung" - } - ], - "modelType": { - "name": "ConceptDictionary" - }, - "conceptDescriptions": [ + "type": "ModelReference", + "keys": [ { - "keys": [ - { - "type": "ConceptDescription", - "idType": "IRI", - "value": "https://acplt.org/Test_ConceptDescription_Missing", - "local": false - } - ] + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel_Missing" } ] } @@ -284,7 +317,7 @@ "idShort": "Identification", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example asset identification submodel for the test application" }, { @@ -292,33 +325,56 @@ "text": "Ein Beispiel-Identifikations-Submodel f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/TestAsset/Identification" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification" }, "semanticId": { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/AssetIdentification", - "local": false + "value": "http://acplt.org/SubmodelTemplates/AssetIdentification" } ] }, "submodelElements": [ { + "extensions": [ + { + "value": "ExampleExtensionValue", + "refersTo": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "AssetAdministrationShell", + "value": "http://acplt.org/RefersTo/ExampleRefersTo" + } + ] + } + ], + "valueType": "xs:string", + "name": "ExampleExtension" + } + ], "idShort": "ManufacturerName", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -326,75 +382,66 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "0173-1#02-AAO677#002", - "local": false + "value": "0173-1#02-AAO677#002" } ] }, "qualifiers": [ { - "modelType": { - "name": "Qualifier" - }, "value": "50", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "int", - "type": "http://acplt.org/Qualifier/ExampleQualifier2" + "valueType": "xs:int", + "type": "http://acplt.org/Qualifier/ExampleQualifier2", + "kind": "TemplateQualifier" }, { - "modelType": { - "name": "Qualifier" - }, "value": "100", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "int", - "type": "http://acplt.org/Qualifier/ExampleQualifier" + "valueType": "xs:int", + "type": "http://acplt.org/Qualifier/ExampleQualifier", + "kind": "ConceptQualifier" } ], "value": "ACPLT", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "InstanceId", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -402,31 +449,44 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber", - "local": false + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" } ] }, + "qualifiers": [ + { + "value": "2023-04-07T16:59:54.870123", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:dateTime", + "type": "http://acplt.org/Qualifier/ExampleQualifier3", + "kind": "ValueQualifier" + } + ], "value": "978-8234-234-342", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } ] }, @@ -434,7 +494,7 @@ "idShort": "BillOfMaterial", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example bill of material submodel for the test application" }, { @@ -442,32 +502,28 @@ "text": "Ein Beispiel-BillofMaterial-Submodel f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", "administration": { - "version": "0.9" + "version": "9", + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial" }, "semanticId": { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/BillOfMaterial", - "local": false + "value": "http://acplt.org/SubmodelTemplates/BillOfMaterial" } ] }, "submodelElements": [ { "idShort": "ExampleEntity", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -475,16 +531,13 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Entity" - }, + "modelType": "Entity", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber", - "local": false + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" } ] }, @@ -494,7 +547,7 @@ "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -502,38 +555,34 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, "value": "exampleValue2", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "ExampleProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -541,64 +590,159 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Formula" + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" } - }, + ] + }, + "valueType": "xs:string", + "embeddedDataSpecifications": [ { - "modelType": { - "name": "Formula" + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] }, - "dependsOn": [ - { + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + }, + "valueType": "xs:string" + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/Values/TestValueId" } ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false } - ] + } } - ], - "value": "exampleValue", - "valueId": { + ] + } + ], + "entityType": "SelfManagedEntity", + "globalAssetId": "http://acplt.org/TestAsset/", + "specificAssetIds": [ + { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/SpecificAssetId/" } ] - }, - "valueType": "string" + } } - ], - "entityType": "CoManagedEntity" + ] }, { "idShort": "ExampleEntity2", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -606,30 +750,17 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Entity" - }, + "modelType": "Entity", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber", - "local": false + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" } ] }, - "entityType": "SelfManagedEntity", - "asset": { - "keys": [ - { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset2", - "local": false - } - ] - } + "entityType": "CoManagedEntity" } ] }, @@ -637,7 +768,7 @@ "idShort": "TestSubmodel", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example submodel for the test application" }, { @@ -645,24 +776,27 @@ "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_Submodel" + } + ] + } }, "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel", - "local": false + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" } ] }, @@ -672,7 +806,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example RelationshipElement object" }, { @@ -680,36 +814,39 @@ "text": "Beispiel RelationshipElement Element" } ], - "modelType": { - "name": "RelationshipElement" - }, + "modelType": "RelationshipElement", "semanticId": { + "type": "ModelReference", "keys": [ { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement", - "local": false + "type": "ConceptDescription", + "value": "https://acplt.org/Test_ConceptDescription" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty2", - "local": true + "value": "ExampleProperty2" } ] } @@ -719,7 +856,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example AnnotatedRelationshipElement object" }, { @@ -727,54 +864,55 @@ "text": "Beispiel AnnotatedRelationshipElement Element" } ], - "modelType": { - "name": "AnnotatedRelationshipElement" - }, + "modelType": "AnnotatedRelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty2", - "local": true + "value": "ExampleProperty2" } ] }, - "annotation": [ + "annotations": [ { "idShort": "ExampleAnnotatedProperty", - "modelType": { - "name": "Property" - }, + "category": "PARAMETER", + "modelType": "Property", "value": "exampleValue", - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "ExampleAnnotatedRange", - "modelType": { - "name": "Range" - }, - "valueType": "integer", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:integer", "min": "1", "max": "5" } @@ -785,7 +923,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Operation object" }, { @@ -793,27 +931,34 @@ "text": "Beispiel Operation Element" } ], - "modelType": { - "name": "Operation" - }, + "modelType": "Operation", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Operations/ExampleOperation", - "local": false + "value": "http://acplt.org/Operations/ExampleOperation" } ] }, - "inputVariable": [ + "inputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -821,42 +966,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInput" } ] }, + "kind": "Template", "value": "exampleValue", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } } ], - "outputVariable": [ + "outputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -864,42 +1016,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyOutput" } ] }, + "kind": "Template", "value": "exampleValue", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } } ], - "inoutputVariable": [ + "inoutputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -907,31 +1066,28 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" } ] }, + "kind": "Template", "value": "exampleValue", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } } ] @@ -941,7 +1097,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Capability object" }, { @@ -949,152 +1105,206 @@ "text": "Beispiel Capability Element" } ], - "modelType": { - "name": "Capability" - }, + "modelType": "Capability", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Capabilities/ExampleCapability", - "local": false + "value": "http://acplt.org/Capabilities/ExampleCapability" } ] } }, { - "idShort": "ExampleBasicEvent", + "idShort": "ExampleBasicEventElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example BasicEvent object" + "language": "en-US", + "text": "Example BasicEventElement object" }, { "language": "de", - "text": "Beispiel BasicEvent Element" + "text": "Beispiel BasicEventElement Element" } ], - "modelType": { - "name": "BasicEvent" - }, + "modelType": "BasicEventElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Events/ExampleBasicEvent", - "local": false + "value": "http://acplt.org/Events/ExampleBasicEventElement" } ] }, "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" }, { - "idShort": "ExampleSubmodelCollectionOrdered", + "idShort": "ExampleSubmodelCollection", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionOrdered object" + "language": "en-US", + "text": "Example SubmodelElementCollection object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionOrdered Element" + "text": "Beispiel SubmodelElementCollection Element" } ], - "modelType": { - "name": "SubmodelElementCollection" - }, + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, "value": [ { - "idShort": "ExampleProperty", - "category": "CONSTANT", + "idShort": "ExampleBlob", + "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Property object" + "language": "en-US", + "text": "Example Blob object" }, { "language": "de", - "text": "Beispiel Property Element" + "text": "Beispiel Blob Element" } ], - "modelType": { - "name": "Property" + "modelType": "Blob", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Blobs/ExampleBlob" + } + ] }, + "contentType": "application/pdf", + "value": "AQIDBAU=" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" + } + ], + "modelType": "File", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Files/ExampleFile" } ] }, - "value": "exampleValue", - "valueId": { + "value": "/TestFile.pdf", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFileURI", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Details of the Asset Administration Shell \u2014 An example for an external file reference" + }, + { + "language": "de", + "text": "Details of the Asset Administration Shell \u2013 Ein Beispiel f\u00fcr eine extern referenzierte Datei" + } + ], + "modelType": "File", + "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/Files/ExampleFile" } ] }, - "valueType": "string" + "value": "https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5", + "contentType": "application/pdf" }, { "idShort": "ExampleMultiLanguageProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example MultiLanguageProperty object" }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], - "modelType": { - "name": "MultiLanguageProperty" - }, + "modelType": "MultiLanguageProperty", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty", - "local": false + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" } - ] + ], + "referredSemanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/Referred" + } + ] + } }, "value": [ { - "language": "en-us", + "language": "en-US", "text": "Example value of a MultiLanguageProperty element" }, { @@ -1103,12 +1313,11 @@ } ], "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleMultiLanguageValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleMultiLanguageValueId" } ] } @@ -1118,7 +1327,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Range object" }, { @@ -1126,358 +1335,476 @@ "text": "Beispiel Range Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, - "valueType": "int", + "valueType": "xs:int", "min": "0", "max": "100" - } - ], - "ordered": true - }, - { - "idShort": "ExampleSubmodelCollectionUnordered", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" }, { - "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" - } - ], - "modelType": { - "name": "SubmodelElementCollection" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false - } - ] - }, - "value": [ - { - "idShort": "ExampleBlob", + "idShort": "ExampleReferenceElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Blob object" + "language": "en-US", + "text": "Example Reference Element object" }, { "language": "de", - "text": "Beispiel Blob Element" + "text": "Beispiel Reference Element Element" } ], - "modelType": { - "name": "Blob" - }, + "modelType": "ReferenceElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Blobs/ExampleBlob", - "local": false + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" } ] }, - "mimeType": "application/pdf", - "value": "AQIDBAU=" - }, - { - "idShort": "ExampleFile", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example File object" - }, - { - "language": "de", - "text": "Beispiel File Element" - } - ], - "modelType": { - "name": "File" - }, - "semanticId": { + "value": { + "type": "ModelReference", "keys": [ { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" } ] - }, - "value": "/TestFile.pdf", - "mimeType": "application/pdf" + } }, { - "idShort": "ExampleFileURI", - "category": "CONSTANT", - "description": [ - { - "language": "en-us", - "text": "Details of the Asset Administration Shell\u2014An example for an external file reference" - }, - { - "language": "de", - "text": "Details of the Asset Administration Shell \u2013 Ein Beispiel f\u00fcr eine extern referenzierte Datei" - } - ], - "modelType": { - "name": "File" - }, - "semanticId": { + "idShort": "ExampleSubmodelList", + "typeValueListElement": "Property", + "valueTypeListElement": "xs:string", + "semanticIdListElement": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, - "value": "https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5", - "mimeType": "application/pdf" - }, - { - "idShort": "ExampleReferenceElement", + "orderRelevant": true, "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Reference Element object" + "language": "en-US", + "text": "Example SubmodelElementList object" }, { "language": "de", - "text": "Beispiel Reference Element Element" + "text": "Beispiel SubmodelElementList Element" } ], - "modelType": { - "name": "ReferenceElement" - }, + "modelType": "SubmodelElementList", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement", - "local": false + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" } ] }, - "value": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - } - } - ], - "ordered": false - } - ] - }, - { - "idShort": "", - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel_Mandatory", - "idType": "IRI" - }, - "submodelElements": [ - { - "idShort": "ExampleRelationshipElement", - "modelType": { - "name": "RelationshipElement" - }, - "first": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - }, - "second": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - } - }, - { - "idShort": "ExampleAnnotatedRelationshipElement", - "modelType": { - "name": "AnnotatedRelationshipElement" - }, - "first": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - }, - "second": { - "keys": [ + "value": [ + { + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "supplementalSemanticIds": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/SupplementalId1" + } + ] + }, + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/SupplementalId2" + } + ] + } + ], + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] + }, + { + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "supplementalSemanticIds": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty2/SupplementalId" + } + ] + } + ], + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + ] + } + ] + } + ] + }, + { + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Mandatory", + "submodelElements": [ + { + "idShort": "ExampleRelationshipElement", + "modelType": "RelationshipElement", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } }, { - "idShort": "ExampleOperation", - "modelType": { - "name": "Operation" + "idShort": "ExampleAnnotatedRelationshipElement", + "modelType": "AnnotatedRelationshipElement", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] } }, + { + "idShort": "ExampleOperation", + "modelType": "Operation" + }, { "idShort": "ExampleCapability", - "modelType": { - "name": "Capability" - } + "modelType": "Capability" }, { - "idShort": "ExampleBasicEvent", - "modelType": { - "name": "BasicEvent" - }, + "idShort": "ExampleBasicEventElement", + "modelType": "BasicEventElement", "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } - }, - { - "idShort": "ExampleSubmodelCollectionOrdered", - "modelType": { - "name": "SubmodelElementCollection" }, - "value": [ - { - "idShort": "ExampleProperty", - "modelType": { - "name": "Property" - }, - "value": null, - "valueType": "string" - }, - { - "idShort": "ExampleMultiLanguageProperty", - "modelType": { - "name": "MultiLanguageProperty" - } - }, - { - "idShort": "ExampleRange", - "modelType": { - "name": "Range" - }, - "valueType": "int", - "min": null, - "max": null - } - ], - "ordered": true + "direction": "input", + "state": "off" }, { - "idShort": "ExampleSubmodelCollectionUnordered", - "modelType": { - "name": "SubmodelElementCollection" - }, + "idShort": "ExampleSubmodelList", + "typeValueListElement": "SubmodelElementCollection", + "modelType": "SubmodelElementList", "value": [ { - "idShort": "ExampleBlob", - "modelType": { - "name": "Blob" - }, - "mimeType": "application/pdf" - }, - { - "idShort": "ExampleFile", - "modelType": { - "name": "File" - }, - "value": null, - "mimeType": "application/pdf" + "modelType": "SubmodelElementCollection", + "value": [ + { + "idShort": "ExampleBlob", + "modelType": "Blob", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFile", + "modelType": "File", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleMultiLanguageProperty", + "category": "PARAMETER", + "modelType": "MultiLanguageProperty" + }, + { + "idShort": "ExampleProperty", + "category": "PARAMETER", + "modelType": "Property", + "valueType": "xs:string" + }, + { + "idShort": "ExampleRange", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:int" + }, + { + "idShort": "ExampleReferenceElement", + "category": "PARAMETER", + "modelType": "ReferenceElement" + } + ] }, { - "idShort": "ExampleReferenceElement", - "modelType": { - "name": "ReferenceElement" - } + "modelType": "SubmodelElementCollection" } - ], - "ordered": false + ] }, { - "idShort": "ExampleSubmodelCollectionUnordered2", - "modelType": { - "name": "SubmodelElementCollection" - }, - "ordered": false + "idShort": "ExampleSubmodelList2", + "typeValueListElement": "Capability", + "modelType": "SubmodelElementList" } ] }, { - "idShort": "", - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel2_Mandatory", - "idType": "IRI" - } + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel2_Mandatory" }, { "idShort": "TestSubmodel", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example submodel for the test application" }, { @@ -1485,24 +1812,18 @@ "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel_Missing", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Missing", "administration": { - "version": "0.9", + "version": "9", "revision": "0" }, "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel", - "local": false + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" } ] }, @@ -1512,7 +1833,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example RelationshipElement object" }, { @@ -1520,36 +1841,39 @@ "text": "Beispiel RelationshipElement Element" } ], - "modelType": { - "name": "RelationshipElement" - }, + "modelType": "RelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } @@ -1559,7 +1883,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example AnnotatedRelationshipElement object" }, { @@ -1567,56 +1891,57 @@ "text": "Beispiel AnnotatedRelationshipElement Element" } ], - "modelType": { - "name": "AnnotatedRelationshipElement" - }, + "modelType": "AnnotatedRelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, - "annotation": [ - { - "idShort": "ExampleAnnotatedProperty", - "modelType": { - "name": "Property" - }, - "value": "exampleValue", - "valueType": "string" - }, + "annotations": [ { "idShort": "ExampleAnnotatedRange", - "modelType": { - "name": "Range" - }, - "valueType": "integer", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:integer", "min": "1", "max": "5" + }, + { + "idShort": "ExampleAnnotatedProperty", + "category": "PARAMETER", + "modelType": "Property", + "value": "exampleValue", + "valueType": "xs:string" } ] }, @@ -1625,7 +1950,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Operation object" }, { @@ -1633,27 +1958,34 @@ "text": "Beispiel Operation Element" } ], - "modelType": { - "name": "Operation" - }, + "modelType": "Operation", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Operations/ExampleOperation", - "local": false + "value": "http://acplt.org/Operations/ExampleOperation" } ] }, - "inputVariable": [ + "inputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -1661,41 +1993,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInput" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" - } - ], + "kind": "Template", "value": "exampleValue", - "valueType": "string" + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" } } ], - "outputVariable": [ + "outputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -1703,41 +2043,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyOutput" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" - } - ], + "kind": "Template", "value": "exampleValue", - "valueType": "string" + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" } } ], - "inoutputVariable": [ + "inoutputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -1745,30 +2093,28 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" - } - ], + "kind": "Template", "value": "exampleValue", - "valueType": "string" + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" } } ] @@ -1778,7 +2124,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Capability object" }, { @@ -1786,128 +2132,151 @@ "text": "Beispiel Capability Element" } ], - "modelType": { - "name": "Capability" - }, + "modelType": "Capability", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Capabilities/ExampleCapability", - "local": false + "value": "http://acplt.org/Capabilities/ExampleCapability" } ] } }, { - "idShort": "ExampleBasicEvent", + "idShort": "ExampleBasicEventElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example BasicEvent object" + "language": "en-US", + "text": "Example BasicEventElement object" }, { "language": "de", - "text": "Beispiel BasicEvent Element" + "text": "Beispiel BasicEventElement Element" } ], - "modelType": { - "name": "BasicEvent" - }, + "modelType": "BasicEventElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Events/ExampleBasicEvent", - "local": false + "value": "http://acplt.org/Events/ExampleBasicEventElement" } ] }, "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" }, { - "idShort": "ExampleSubmodelCollectionOrdered", + "idShort": "ExampleSubmodelCollection", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionOrdered object" + "language": "en-US", + "text": "Example SubmodelElementCollection object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionOrdered Element" + "text": "Beispiel SubmodelElementCollection Element" } ], - "modelType": { - "name": "SubmodelElementCollection" - }, + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, "value": [ { - "idShort": "ExampleProperty", - "category": "CONSTANT", + "idShort": "ExampleBlob", + "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Property object" + "language": "en-US", + "text": "Example Blob object" }, { "language": "de", - "text": "Beispiel Property Element" + "text": "Beispiel Blob Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Blob", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Blobs/ExampleBlob" } ] }, - "qualifiers": [ + "contentType": "application/pdf", + "value": "AQIDBAU=" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" } ], - "value": "exampleValue", - "valueType": "string" + "modelType": "File", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Files/ExampleFile" + } + ] + }, + "value": "/TestFile.pdf", + "contentType": "application/pdf" }, { "idShort": "ExampleMultiLanguageProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example MultiLanguageProperty object" }, { @@ -1915,22 +2284,19 @@ "text": "Beispiel MulitLanguageProperty Element" } ], - "modelType": { - "name": "MultiLanguageProperty" - }, + "modelType": "MultiLanguageProperty", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty", - "local": false + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" } ] }, "value": [ { - "language": "en-us", + "language": "en-US", "text": "Example value of a MultiLanguageProperty element" }, { @@ -1940,129 +2306,70 @@ ] }, { - "idShort": "ExampleRange", - "category": "PARAMETER", + "idShort": "ExampleProperty", + "category": "CONSTANT", "description": [ { - "language": "en-us", - "text": "Example Range object" + "language": "en-US", + "text": "Example Property object" }, { "language": "de", - "text": "Beispiel Range Element" + "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, - "valueType": "int", - "min": "0", - "max": "100" - } - ], - "ordered": true - }, - { - "idShort": "ExampleSubmodelCollectionUnordered", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" - }, - { - "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" - } - ], - "modelType": { - "name": "SubmodelElementCollection" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false - } - ] - }, - "value": [ - { - "idShort": "ExampleBlob", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example Blob object" - }, + "qualifiers": [ { - "language": "de", - "text": "Beispiel Blob Element" + "valueType": "xs:string", + "type": "http://acplt.org/Qualifier/ExampleQualifier" } ], - "modelType": { - "name": "Blob" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Blobs/ExampleBlob", - "local": false - } - ] - }, - "mimeType": "application/pdf", - "value": "AQIDBAU=" + "value": "exampleValue", + "valueType": "xs:string" }, { - "idShort": "ExampleFile", + "idShort": "ExampleRange", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example File object" + "language": "en-US", + "text": "Example Range object" }, { "language": "de", - "text": "Beispiel File Element" + "text": "Beispiel Range Element" } ], - "modelType": { - "name": "File" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, - "value": "/TestFile.pdf", - "mimeType": "application/pdf" + "valueType": "xs:int", + "min": "0", + "max": "100" }, { "idShort": "ExampleReferenceElement", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Reference Element object" }, { @@ -2070,32 +2377,31 @@ "text": "Beispiel Reference Element Element" } ], - "modelType": { - "name": "ReferenceElement" - }, + "modelType": "ReferenceElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement", - "local": false + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" } ] }, "value": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } } - ], - "ordered": false + ] } ] }, @@ -2103,7 +2409,7 @@ "idShort": "TestSubmodel", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example submodel for the test application" }, { @@ -2111,24 +2417,18 @@ "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel_Template", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Template", "administration": { - "version": "0.9", + "version": "9", "revision": "0" }, "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel", - "local": false + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" } ] }, @@ -2139,7 +2439,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example RelationshipElement object" }, { @@ -2147,37 +2447,40 @@ "text": "Beispiel RelationshipElement Element" } ], - "modelType": { - "name": "RelationshipElement" - }, + "modelType": "RelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement" } ] }, "kind": "Template", "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } @@ -2187,7 +2490,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example AnnotatedRelationshipElement object" }, { @@ -2195,37 +2498,40 @@ "text": "Beispiel AnnotatedRelationshipElement Element" } ], - "modelType": { - "name": "AnnotatedRelationshipElement" - }, + "modelType": "AnnotatedRelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" } ] }, "kind": "Template", "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } @@ -2235,7 +2541,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Operation object" }, { @@ -2243,28 +2549,25 @@ "text": "Beispiel Operation Element" } ], - "modelType": { - "name": "Operation" - }, + "modelType": "Operation", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Operations/ExampleOperation", - "local": false + "value": "http://acplt.org/Operations/ExampleOperation" } ] }, "kind": "Template", - "inputVariable": [ + "inputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInput", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2272,33 +2575,29 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInput" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" } } ], - "outputVariable": [ + "outputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyOutput", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2306,33 +2605,29 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyOutput" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" } } ], - "inoutputVariable": [ + "inoutputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInOutput", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2340,22 +2635,18 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" } } ] @@ -2365,7 +2656,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Capability object" }, { @@ -2373,82 +2664,126 @@ "text": "Beispiel Capability Element" } ], - "modelType": { - "name": "Capability" - }, + "modelType": "Capability", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Capabilities/ExampleCapability", - "local": false + "value": "http://acplt.org/Capabilities/ExampleCapability" } ] }, "kind": "Template" }, { - "idShort": "ExampleBasicEvent", + "idShort": "ExampleBasicEventElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example BasicEvent object" + "language": "en-US", + "text": "Example BasicEventElement object" }, { "language": "de", - "text": "Beispiel BasicEvent Element" + "text": "Beispiel BasicEventElement Element" } ], - "modelType": { - "name": "BasicEvent" - }, + "modelType": "BasicEventElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Events/ExampleBasicEvent", - "local": false + "value": "http://acplt.org/Events/ExampleBasicEventElement" } ] }, "kind": "Template", "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" }, { - "idShort": "ExampleSubmodelCollectionOrdered", + "idShort": "ExampleSubmodelList", + "typeValueListElement": "SubmodelElementCollection", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "orderRelevant": true, "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionOrdered object" + "language": "en-US", + "text": "Example SubmodelElementList object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionOrdered Element" + "text": "Beispiel SubmodelElementList Element" } ], - "modelType": { - "name": "SubmodelElementCollection" + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] }, + "kind": "Template", + "value": [ + { + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementCollection object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementCollection Element" + } + ], + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, @@ -2459,7 +2794,7 @@ "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2467,29 +2802,25 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "ExampleMultiLanguageProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example MultiLanguageProperty object" }, { @@ -2497,16 +2828,13 @@ "text": "Beispiel MulitLanguageProperty Element" } ], - "modelType": { - "name": "MultiLanguageProperty" - }, + "modelType": "MultiLanguageProperty", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty", - "local": false + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" } ] }, @@ -2517,7 +2845,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Range object" }, { @@ -2525,22 +2853,18 @@ "text": "Beispiel Range Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, "kind": "Template", - "valueType": "int", - "min": null, + "valueType": "xs:int", "max": "100" }, { @@ -2548,7 +2872,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Range object" }, { @@ -2556,61 +2880,26 @@ "text": "Beispiel Range Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, "kind": "Template", - "valueType": "int", - "min": "0", - "max": null - } - ], - "ordered": true - }, - { - "idShort": "ExampleSubmodelCollectionUnordered", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" + "valueType": "xs:int", + "min": "0" }, - { - "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" - } - ], - "modelType": { - "name": "SubmodelElementCollection" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false - } - ] - }, - "kind": "Template", - "value": [ { "idShort": "ExampleBlob", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Blob object" }, { @@ -2618,28 +2907,25 @@ "text": "Beispiel Blob Element" } ], - "modelType": { - "name": "Blob" - }, + "modelType": "Blob", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Blobs/ExampleBlob", - "local": false + "value": "http://acplt.org/Blobs/ExampleBlob" } ] }, "kind": "Template", - "mimeType": "application/pdf" + "contentType": "application/pdf" }, { "idShort": "ExampleFile", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example File object" }, { @@ -2647,29 +2933,25 @@ "text": "Beispiel File Element" } ], - "modelType": { - "name": "File" - }, + "modelType": "File", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "value": "http://acplt.org/Files/ExampleFile" } ] }, "kind": "Template", - "value": null, - "mimeType": "application/pdf" + "contentType": "application/pdf" }, { "idShort": "ExampleReferenceElement", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Reference Element object" }, { @@ -2677,134 +2959,83 @@ "text": "Beispiel Reference Element Element" } ], - "modelType": { - "name": "ReferenceElement" - }, + "modelType": "ReferenceElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement", - "local": false + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" } ] }, "kind": "Template" } - ], - "ordered": false + ] }, - { - "idShort": "ExampleSubmodelCollectionUnordered2", + { "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" + "language": "en-US", + "text": "Example SubmodelElementCollection object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" + "text": "Beispiel SubmodelElementCollection Element" } ], - "modelType": { - "name": "SubmodelElementCollection" - }, + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, - "kind": "Template", - "ordered": false - } - ] - } - ], - "assets": [ - { - "idShort": "Test_Asset", - "description": [ - { - "language": "en-us", - "text": "An example asset for the test application" - }, - { - "language": "de", - "text": "Ein Beispiel-Asset f\u00fcr eine Test-Anwendung" + "kind": "Template" } - ], - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset", - "idType": "IRI" - }, - "administration": { - "version": "0.9", - "revision": "0" - }, - "kind": "Instance", - "assetIdentificationModel": { - "keys": [ - { - "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "local": false - } - ] - }, - "billOfMaterial": { - "keys": [ - { - "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", - "local": false - } - ] - } - }, - { - "idShort": "", - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset_Mandatory", - "idType": "IRI" - }, - "kind": "Instance" - }, - { - "idShort": "Test_Asset", - "description": [ - { - "language": "en-us", - "text": "An example asset for the test application" + ] }, { - "language": "de", - "text": "Ein Beispiel-Asset f\u00fcr eine Test-Anwendung" + "idShort": "ExampleSubmodelList2", + "typeValueListElement": "Capability", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "orderRelevant": true, + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementList object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementList Element" + } + ], + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] + }, + "kind": "Template" } - ], - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset_Missing", - "idType": "IRI" - }, - "administration": {}, - "kind": "Instance" + ] } ], "conceptDescriptions": [ @@ -2812,195 +3043,168 @@ "idShort": "TestConceptDescription", "description": [ { - "language": "en-us", - "text": "An example concept description for the test application" + "language": "en-US", + "text": "An example concept description for the test application" }, { "language": "de", "text": "Ein Beispiel-ConceptDescription f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "https://acplt.org/Test_ConceptDescription", - "idType": "IRI" - }, + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_ConceptDescription" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] }, "isCaseOf": [ { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription", - "local": false + "value": "http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription" } ] } ] }, { - "idShort": "", - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "https://acplt.org/Test_ConceptDescription_Mandatory", - "idType": "IRI" - } + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription_Mandatory" }, { "idShort": "TestConceptDescription", "description": [ { - "language": "en-us", - "text": "An example concept description for the test application" + "language": "en-US", + "text": "An example concept description for the test application" }, { "language": "de", "text": "Ein Beispiel-ConceptDescription f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "https://acplt.org/Test_ConceptDescription_Missing", - "idType": "IRI" - }, + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription_Missing", "administration": { - "version": "0.9", + "version": "9", "revision": "0" } - }, - { - "idShort": "TestSpec_01", - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "http://acplt.org/DataSpecifciations/Example/Identification", - "idType": "IRI" - }, - "administration": { - "version": "0.9", - "revision": "0" - }, - "isCaseOf": [ - { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ConceptDescriptionX", - "local": false - } - ] - } - ], - "embeddedDataSpecifications": [ - { - "dataSpecification": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0", - "local": false - } - ] - }, - "dataSpecificationContent": { - "preferredName": [ - { - "language": "de", - "text": "Test Specification" - }, - { - "language": "en-us", - "text": "TestSpecification" - } - ], - "dataType": "REAL_MEASURE", - "definition": [ - { - "language": "de", - "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" - }, - { - "language": "en-us", - "text": "This is a DataSpecification for testing purposes" - } - ], - "shortName": [ - { - "language": "de", - "text": "Test Spec" - }, - { - "language": "en-us", - "text": "TestSpec" - } - ], - "unit": "SpaceUnit", - "unitId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Units/SpaceUnit", - "local": false - } - ] - }, - "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", - "symbol": "SU", - "valueFormat": "string", - "valueList": { - "valueReferencePairTypes": [ - { - "value": "exampleValue2", - "valueId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId2", - "local": false - } - ] - }, - "valueType": "string" - }, - { - "value": "exampleValue", - "valueId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false - } - ] - }, - "valueType": "string" - } - ] - }, - "value": "TEST", - "levelType": [ - "Min", - "Max" - ] - } - } - ] } ] -} +} \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example.xml b/test/compliance_tool/files/test_demo_full_example.xml index fdfdb1075..39fae5599 100644 --- a/test/compliance_tool/files/test_demo_full_example.xml +++ b/test/compliance_tool/files/test_demo_full_example.xml @@ -1,1684 +1,2832 @@ - + TestAssetAdministrationShell - An Example Asset Administration Shell for the test application - Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + - https://acplt.org/Test_AssetAdministrationShell - 0.9 + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell + + + + http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell + https://acplt.org/Test_AssetAdministrationShell + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + ModelReference - https://acplt.org/TestAssetAdministrationShell2 + + AssetAdministrationShell + https://acplt.org/TestAssetAdministrationShell2 + - - - https://acplt.org/Test_Asset - - - - + + Instance + http://acplt.org/TestAsset/ + + + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + http://acplt.org/TestAssetType/ + + file:///path/to/thumbnail.png + image/png + + + + + ModelReference + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + + + - https://acplt.org/Test_Submodel + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/Identification + - - + + + ModelReference + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + - http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + + Submodel + https://acplt.org/Test_Submodel + - - + + + ModelReference - http://acplt.org/Submodels/Assets/TestAsset/Identification + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + - - - - - TestConceptDictionary - - An example concept dictionary for the test application - Ein Beispiel-ConceptDictionary für eine Test-Anwendung - - - - - https://acplt.org/Test_ConceptDescription - - - - - + + - - https://acplt.org/Test_AssetAdministrationShell_Mandatory - - - https://acplt.org/Test_Asset_Mandatory - - - - + https://acplt.org/Test_AssetAdministrationShell_Mandatory + + Instance + http://acplt.org/Test_Asset_Mandatory/ + + + + ModelReference - https://acplt.org/Test_Submodel2_Mandatory + + Submodel + https://acplt.org/Test_Submodel2_Mandatory + - - + + + ModelReference - https://acplt.org/Test_Submodel_Mandatory + + Submodel + https://acplt.org/Test_Submodel_Mandatory + - - - - - TestConceptDictionary - - - + + - - https://acplt.org/Test_AssetAdministrationShell2_Mandatory - - - https://acplt.org/Test_Asset_Mandatory - - + https://acplt.org/Test_AssetAdministrationShell2_Mandatory + + Instance + http://acplt.org/TestAsset2_Mandatory/ + TestAssetAdministrationShell - An Example Asset Administration Shell for the test application - Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + - https://acplt.org/Test_AssetAdministrationShell_Missing - 0.9 + 9 0 - - - https://acplt.org/Test_Asset_Missing - - - - - - https://acplt.org/Test_Submodel_Missing - - - - - - ExampleView - - - - https://acplt.org/Test_Submodel_Missing - - - - - - ExampleView2 - - - - - - TestConceptDictionary - - An example concept dictionary for the test application - Ein Beispiel-ConceptDictionary für eine Test-Anwendung - - - + https://acplt.org/Test_AssetAdministrationShell_Missing + + Instance + http://acplt.org/Test_Asset_Missing/ + + + TestKey + TestValue + + ExternalReference - https://acplt.org/Test_ConceptDescription_Missing + + GlobalReference + http://acplt.org/SpecificAssetId/ + - - - - + + + + + file:///TestFile.pdf + application/pdf + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Missing + + + + - - - Test_Asset - - An example asset for the test application - Ein Beispiel-Asset für eine Test-Anwendung - - https://acplt.org/Test_Asset - - 0.9 - 0 - - - - http://acplt.org/Submodels/Assets/TestAsset/Identification - - - - - http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial - - - Instance - - - - https://acplt.org/Test_Asset_Mandatory - Instance - - - Test_Asset - - An example asset for the test application - Ein Beispiel-Asset für eine Test-Anwendung - - https://acplt.org/Test_Asset_Missing - - Instance - - Identification - An example asset identification submodel for the test application - Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + + en-US + An example asset identification submodel for the test application + + + de + Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + - http://acplt.org/Submodels/Assets/TestAsset/Identification - 0.9 + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/TestAsset/Identification + + + + http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification + http://acplt.org/Submodels/Assets/TestAsset/Identification Instance + ModelReference - http://acplt.org/SubmodelTemplates/AssetIdentification + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + - - - ManufacturerName - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - 0173-1#02-AAO677#002 - - - - - http://acplt.org/Qualifier/ExampleQualifier - int - + + + + ExampleExtension + xs:string + ExampleExtensionValue + + + ModelReference - http://acplt.org/ValueId/ExampleValueId + + AssetAdministrationShell + http://acplt.org/RefersTo/ExampleRefersTo + - - 100 - + + + + + PARAMETER + ManufacturerName + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + 0173-1#02-AAO677#002 + + + + + + ConceptQualifier + http://acplt.org/Qualifier/ExampleQualifier + xs:int + 100 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + - - http://acplt.org/Qualifier/ExampleQualifier2 - int - - - http://acplt.org/ValueId/ExampleValueId - - - 50 - + TemplateQualifier + http://acplt.org/Qualifier/ExampleQualifier2 + xs:int + 50 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + - string - ACPLT - - - http://acplt.org/ValueId/ExampleValueId - - - - - - - InstanceId - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber - - - string - 978-8234-234-342 - - - http://acplt.org/ValueId/ExampleValueId - - - - + + xs:string + ACPLT + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + PARAMETER + InstanceId + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + ValueQualifier + http://acplt.org/Qualifier/ExampleQualifier3 + xs:dateTime + 2023-04-07T16:59:54.870123 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + xs:string + 978-8234-234-342 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + BillOfMaterial - An example bill of material submodel for the test application - Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + + en-US + An example bill of material submodel for the test application + + + de + Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + - http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial - 0.9 + 9 + http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial Instance + ModelReference - http://acplt.org/SubmodelTemplates/BillOfMaterial + + Submodel + http://acplt.org/SubmodelTemplates/BillOfMaterial + - - - ExampleEntity - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber - - - - - - ExampleProperty2 - CONSTANT - - Example Property object - Beispiel Property Element - - Instance - - - http://acplt.org/Properties/ExampleProperty - - - string - exampleValue2 - - - http://acplt.org/ValueId/ExampleValueId - - - - - - - ExampleProperty - CONSTANT - - Example Property object - Beispiel Property Element - - Instance - - - http://acplt.org/Properties/ExampleProperty - - - - - - - - - - - http://acplt.org/ValueId/ExampleValueId - - - - - - string - exampleValue - - - http://acplt.org/ValueId/ExampleValueId - - - - - - CoManagedEntity - - - - - ExampleEntity2 - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber - - - - SelfManagedEntity - - - https://acplt.org/Test_Asset2 - - - - + + PARAMETER + ExampleEntity + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + CONSTANT + ExampleProperty2 + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + SelfManagedEntity + http://acplt.org/TestAsset/ + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + + PARAMETER + ExampleEntity2 + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + CoManagedEntity + TestSubmodel - An example submodel for the test application - Ein Beispiel-Teilmodell für eine Test-Anwendung + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + - https://acplt.org/Test_Submodel - 0.9 + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_Submodel + + + + https://acplt.org/Test_Submodel Instance + ExternalReference - http://acplt.org/SubmodelTemplates/ExampleSubmodel + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + - - - ExampleRelationshipElement - PARAMETER - - Example RelationshipElement object - Beispiel RelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty2 - - - - - - - ExampleAnnotatedRelationshipElement - PARAMETER - - Example AnnotatedRelationshipElement object - Beispiel AnnotatedRelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty2 - - - - - - ExampleAnnotatedProperty - Instance - string - exampleValue - - - - - ExampleAnnotatedRange - Instance - integer - 1 - 5 - - - - - - - - ExampleOperation - PARAMETER - - Example Operation object - Beispiel Operation Element - - Instance - - - http://acplt.org/Operations/ExampleOperation - - - + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ModelReference + + + ConceptDescription + https://acplt.org/Test_ConceptDescription + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + - ExampleProperty CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + - string + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - + + + + - ExampleProperty CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + - string + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - + + + + - ExampleProperty CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + - string + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - - - ExampleCapability - PARAMETER - - Example Capability object - Beispiel Capability Element - - Instance - - - http://acplt.org/Capabilities/ExampleCapability - - - - - - - ExampleBasicEvent - PARAMETER - - Example BasicEvent object - Beispiel BasicEvent Element - - Instance - - - http://acplt.org/Events/ExampleBasicEvent - - - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - PARAMETER - - Example SubmodelElementCollectionOrdered object - Beispiel SubmodelElementCollectionOrdered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered - - - - + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleFileURI + + + en-US + Details of the Asset Administration Shell — An example for an external file reference + + + de + Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5 + application/pdf + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + Property + xs:string + - ExampleProperty CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExampleProperty + - string + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId1 + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId2 + + + + + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - ExampleMultiLanguageProperty + CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example MultiLanguageProperty object - Beispiel MulitLanguageProperty Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty2/SupplementalId + + + + + xs:string + exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleMultiLanguageValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - Example value of a MultiLanguageProperty element - Beispielswert für ein MulitLanguageProperty-Element - - - - - - ExampleRange - PARAMETER - - Example Range object - Beispiel Range Element - - Instance - - - http://acplt.org/Ranges/ExampleRange - - - int - 0 - 100 - - - - true - false - - - - - ExampleSubmodelCollectionUnordered - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - + + + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MultiLanguageProperty Element + + + + ExternalReference + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/Referred + + + + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleMultiLanguageValueId + + + + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + + + + + https://acplt.org/Test_Submodel_Mandatory + Instance + + + ExampleRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleAnnotatedRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleOperation + + + ExampleCapability + + + ExampleBasicEventElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + input + off + + + ExampleSubmodelList + SubmodelElementCollection + + + ExampleBlob - PARAMETER - - Example Blob object - Beispiel Blob Element - - Instance - - - http://acplt.org/Blobs/ExampleBlob - - - AQIDBAU= - application/pdf + + application/pdf - - ExampleFile - PARAMETER - - Example File object - Beispiel File Element - - Instance - - - http://acplt.org/Files/ExampleFile - - - application/pdf - /TestFile.pdf - - - - - ExampleFileURI - CONSTANT - - Details of the Asset Administration Shell—An example for an external file reference - Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei - - Instance - - - http://acplt.org/Files/ExampleFile - - - application/pdf - https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5 + application/pdf - - - - ExampleReferenceElement + PARAMETER - - Example Reference Element object - Beispiel Reference Element Element - - Instance - - - http://acplt.org/ReferenceElements/ExampleReferenceElement - - - - - ExampleProperty - - - - - - false - false - - - - - - - https://acplt.org/Test_Submodel_Mandatory - Instance - - - - ExampleRelationshipElement - Instance - - - ExampleProperty - - - - - ExampleProperty - - - - - - - ExampleAnnotatedRelationshipElement - Instance - - - ExampleProperty - - - - - ExampleProperty - - - - - - - - ExampleOperation - Instance - - - - - ExampleCapability - Instance - - - - - ExampleBasicEvent - Instance - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - Instance - - + ExampleMultiLanguageProperty + + PARAMETER ExampleProperty - Instance - string + xs:string - - - - ExampleMultiLanguageProperty - Instance - - - + PARAMETER ExampleRange - Instance - int + xs:int - - - true - false - - - - - ExampleSubmodelCollectionUnordered - Instance - - - - ExampleBlob - Instance - - application/pdf - - - - - ExampleFile - Instance - application/pdf - - - + PARAMETER ExampleReferenceElement - Instance - - - false - false - - - - - ExampleSubmodelCollectionUnordered2 - Instance - - false - false - - + + + + + + + + ExampleSubmodelList2 + Capability + - - https://acplt.org/Test_Submodel2_Mandatory + https://acplt.org/Test_Submodel2_Mandatory Instance - TestSubmodel - An example submodel for the test application - Ein Beispiel-Teilmodell für eine Test-Anwendung + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + - https://acplt.org/Test_Submodel_Missing - 0.9 + 9 0 + https://acplt.org/Test_Submodel_Missing Instance + ExternalReference - http://acplt.org/SubmodelTemplates/ExampleSubmodel + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + - - - ExampleRelationshipElement - PARAMETER - - Example RelationshipElement object - Beispiel RelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - - ExampleAnnotatedRelationshipElement - PARAMETER - - Example AnnotatedRelationshipElement object - Beispiel AnnotatedRelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - ExampleAnnotatedRange - Instance - integer - 1 - 5 - - - - - ExampleAnnotatedProperty - Instance - string - exampleValue - - - - - - - - ExampleOperation - PARAMETER - - Example Operation object - Beispiel Operation Element - - Instance - - - http://acplt.org/Operations/ExampleOperation - - - + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + - ExampleProperty CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string + xs:string exampleValue - - - - - - - ExampleProperty - CONSTANT - - Example Property object - Beispiel Property Element - - Instance - + + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string - exampleValue + - - + + + + - ExampleProperty CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string + xs:string exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + - - - - - - ExampleCapability - PARAMETER - - Example Capability object - Beispiel Capability Element - - Instance - - - http://acplt.org/Capabilities/ExampleCapability - - - - - - - ExampleBasicEvent - PARAMETER - - Example BasicEvent object - Beispiel BasicEvent Element - - Instance - - - http://acplt.org/Events/ExampleBasicEvent - - - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - PARAMETER - - Example SubmodelElementCollectionOrdered object - Beispiel SubmodelElementCollectionOrdered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered - - - - + + + + + - ExampleProperty CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string + xs:string exampleValue - - - - - ExampleMultiLanguageProperty - CONSTANT - - Example MultiLanguageProperty object - Beispiel MulitLanguageProperty Element - - Instance - - - http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty - - - - Example value of a MultiLanguageProperty element - Beispielswert für ein MulitLanguageProperty-Element - - - - - - ExampleRange - PARAMETER - - Example Range object - Beispiel Range Element - - Instance - - - http://acplt.org/Ranges/ExampleRange - - - int - 0 - 100 - - - - true - false - - - - - ExampleSubmodelCollectionUnordered - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - - - ExampleBlob - PARAMETER - - Example Blob object - Beispiel Blob Element - - Instance - - - http://acplt.org/Blobs/ExampleBlob - - - AQIDBAU= - application/pdf - - - - - ExampleFile - PARAMETER - - Example File object - Beispiel File Element - - Instance - - - http://acplt.org/Files/ExampleFile - - - application/pdf - /TestFile.pdf - - - - - ExampleReferenceElement - PARAMETER - - Example Reference Element object - Beispiel Reference Element Element - - Instance - - - http://acplt.org/ReferenceElements/ExampleReferenceElement - - - + + ExternalReference - ExampleProperty + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - - false - false - - + + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + http://acplt.org/Qualifier/ExampleQualifier + xs:string + + + xs:string + exampleValue + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + TestSubmodel - An example submodel for the test application - Ein Beispiel-Teilmodell für eine Test-Anwendung + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + - https://acplt.org/Test_Submodel_Template - 0.9 + 9 0 + https://acplt.org/Test_Submodel_Template Template + ExternalReference - http://acplt.org/SubmodelTemplates/ExampleSubmodel + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + - - - ExampleRelationshipElement - PARAMETER - - Example RelationshipElement object - Beispiel RelationshipElement Element - - Template - - - http://acplt.org/RelationshipElements/ExampleRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - - ExampleAnnotatedRelationshipElement - PARAMETER - - Example AnnotatedRelationshipElement object - Beispiel AnnotatedRelationshipElement Element - - Template - - - http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - - - ExampleOperation - PARAMETER - - Example Operation object - Beispiel Operation Element - - Template - - - http://acplt.org/Operations/ExampleOperation - - - + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + - ExampleProperty CONSTANT + ExamplePropertyInput - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + - string + xs:string - - + + + + - ExampleProperty CONSTANT + ExamplePropertyOutput - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + - string + xs:string - - + + + + - ExampleProperty CONSTANT + ExamplePropertyInOutput - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + - string + xs:string - - - - - - ExampleCapability - PARAMETER - - Example Capability object - Beispiel Capability Element - - Template - - - http://acplt.org/Capabilities/ExampleCapability - - - - - - - ExampleBasicEvent - PARAMETER - - Example BasicEvent object - Beispiel BasicEvent Element - - Template - - - http://acplt.org/Events/ExampleBasicEvent - - - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - PARAMETER - - Example SubmodelElementCollectionOrdered object - Beispiel SubmodelElementCollectionOrdered Element - - Template - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered - - - - + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + SubmodelElementCollection + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + - ExampleProperty CONSTANT + ExampleProperty - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExampleProperty + - string + xs:string - - - ExampleMultiLanguageProperty CONSTANT + ExampleMultiLanguageProperty - Example MultiLanguageProperty object - Beispiel MulitLanguageProperty Element + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + - Template + ExternalReference - http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + - - - ExampleRange PARAMETER + ExampleRange - Example Range object - Beispiel Range Element + + en-US + Example Range object + + + de + Beispiel Range Element + - Template + ExternalReference - http://acplt.org/Ranges/ExampleRange + + GlobalReference + http://acplt.org/Ranges/ExampleRange + - int + xs:int 100 - - - ExampleRange2 PARAMETER + ExampleRange2 - Example Range object - Beispiel Range Element + + en-US + Example Range object + + + de + Beispiel Range Element + - Template + ExternalReference - http://acplt.org/Ranges/ExampleRange + + GlobalReference + http://acplt.org/Ranges/ExampleRange + - int + xs:int 0 - - - true - false - - - - - ExampleSubmodelCollectionUnordered - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Template - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - - ExampleBlob PARAMETER + ExampleBlob - Example Blob object - Beispiel Blob Element + + en-US + Example Blob object + + + de + Beispiel Blob Element + - Template + ExternalReference - http://acplt.org/Blobs/ExampleBlob + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + - application/pdf + application/pdf - - - ExampleFile PARAMETER + ExampleFile - Example File object - Beispiel File Element + + en-US + Example File object + + + de + Beispiel File Element + - Template + ExternalReference - http://acplt.org/Files/ExampleFile + + GlobalReference + http://acplt.org/Files/ExampleFile + - application/pdf + application/pdf - - - ExampleReferenceElement PARAMETER + ExampleReferenceElement - Example Reference Element object - Beispiel Reference Element Element + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + - Template + ExternalReference - http://acplt.org/ReferenceElements/ExampleReferenceElement + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + - - - false - false - - - - - ExampleSubmodelCollectionUnordered2 - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Template - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - false - false - - + + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + + + PARAMETER + ExampleSubmodelList2 + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + Capability + @@ -1686,102 +2834,158 @@ TestConceptDescription - An example concept description for the test application - Ein Beispiel-ConceptDescription für eine Test-Anwendung + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + - https://acplt.org/Test_ConceptDescription - 0.9 + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_ConceptDescription + + + + http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription + https://acplt.org/Test_ConceptDescription - - http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription - + + ExternalReference + + + GlobalReference + http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription + + + - - https://acplt.org/Test_ConceptDescription_Mandatory + https://acplt.org/Test_ConceptDescription_Mandatory TestConceptDescription - An example concept description for the test application - Ein Beispiel-ConceptDescription für eine Test-Anwendung + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + - https://acplt.org/Test_ConceptDescription_Missing - 0.9 + 9 0 - - - TestSpec_01 - http://acplt.org/DataSpecifciations/Example/Identification - - 0.9 - 0 - - - - - - Test Specification - TestSpecification - - - Test Spec - TestSpec - - SpaceUnit - - - http://acplt.org/Units/SpaceUnit - - - http://acplt.org/DataSpec/ExampleDef - SU - REAL_MEASURE - - Dies ist eine Data Specification für Testzwecke - This is a DataSpecification for testing purposes - - string - - - - - http://acplt.org/ValueId/ExampleValueId - - - exampleValue - - - - - http://acplt.org/ValueId/ExampleValueId2 - - - exampleValue2 - - - TEST - Max - Min - - - - - http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0 - - - - - - http://acplt.org/ReferenceElements/ConceptDescriptionX - - + https://acplt.org/Test_ConceptDescription_Missing - + diff --git a/test/compliance_tool/files/test_demo_full_example2.aasx b/test/compliance_tool/files/test_demo_full_example2.aasx deleted file mode 100644 index 624691f48..000000000 Binary files a/test/compliance_tool/files/test_demo_full_example2.aasx and /dev/null differ diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/TestFile.pdf b/test/compliance_tool/files/test_demo_full_example_json_aasx/TestFile.pdf new file mode 100644 index 000000000..2bccbec5f Binary files /dev/null and b/test/compliance_tool/files/test_demo_full_example_json_aasx/TestFile.pdf differ diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/[Content_Types].xml b/test/compliance_tool/files/test_demo_full_example_json_aasx/[Content_Types].xml new file mode 100644 index 000000000..4d0bdc9aa --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_json_aasx/[Content_Types].xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/_rels/.rels b/test/compliance_tool/files/test_demo_full_example_json_aasx/_rels/.rels new file mode 100644 index 000000000..9758543f3 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_json_aasx/_rels/.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/_rels/aasx-origin.rels b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/_rels/aasx-origin.rels new file mode 100644 index 000000000..3ec0a479e --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/_rels/aasx-origin.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/_rels/data.json.rels b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/_rels/data.json.rels new file mode 100644 index 000000000..43350edd0 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/_rels/data.json.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/aasx-origin b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/aasx-origin new file mode 100644 index 000000000..e69de29bb diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/data.json b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/data.json new file mode 100644 index 000000000..7172735e6 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_json_aasx/aasx/data.json @@ -0,0 +1,3218 @@ +{ + "assetAdministrationShells": [ + { + "idShort": "TestAssetAdministrationShell", + "description": [ + { + "language": "en-US", + "text": "An Example Asset Administration Shell for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-Verwaltungsschale f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell", + "administration": { + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell" + }, + "derivedFrom": { + "type": "ModelReference", + "keys": [ + { + "type": "AssetAdministrationShell", + "value": "https://acplt.org/TestAssetAdministrationShell2" + } + ] + }, + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset/", + "specificAssetIds": [ + { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + }, + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + } + } + ], + "defaultThumbnail": { + "path": "file:///path/to/thumbnail.png", + "contentType": "image/png" + } + }, + "submodels": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel" + } + ], + "referredSemanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" + } + ] + } + }, + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial" + } + ] + }, + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification" + } + ], + "referredSemanticId": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/SubmodelTemplates/AssetIdentification" + } + ] + } + }, + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel_Template" + } + ] + } + ], + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] + }, + { + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell_Mandatory", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset_Mandatory/" + }, + "submodels": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel2_Mandatory" + } + ] + }, + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel_Mandatory" + } + ] + } + ] + }, + { + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell2_Mandatory", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset2_Mandatory/" + } + }, + { + "idShort": "TestAssetAdministrationShell", + "description": [ + { + "language": "en-US", + "text": "An Example Asset Administration Shell for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-Verwaltungsschale f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell_Missing", + "administration": { + "version": "9", + "revision": "0" + }, + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset_Missing/", + "specificAssetIds": [ + { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + } + } + ], + "defaultThumbnail": { + "path": "file:///TestFile.pdf", + "contentType": "application/pdf" + } + }, + "submodels": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel_Missing" + } + ] + } + ] + } + ], + "submodels": [ + { + "idShort": "Identification", + "description": [ + { + "language": "en-US", + "text": "An example asset identification submodel for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-Identifikations-Submodel f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", + "administration": { + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/TestAsset/Identification" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification" + }, + "semanticId": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/SubmodelTemplates/AssetIdentification" + } + ] + }, + "submodelElements": [ + { + "extensions": [ + { + "value": "ExampleExtensionValue", + "refersTo": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "AssetAdministrationShell", + "value": "http://acplt.org/RefersTo/ExampleRefersTo" + } + ] + } + ], + "valueType": "xs:string", + "name": "ExampleExtension" + } + ], + "idShort": "ManufacturerName", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." + }, + { + "language": "de", + "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "0173-1#02-AAO677#002" + } + ] + }, + "qualifiers": [ + { + "value": "50", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:int", + "type": "http://acplt.org/Qualifier/ExampleQualifier2", + "kind": "TemplateQualifier" + }, + { + "value": "100", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:int", + "type": "http://acplt.org/Qualifier/ExampleQualifier", + "kind": "ConceptQualifier" + } + ], + "value": "ACPLT", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + }, + { + "idShort": "InstanceId", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." + }, + { + "language": "de", + "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" + } + ] + }, + "qualifiers": [ + { + "value": "2023-04-07T16:59:54.870123", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:dateTime", + "type": "http://acplt.org/Qualifier/ExampleQualifier3", + "kind": "ValueQualifier" + } + ], + "value": "978-8234-234-342", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + ] + }, + { + "idShort": "BillOfMaterial", + "description": [ + { + "language": "en-US", + "text": "An example bill of material submodel for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-BillofMaterial-Submodel f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", + "administration": { + "version": "9", + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial" + }, + "semanticId": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/SubmodelTemplates/BillOfMaterial" + } + ] + }, + "submodelElements": [ + { + "idShort": "ExampleEntity", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." + }, + { + "language": "de", + "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" + } + ], + "modelType": "Entity", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" + } + ] + }, + "statements": [ + { + "idShort": "ExampleProperty2", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + }, + { + "idShort": "ExampleProperty", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + }, + "valueType": "xs:string" + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] + } + ], + "entityType": "SelfManagedEntity", + "globalAssetId": "http://acplt.org/TestAsset/", + "specificAssetIds": [ + { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + } + } + ] + }, + { + "idShort": "ExampleEntity2", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." + }, + { + "language": "de", + "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" + } + ], + "modelType": "Entity", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" + } + ] + }, + "entityType": "CoManagedEntity" + } + ] + }, + { + "idShort": "TestSubmodel", + "description": [ + { + "language": "en-US", + "text": "An example submodel for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel", + "administration": { + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_Submodel" + } + ] + } + }, + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" + } + ] + }, + "submodelElements": [ + { + "idShort": "ExampleRelationshipElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example RelationshipElement object" + }, + { + "language": "de", + "text": "Beispiel RelationshipElement Element" + } + ], + "modelType": "RelationshipElement", + "semanticId": { + "type": "ModelReference", + "keys": [ + { + "type": "ConceptDescription", + "value": "https://acplt.org/Test_ConceptDescription" + } + ] + }, + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty2" + } + ] + } + }, + { + "idShort": "ExampleAnnotatedRelationshipElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example AnnotatedRelationshipElement object" + }, + { + "language": "de", + "text": "Beispiel AnnotatedRelationshipElement Element" + } + ], + "modelType": "AnnotatedRelationshipElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" + } + ] + }, + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty2" + } + ] + }, + "annotations": [ + { + "idShort": "ExampleAnnotatedProperty", + "category": "PARAMETER", + "modelType": "Property", + "value": "exampleValue", + "valueType": "xs:string" + }, + { + "idShort": "ExampleAnnotatedRange", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:integer", + "min": "1", + "max": "5" + } + ] + }, + { + "idShort": "ExampleOperation", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Operation object" + }, + { + "language": "de", + "text": "Beispiel Operation Element" + } + ], + "modelType": "Operation", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Operations/ExampleOperation" + } + ] + }, + "inputVariables": [ + { + "value": { + "idShort": "ExamplePropertyInput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyInput" + } + ] + }, + "kind": "Template", + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + } + ], + "outputVariables": [ + { + "value": { + "idShort": "ExamplePropertyOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyOutput" + } + ] + }, + "kind": "Template", + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + } + ], + "inoutputVariables": [ + { + "value": { + "idShort": "ExamplePropertyInOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" + } + ] + }, + "kind": "Template", + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + } + ] + }, + { + "idShort": "ExampleCapability", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Capability object" + }, + { + "language": "de", + "text": "Beispiel Capability Element" + } + ], + "modelType": "Capability", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Capabilities/ExampleCapability" + } + ] + } + }, + { + "idShort": "ExampleBasicEventElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example BasicEventElement object" + }, + { + "language": "de", + "text": "Beispiel BasicEventElement Element" + } + ], + "modelType": "BasicEventElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Events/ExampleBasicEventElement" + } + ] + }, + "observed": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" + }, + { + "idShort": "ExampleSubmodelCollection", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementCollection object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementCollection Element" + } + ], + "modelType": "SubmodelElementCollection", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "value": [ + { + "idShort": "ExampleBlob", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Blob object" + }, + { + "language": "de", + "text": "Beispiel Blob Element" + } + ], + "modelType": "Blob", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Blobs/ExampleBlob" + } + ] + }, + "contentType": "application/pdf", + "value": "AQIDBAU=" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" + } + ], + "modelType": "File", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Files/ExampleFile" + } + ] + }, + "value": "/TestFile.pdf", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFileURI", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Details of the Asset Administration Shell \u2014 An example for an external file reference" + }, + { + "language": "de", + "text": "Details of the Asset Administration Shell \u2013 Ein Beispiel f\u00fcr eine extern referenzierte Datei" + } + ], + "modelType": "File", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Files/ExampleFile" + } + ] + }, + "value": "https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleMultiLanguageProperty", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example MultiLanguageProperty object" + }, + { + "language": "de", + "text": "Beispiel MultiLanguageProperty Element" + } + ], + "modelType": "MultiLanguageProperty", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" + } + ], + "referredSemanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/Referred" + } + ] + } + }, + "value": [ + { + "language": "en-US", + "text": "Example value of a MultiLanguageProperty element" + }, + { + "language": "de", + "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + } + ], + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleMultiLanguageValueId" + } + ] + } + }, + { + "idShort": "ExampleRange", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Range object" + }, + { + "language": "de", + "text": "Beispiel Range Element" + } + ], + "modelType": "Range", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Ranges/ExampleRange" + } + ] + }, + "valueType": "xs:int", + "min": "0", + "max": "100" + }, + { + "idShort": "ExampleReferenceElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Reference Element object" + }, + { + "language": "de", + "text": "Beispiel Reference Element Element" + } + ], + "modelType": "ReferenceElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" + } + ] + }, + "value": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + }, + { + "idShort": "ExampleSubmodelList", + "typeValueListElement": "Property", + "valueTypeListElement": "xs:string", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "orderRelevant": true, + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementList object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementList Element" + } + ], + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] + }, + "value": [ + { + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "supplementalSemanticIds": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/SupplementalId1" + } + ] + }, + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/SupplementalId2" + } + ] + } + ], + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] + }, + { + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "supplementalSemanticIds": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty2/SupplementalId" + } + ] + } + ], + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + ] + } + ] + } + ] + }, + { + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Mandatory", + "submodelElements": [ + { + "idShort": "ExampleRelationshipElement", + "modelType": "RelationshipElement", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + }, + { + "idShort": "ExampleAnnotatedRelationshipElement", + "modelType": "AnnotatedRelationshipElement", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + }, + { + "idShort": "ExampleOperation", + "modelType": "Operation" + }, + { + "idShort": "ExampleCapability", + "modelType": "Capability" + }, + { + "idShort": "ExampleBasicEventElement", + "modelType": "BasicEventElement", + "observed": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "direction": "input", + "state": "off" + }, + { + "idShort": "ExampleSubmodelList", + "typeValueListElement": "SubmodelElementCollection", + "modelType": "SubmodelElementList", + "value": [ + { + "modelType": "SubmodelElementCollection", + "value": [ + { + "idShort": "ExampleBlob", + "modelType": "Blob", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFile", + "modelType": "File", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleMultiLanguageProperty", + "category": "PARAMETER", + "modelType": "MultiLanguageProperty" + }, + { + "idShort": "ExampleProperty", + "category": "PARAMETER", + "modelType": "Property", + "valueType": "xs:string" + }, + { + "idShort": "ExampleRange", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:int" + }, + { + "idShort": "ExampleReferenceElement", + "category": "PARAMETER", + "modelType": "ReferenceElement" + } + ] + }, + { + "modelType": "SubmodelElementCollection" + } + ] + }, + { + "idShort": "ExampleSubmodelList2", + "typeValueListElement": "Capability", + "modelType": "SubmodelElementList" + } + ] + }, + { + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel2_Mandatory" + }, + { + "idShort": "TestSubmodel", + "description": [ + { + "language": "en-US", + "text": "An example submodel for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Missing", + "administration": { + "version": "9", + "revision": "0" + }, + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" + } + ] + }, + "submodelElements": [ + { + "idShort": "ExampleRelationshipElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example RelationshipElement object" + }, + { + "language": "de", + "text": "Beispiel RelationshipElement Element" + } + ], + "modelType": "RelationshipElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement" + } + ] + }, + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + }, + { + "idShort": "ExampleAnnotatedRelationshipElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example AnnotatedRelationshipElement object" + }, + { + "language": "de", + "text": "Beispiel AnnotatedRelationshipElement Element" + } + ], + "modelType": "AnnotatedRelationshipElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" + } + ] + }, + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "annotations": [ + { + "idShort": "ExampleAnnotatedRange", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:integer", + "min": "1", + "max": "5" + }, + { + "idShort": "ExampleAnnotatedProperty", + "category": "PARAMETER", + "modelType": "Property", + "value": "exampleValue", + "valueType": "xs:string" + } + ] + }, + { + "idShort": "ExampleOperation", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Operation object" + }, + { + "language": "de", + "text": "Beispiel Operation Element" + } + ], + "modelType": "Operation", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Operations/ExampleOperation" + } + ] + }, + "inputVariables": [ + { + "value": { + "idShort": "ExamplePropertyInput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyInput" + } + ] + }, + "kind": "Template", + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + } + ], + "outputVariables": [ + { + "value": { + "idShort": "ExamplePropertyOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyOutput" + } + ] + }, + "kind": "Template", + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + } + ], + "inoutputVariables": [ + { + "value": { + "idShort": "ExamplePropertyInOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" + } + ] + }, + "kind": "Template", + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + } + ] + }, + { + "idShort": "ExampleCapability", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Capability object" + }, + { + "language": "de", + "text": "Beispiel Capability Element" + } + ], + "modelType": "Capability", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Capabilities/ExampleCapability" + } + ] + } + }, + { + "idShort": "ExampleBasicEventElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example BasicEventElement object" + }, + { + "language": "de", + "text": "Beispiel BasicEventElement Element" + } + ], + "modelType": "BasicEventElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Events/ExampleBasicEventElement" + } + ] + }, + "observed": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" + }, + { + "idShort": "ExampleSubmodelCollection", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementCollection object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementCollection Element" + } + ], + "modelType": "SubmodelElementCollection", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "value": [ + { + "idShort": "ExampleBlob", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Blob object" + }, + { + "language": "de", + "text": "Beispiel Blob Element" + } + ], + "modelType": "Blob", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Blobs/ExampleBlob" + } + ] + }, + "contentType": "application/pdf", + "value": "AQIDBAU=" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" + } + ], + "modelType": "File", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Files/ExampleFile" + } + ] + }, + "value": "/TestFile.pdf", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleMultiLanguageProperty", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example MultiLanguageProperty object" + }, + { + "language": "de", + "text": "Beispiel MulitLanguageProperty Element" + } + ], + "modelType": "MultiLanguageProperty", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" + } + ] + }, + "value": [ + { + "language": "en-US", + "text": "Example value of a MultiLanguageProperty element" + }, + { + "language": "de", + "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + } + ] + }, + { + "idShort": "ExampleProperty", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "qualifiers": [ + { + "valueType": "xs:string", + "type": "http://acplt.org/Qualifier/ExampleQualifier" + } + ], + "value": "exampleValue", + "valueType": "xs:string" + }, + { + "idShort": "ExampleRange", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Range object" + }, + { + "language": "de", + "text": "Beispiel Range Element" + } + ], + "modelType": "Range", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Ranges/ExampleRange" + } + ] + }, + "valueType": "xs:int", + "min": "0", + "max": "100" + }, + { + "idShort": "ExampleReferenceElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Reference Element object" + }, + { + "language": "de", + "text": "Beispiel Reference Element Element" + } + ], + "modelType": "ReferenceElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" + } + ] + }, + "value": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + } + ] + } + ] + }, + { + "idShort": "TestSubmodel", + "description": [ + { + "language": "en-US", + "text": "An example submodel for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Template", + "administration": { + "version": "9", + "revision": "0" + }, + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" + } + ] + }, + "kind": "Template", + "submodelElements": [ + { + "idShort": "ExampleRelationshipElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example RelationshipElement object" + }, + { + "language": "de", + "text": "Beispiel RelationshipElement Element" + } + ], + "modelType": "RelationshipElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement" + } + ] + }, + "kind": "Template", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + }, + { + "idShort": "ExampleAnnotatedRelationshipElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example AnnotatedRelationshipElement object" + }, + { + "language": "de", + "text": "Beispiel AnnotatedRelationshipElement Element" + } + ], + "modelType": "AnnotatedRelationshipElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" + } + ] + }, + "kind": "Template", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + } + }, + { + "idShort": "ExampleOperation", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Operation object" + }, + { + "language": "de", + "text": "Beispiel Operation Element" + } + ], + "modelType": "Operation", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Operations/ExampleOperation" + } + ] + }, + "kind": "Template", + "inputVariables": [ + { + "value": { + "idShort": "ExamplePropertyInput", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyInput" + } + ] + }, + "kind": "Template", + "valueType": "xs:string" + } + } + ], + "outputVariables": [ + { + "value": { + "idShort": "ExamplePropertyOutput", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyOutput" + } + ] + }, + "kind": "Template", + "valueType": "xs:string" + } + } + ], + "inoutputVariables": [ + { + "value": { + "idShort": "ExamplePropertyInOutput", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" + } + ] + }, + "kind": "Template", + "valueType": "xs:string" + } + } + ] + }, + { + "idShort": "ExampleCapability", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Capability object" + }, + { + "language": "de", + "text": "Beispiel Capability Element" + } + ], + "modelType": "Capability", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Capabilities/ExampleCapability" + } + ] + }, + "kind": "Template" + }, + { + "idShort": "ExampleBasicEventElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example BasicEventElement object" + }, + { + "language": "de", + "text": "Beispiel BasicEventElement Element" + } + ], + "modelType": "BasicEventElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Events/ExampleBasicEventElement" + } + ] + }, + "kind": "Template", + "observed": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" + }, + { + "idShort": "ExampleSubmodelList", + "typeValueListElement": "SubmodelElementCollection", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "orderRelevant": true, + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementList object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementList Element" + } + ], + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] + }, + "kind": "Template", + "value": [ + { + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementCollection object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementCollection Element" + } + ], + "modelType": "SubmodelElementCollection", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "kind": "Template", + "value": [ + { + "idShort": "ExampleProperty", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "kind": "Template", + "valueType": "xs:string" + }, + { + "idShort": "ExampleMultiLanguageProperty", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example MultiLanguageProperty object" + }, + { + "language": "de", + "text": "Beispiel MulitLanguageProperty Element" + } + ], + "modelType": "MultiLanguageProperty", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" + } + ] + }, + "kind": "Template" + }, + { + "idShort": "ExampleRange", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Range object" + }, + { + "language": "de", + "text": "Beispiel Range Element" + } + ], + "modelType": "Range", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Ranges/ExampleRange" + } + ] + }, + "kind": "Template", + "valueType": "xs:int", + "max": "100" + }, + { + "idShort": "ExampleRange2", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Range object" + }, + { + "language": "de", + "text": "Beispiel Range Element" + } + ], + "modelType": "Range", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Ranges/ExampleRange" + } + ] + }, + "kind": "Template", + "valueType": "xs:int", + "min": "0" + }, + { + "idShort": "ExampleBlob", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Blob object" + }, + { + "language": "de", + "text": "Beispiel Blob Element" + } + ], + "modelType": "Blob", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Blobs/ExampleBlob" + } + ] + }, + "kind": "Template", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" + } + ], + "modelType": "File", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Files/ExampleFile" + } + ] + }, + "kind": "Template", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleReferenceElement", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example Reference Element object" + }, + { + "language": "de", + "text": "Beispiel Reference Element Element" + } + ], + "modelType": "ReferenceElement", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" + } + ] + }, + "kind": "Template" + } + ] + }, + { + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementCollection object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementCollection Element" + } + ], + "modelType": "SubmodelElementCollection", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "kind": "Template" + } + ] + }, + { + "idShort": "ExampleSubmodelList2", + "typeValueListElement": "Capability", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "orderRelevant": true, + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementList object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementList Element" + } + ], + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] + }, + "kind": "Template" + } + ] + } + ], + "conceptDescriptions": [ + { + "idShort": "TestConceptDescription", + "description": [ + { + "language": "en-US", + "text": "An example concept description for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-ConceptDescription f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription", + "administration": { + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_ConceptDescription" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] + }, + "isCaseOf": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription" + } + ] + } + ] + }, + { + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription_Mandatory" + }, + { + "idShort": "TestConceptDescription", + "description": [ + { + "language": "en-US", + "text": "An example concept description for the test application" + }, + { + "language": "de", + "text": "Ein Beispiel-ConceptDescription f\u00fcr eine Test-Anwendung" + } + ], + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription_Missing", + "administration": { + "version": "9", + "revision": "0" + } + } + ] +} \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_json_aasx/docProps/core.xml b/test/compliance_tool/files/test_demo_full_example_json_aasx/docProps/core.xml new file mode 100644 index 000000000..5f0e65331 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_json_aasx/docProps/core.xml @@ -0,0 +1 @@ +2020-01-01T00:00:00Eclipse BaSyx Python Testing FrameworkTest_DescriptionEclipse BaSyx Python Testing Framework Compliance Tool2020-01-01T00:00:011.0Test Title2.0.1 \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.aasx b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.aasx deleted file mode 100644 index ab9451919..000000000 Binary files a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.aasx and /dev/null differ diff --git a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json index 1318195c1..8f816697d 100644 --- a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json +++ b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json @@ -4,7 +4,7 @@ "idShort": "TestAssetAdministrationShell123", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An Example Asset Administration Shell for the test application" }, { @@ -12,175 +12,257 @@ "text": "Ein Beispiel-Verwaltungsschale f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell", - "idType": "IRI" - }, + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell" }, "derivedFrom": { + "type": "ModelReference", "keys": [ { "type": "AssetAdministrationShell", - "idType": "IRI", - "value": "https://acplt.org/TestAssetAdministrationShell2", - "local": false + "value": "https://acplt.org/TestAssetAdministrationShell2" } ] }, - "asset": { - "keys": [ + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset/", + "specificAssetIds": [ { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset", - "local": false + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + }, + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" + } + ] + } } - ] + ], + "assetType": "http://acplt.org/TestAssetType/", + "defaultThumbnail": { + "path": "file:///path/to/thumbnail.png", + "contentType": "image/png" + } }, "submodels": [ { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", - "local": true + "value": "https://acplt.org/Test_Submodel" } - ] + ], + "referredSemanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" + } + ] + } }, { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel", - "local": true + "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial" } ] }, { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "local": true + "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification" } - ] + ], + "referredSemanticId": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/SubmodelTemplates/AssetIdentification" + } + ] + } } ], - "conceptDictionaries": [ + "embeddedDataSpecifications": [ { - "idShort": "TestConceptDictionary", - "description": [ - { - "language": "en-us", - "text": "An example concept dictionary for the test application" - }, - { - "language": "de", - "text": "Ein Beispiel-ConceptDictionary f\u00fcr eine Test-Anwendung" - } - ], - "modelType": { - "name": "ConceptDictionary" + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] }, - "conceptDescriptions": [ - { + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", "keys": [ { - "type": "ConceptDescription", - "idType": "IRI", - "value": "https://acplt.org/Test_ConceptDescription", - "local": false + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" } ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false } - ] + } } ] }, { - "idShort": "", - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell_Mandatory", - "idType": "IRI" - }, - "asset": { - "keys": [ - { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset_Mandatory", - "local": false - } - ] + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell_Mandatory", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset_Mandatory/" }, "submodels": [ { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel_Mandatory", - "local": true + "value": "https://acplt.org/Test_Submodel2_Mandatory" } ] }, { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel2_Mandatory", - "local": true + "value": "https://acplt.org/Test_Submodel_Mandatory" } ] } - ], - "conceptDictionaries": [ - { - "idShort": "TestConceptDictionary", - "modelType": { - "name": "ConceptDictionary" - } - } ] }, { - "idShort": "", - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell2_Mandatory", - "idType": "IRI" - }, - "asset": { - "keys": [ - { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset_Mandatory", - "local": false - } - ] + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell2_Mandatory", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset2_Mandatory/" } }, { "idShort": "TestAssetAdministrationShell", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An Example Asset Administration Shell for the test application" }, { @@ -188,91 +270,42 @@ "text": "Ein Beispiel-Verwaltungsschale f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "AssetAdministrationShell" - }, - "identification": { - "id": "https://acplt.org/Test_AssetAdministrationShell_Missing", - "idType": "IRI" - }, + "modelType": "AssetAdministrationShell", + "id": "https://acplt.org/Test_AssetAdministrationShell_Missing", "administration": { - "version": "0.9", + "version": "9", "revision": "0" }, - "asset": { - "keys": [ + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset_Missing/", + "specificAssetIds": [ { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset_Missing", - "local": false - } - ] - }, - "submodels": [ - { - "keys": [ - { - "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel_Missing", - "local": true - } - ] - } - ], - "views": [ - { - "idShort": "ExampleView", - "modelType": { - "name": "View" - }, - "containedElements": [ - { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", "keys": [ { - "type": "Submodel", - "idType": "IRI", - "value": "https://acplt.org/Test_Submodel_Missing", - "local": false + "type": "GlobalReference", + "value": "http://acplt.org/SpecificAssetId/" } ] } - ] - }, - { - "idShort": "ExampleView2", - "modelType": { - "name": "View" } + ], + "defaultThumbnail": { + "path": "file:///TestFile.pdf", + "contentType": "application/pdf" } - ], - "conceptDictionaries": [ + }, + "submodels": [ { - "idShort": "TestConceptDictionary", - "description": [ - { - "language": "en-us", - "text": "An example concept dictionary for the test application" - }, - { - "language": "de", - "text": "Ein Beispiel-ConceptDictionary f\u00fcr eine Test-Anwendung" - } - ], - "modelType": { - "name": "ConceptDictionary" - }, - "conceptDescriptions": [ + "type": "ModelReference", + "keys": [ { - "keys": [ - { - "type": "ConceptDescription", - "idType": "IRI", - "value": "https://acplt.org/Test_ConceptDescription_Missing", - "local": false - } - ] + "type": "Submodel", + "value": "https://acplt.org/Test_Submodel_Missing" } ] } @@ -284,7 +317,7 @@ "idShort": "Identification", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example asset identification submodel for the test application" }, { @@ -292,33 +325,56 @@ "text": "Ein Beispiel-Identifikations-Submodel f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/TestAsset/Identification" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification" }, "semanticId": { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/AssetIdentification", - "local": false + "value": "http://acplt.org/SubmodelTemplates/AssetIdentification" } ] }, "submodelElements": [ { + "extensions": [ + { + "value": "ExampleExtensionValue", + "refersTo": [ + { + "type": "ModelReference", + "keys": [ + { + "type": "AssetAdministrationShell", + "value": "http://acplt.org/RefersTo/ExampleRefersTo" + } + ] + } + ], + "valueType": "xs:string", + "name": "ExampleExtension" + } + ], "idShort": "ManufacturerName", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -326,75 +382,66 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "0173-1#02-AAO677#002", - "local": false + "value": "0173-1#02-AAO677#002" } ] }, "qualifiers": [ { - "modelType": { - "name": "Qualifier" - }, "value": "50", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "int", - "type": "http://acplt.org/Qualifier/ExampleQualifier2" + "valueType": "xs:int", + "type": "http://acplt.org/Qualifier/ExampleQualifier2", + "kind": "TemplateQualifier" }, { - "modelType": { - "name": "Qualifier" - }, "value": "100", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "int", - "type": "http://acplt.org/Qualifier/ExampleQualifier" + "valueType": "xs:int", + "type": "http://acplt.org/Qualifier/ExampleQualifier", + "kind": "ConceptQualifier" } ], "value": "ACPLT", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "InstanceId", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -402,31 +449,44 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber", - "local": false + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" } ] }, + "qualifiers": [ + { + "value": "2023-04-07T16:59:54.870123", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:dateTime", + "type": "http://acplt.org/Qualifier/ExampleQualifier3", + "kind": "ValueQualifier" + } + ], "value": "978-8234-234-342", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } ] }, @@ -434,7 +494,7 @@ "idShort": "BillOfMaterial", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example bill of material submodel for the test application" }, { @@ -442,32 +502,28 @@ "text": "Ein Beispiel-BillofMaterial-Submodel f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", "administration": { - "version": "0.9" + "version": "9", + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial" }, "semanticId": { + "type": "ModelReference", "keys": [ { "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/BillOfMaterial", - "local": false + "value": "http://acplt.org/SubmodelTemplates/BillOfMaterial" } ] }, "submodelElements": [ { "idShort": "ExampleEntity", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -475,16 +531,13 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Entity" - }, + "modelType": "Entity", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber", - "local": false + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" } ] }, @@ -494,7 +547,7 @@ "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -502,38 +555,34 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, "value": "exampleValue2", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "ExampleProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -541,64 +590,159 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Formula" + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" } - }, + ] + }, + "valueType": "xs:string", + "embeddedDataSpecifications": [ { - "modelType": { - "name": "Formula" + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] }, - "dependsOn": [ - { + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + }, + "valueType": "xs:string" + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/Values/TestValueId" } ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false } - ] + } } - ], - "value": "exampleValue", - "valueId": { + ] + } + ], + "entityType": "SelfManagedEntity", + "globalAssetId": "http://acplt.org/TestAsset/", + "specificAssetIds": [ + { + "name": "TestKey", + "value": "TestValue", + "externalSubjectId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/SpecificAssetId/" } ] - }, - "valueType": "string" + } } - ], - "entityType": "CoManagedEntity" + ] }, { "idShort": "ExampleEntity2", + "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation." }, { @@ -606,30 +750,17 @@ "text": "Bezeichnung f\u00fcr eine nat\u00fcrliche oder juristische Person, die f\u00fcr die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist" } ], - "modelType": { - "name": "Entity" - }, + "modelType": "Entity", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber", - "local": false + "value": "http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber" } ] }, - "entityType": "SelfManagedEntity", - "asset": { - "keys": [ - { - "type": "Asset", - "idType": "IRI", - "value": "https://acplt.org/Test_Asset2", - "local": false - } - ] - } + "entityType": "CoManagedEntity" } ] }, @@ -637,7 +768,7 @@ "idShort": "TestSubmodel", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example submodel for the test application" }, { @@ -645,24 +776,27 @@ "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_Submodel" + } + ] + } }, "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel", - "local": false + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" } ] }, @@ -672,7 +806,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example RelationshipElement object" }, { @@ -680,36 +814,39 @@ "text": "Beispiel RelationshipElement Element" } ], - "modelType": { - "name": "RelationshipElement" - }, + "modelType": "RelationshipElement", "semanticId": { + "type": "ModelReference", "keys": [ { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement", - "local": false + "type": "ConceptDescription", + "value": "https://acplt.org/Test_ConceptDescription" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty2", - "local": true + "value": "ExampleProperty2" } ] } @@ -719,7 +856,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example AnnotatedRelationshipElement object" }, { @@ -727,54 +864,55 @@ "text": "Beispiel AnnotatedRelationshipElement Element" } ], - "modelType": { - "name": "AnnotatedRelationshipElement" - }, + "modelType": "AnnotatedRelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty2", - "local": true + "value": "ExampleProperty2" } ] }, - "annotation": [ + "annotations": [ { "idShort": "ExampleAnnotatedProperty", - "modelType": { - "name": "Property" - }, + "category": "PARAMETER", + "modelType": "Property", "value": "exampleValue", - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "ExampleAnnotatedRange", - "modelType": { - "name": "Range" - }, - "valueType": "integer", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:integer", "min": "1", "max": "5" } @@ -785,7 +923,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Operation object" }, { @@ -793,27 +931,34 @@ "text": "Beispiel Operation Element" } ], - "modelType": { - "name": "Operation" - }, + "modelType": "Operation", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Operations/ExampleOperation", - "local": false + "value": "http://acplt.org/Operations/ExampleOperation" } ] }, - "inputVariable": [ + "inputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -821,42 +966,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInput" } ] }, + "kind": "Template", "value": "exampleValue", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } } ], - "outputVariable": [ + "outputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -864,42 +1016,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyOutput" } ] }, + "kind": "Template", "value": "exampleValue", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } } ], - "inoutputVariable": [ + "inoutputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -907,31 +1066,28 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" } ] }, + "kind": "Template", "value": "exampleValue", "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleValueId" } ] }, - "valueType": "string" + "valueType": "xs:string" } } ] @@ -941,7 +1097,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Capability object" }, { @@ -949,152 +1105,206 @@ "text": "Beispiel Capability Element" } ], - "modelType": { - "name": "Capability" - }, + "modelType": "Capability", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Capabilities/ExampleCapability", - "local": false + "value": "http://acplt.org/Capabilities/ExampleCapability" } ] } }, { - "idShort": "ExampleBasicEvent", + "idShort": "ExampleBasicEventElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example BasicEvent object" + "language": "en-US", + "text": "Example BasicEventElement object" }, { "language": "de", - "text": "Beispiel BasicEvent Element" + "text": "Beispiel BasicEventElement Element" } ], - "modelType": { - "name": "BasicEvent" - }, + "modelType": "BasicEventElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Events/ExampleBasicEvent", - "local": false + "value": "http://acplt.org/Events/ExampleBasicEventElement" } ] }, "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" }, { - "idShort": "ExampleSubmodelCollectionOrdered", + "idShort": "ExampleSubmodelCollection", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionOrdered object" + "language": "en-US", + "text": "Example SubmodelElementCollection object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionOrdered Element" + "text": "Beispiel SubmodelElementCollection Element" } ], - "modelType": { - "name": "SubmodelElementCollection" - }, + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, "value": [ { - "idShort": "ExampleProperty", - "category": "CONSTANT", + "idShort": "ExampleBlob", + "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Property object" + "language": "en-US", + "text": "Example Blob object" }, { "language": "de", - "text": "Beispiel Property Element" + "text": "Beispiel Blob Element" } ], - "modelType": { - "name": "Property" + "modelType": "Blob", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Blobs/ExampleBlob" + } + ] }, + "contentType": "application/pdf", + "value": "AQIDBAU=" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" + } + ], + "modelType": "File", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Files/ExampleFile" } ] }, - "value": "exampleValue", - "valueId": { + "value": "/TestFile.pdf", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFileURI", + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Details of the Asset Administration Shell \u2014 An example for an external file reference" + }, + { + "language": "de", + "text": "Details of the Asset Administration Shell \u2013 Ein Beispiel f\u00fcr eine extern referenzierte Datei" + } + ], + "modelType": "File", + "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false + "value": "http://acplt.org/Files/ExampleFile" } ] }, - "valueType": "string" + "value": "https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5", + "contentType": "application/pdf" }, { "idShort": "ExampleMultiLanguageProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example MultiLanguageProperty object" }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], - "modelType": { - "name": "MultiLanguageProperty" - }, + "modelType": "MultiLanguageProperty", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty", - "local": false + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" } - ] + ], + "referredSemanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/Referred" + } + ] + } }, "value": [ { - "language": "en-us", + "language": "en-US", "text": "Example value of a MultiLanguageProperty element" }, { @@ -1103,12 +1313,11 @@ } ], "valueId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleMultiLanguageValueId", - "local": false + "value": "http://acplt.org/ValueId/ExampleMultiLanguageValueId" } ] } @@ -1118,7 +1327,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Range object" }, { @@ -1126,358 +1335,476 @@ "text": "Beispiel Range Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, - "valueType": "int", + "valueType": "xs:int", "min": "0", "max": "100" - } - ], - "ordered": true - }, - { - "idShort": "ExampleSubmodelCollectionUnordered", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" }, { - "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" - } - ], - "modelType": { - "name": "SubmodelElementCollection" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false - } - ] - }, - "value": [ - { - "idShort": "ExampleBlob", + "idShort": "ExampleReferenceElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Blob object" + "language": "en-US", + "text": "Example Reference Element object" }, { "language": "de", - "text": "Beispiel Blob Element" + "text": "Beispiel Reference Element Element" } ], - "modelType": { - "name": "Blob" - }, + "modelType": "ReferenceElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Blobs/ExampleBlob", - "local": false + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" } ] }, - "mimeType": "application/pdf", - "value": "AQIDBAU=" - }, - { - "idShort": "ExampleFile", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example File object" - }, - { - "language": "de", - "text": "Beispiel File Element" - } - ], - "modelType": { - "name": "File" - }, - "semanticId": { + "value": { + "type": "ModelReference", "keys": [ { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" } ] - }, - "value": "/TestFile.pdf", - "mimeType": "application/pdf" + } }, { - "idShort": "ExampleFileURI", - "category": "CONSTANT", - "description": [ - { - "language": "en-us", - "text": "Details of the Asset Administration Shell\u2014An example for an external file reference" - }, - { - "language": "de", - "text": "Details of the Asset Administration Shell \u2013 Ein Beispiel f\u00fcr eine extern referenzierte Datei" - } - ], - "modelType": { - "name": "File" - }, - "semanticId": { + "idShort": "ExampleSubmodelList", + "typeValueListElement": "Property", + "valueTypeListElement": "xs:string", + "semanticIdListElement": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, - "value": "https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5", - "mimeType": "application/pdf" - }, - { - "idShort": "ExampleReferenceElement", + "orderRelevant": true, "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Reference Element object" + "language": "en-US", + "text": "Example SubmodelElementList object" }, { "language": "de", - "text": "Beispiel Reference Element Element" + "text": "Beispiel SubmodelElementList Element" } ], - "modelType": { - "name": "ReferenceElement" - }, + "modelType": "SubmodelElementList", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement", - "local": false + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" } ] }, - "value": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - } - } - ], - "ordered": false - } - ] - }, - { - "idShort": "", - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel_Mandatory", - "idType": "IRI" - }, - "submodelElements": [ - { - "idShort": "ExampleRelationshipElement", - "modelType": { - "name": "RelationshipElement" - }, - "first": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - }, - "second": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - } - }, - { - "idShort": "ExampleAnnotatedRelationshipElement", - "modelType": { - "name": "AnnotatedRelationshipElement" - }, - "first": { - "keys": [ - { - "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true - } - ] - }, - "second": { - "keys": [ + "value": [ + { + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "supplementalSemanticIds": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/SupplementalId1" + } + ] + }, + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty/SupplementalId2" + } + ] + } + ], + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] + }, + { + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], + "category": "CONSTANT", + "description": [ + { + "language": "en-US", + "text": "Example Property object" + }, + { + "language": "de", + "text": "Beispiel Property Element" + } + ], + "modelType": "Property", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty" + } + ] + }, + "supplementalSemanticIds": [ + { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Properties/ExampleProperty2/SupplementalId" + } + ] + } + ], + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" + } + ] + } + ] + } + ] + }, + { + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Mandatory", + "submodelElements": [ + { + "idShort": "ExampleRelationshipElement", + "modelType": "RelationshipElement", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } }, { - "idShort": "ExampleOperation", - "modelType": { - "name": "Operation" + "idShort": "ExampleAnnotatedRelationshipElement", + "modelType": "AnnotatedRelationshipElement", + "first": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] + }, + "second": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, + { + "type": "Property", + "value": "ExampleProperty" + } + ] } }, + { + "idShort": "ExampleOperation", + "modelType": "Operation" + }, { "idShort": "ExampleCapability", - "modelType": { - "name": "Capability" - } + "modelType": "Capability" }, { - "idShort": "ExampleBasicEvent", - "modelType": { - "name": "BasicEvent" - }, + "idShort": "ExampleBasicEventElement", + "modelType": "BasicEventElement", "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } - }, - { - "idShort": "ExampleSubmodelCollectionOrdered", - "modelType": { - "name": "SubmodelElementCollection" }, - "value": [ - { - "idShort": "ExampleProperty", - "modelType": { - "name": "Property" - }, - "value": null, - "valueType": "string" - }, - { - "idShort": "ExampleMultiLanguageProperty", - "modelType": { - "name": "MultiLanguageProperty" - } - }, - { - "idShort": "ExampleRange", - "modelType": { - "name": "Range" - }, - "valueType": "int", - "min": null, - "max": null - } - ], - "ordered": true + "direction": "input", + "state": "off" }, { - "idShort": "ExampleSubmodelCollectionUnordered", - "modelType": { - "name": "SubmodelElementCollection" - }, + "idShort": "ExampleSubmodelList", + "typeValueListElement": "SubmodelElementCollection", + "modelType": "SubmodelElementList", "value": [ { - "idShort": "ExampleBlob", - "modelType": { - "name": "Blob" - }, - "mimeType": "application/pdf" - }, - { - "idShort": "ExampleFile", - "modelType": { - "name": "File" - }, - "value": null, - "mimeType": "application/pdf" + "modelType": "SubmodelElementCollection", + "value": [ + { + "idShort": "ExampleBlob", + "modelType": "Blob", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleFile", + "modelType": "File", + "contentType": "application/pdf" + }, + { + "idShort": "ExampleMultiLanguageProperty", + "category": "PARAMETER", + "modelType": "MultiLanguageProperty" + }, + { + "idShort": "ExampleProperty", + "category": "PARAMETER", + "modelType": "Property", + "valueType": "xs:string" + }, + { + "idShort": "ExampleRange", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:int" + }, + { + "idShort": "ExampleReferenceElement", + "category": "PARAMETER", + "modelType": "ReferenceElement" + } + ] }, { - "idShort": "ExampleReferenceElement", - "modelType": { - "name": "ReferenceElement" - } + "modelType": "SubmodelElementCollection" } - ], - "ordered": false + ] }, { - "idShort": "ExampleSubmodelCollectionUnordered2", - "modelType": { - "name": "SubmodelElementCollection" - }, - "ordered": false + "idShort": "ExampleSubmodelList2", + "typeValueListElement": "Capability", + "modelType": "SubmodelElementList" } ] }, { - "idShort": "", - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel2_Mandatory", - "idType": "IRI" - } + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel2_Mandatory" }, { "idShort": "TestSubmodel", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example submodel for the test application" }, { @@ -1485,24 +1812,18 @@ "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel_Missing", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Missing", "administration": { - "version": "0.9", + "version": "9", "revision": "0" }, "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel", - "local": false + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" } ] }, @@ -1512,7 +1833,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example RelationshipElement object" }, { @@ -1520,36 +1841,39 @@ "text": "Beispiel RelationshipElement Element" } ], - "modelType": { - "name": "RelationshipElement" - }, + "modelType": "RelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } @@ -1559,7 +1883,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example AnnotatedRelationshipElement object" }, { @@ -1567,56 +1891,57 @@ "text": "Beispiel AnnotatedRelationshipElement Element" } ], - "modelType": { - "name": "AnnotatedRelationshipElement" - }, + "modelType": "AnnotatedRelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" } ] }, "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, - "annotation": [ - { - "idShort": "ExampleAnnotatedProperty", - "modelType": { - "name": "Property" - }, - "value": "exampleValue", - "valueType": "string" - }, + "annotations": [ { "idShort": "ExampleAnnotatedRange", - "modelType": { - "name": "Range" - }, - "valueType": "integer", + "category": "PARAMETER", + "modelType": "Range", + "valueType": "xs:integer", "min": "1", "max": "5" + }, + { + "idShort": "ExampleAnnotatedProperty", + "category": "PARAMETER", + "modelType": "Property", + "value": "exampleValue", + "valueType": "xs:string" } ] }, @@ -1625,7 +1950,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Operation object" }, { @@ -1633,27 +1958,34 @@ "text": "Beispiel Operation Element" } ], - "modelType": { - "name": "Operation" - }, + "modelType": "Operation", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Operations/ExampleOperation", - "local": false + "value": "http://acplt.org/Operations/ExampleOperation" } ] }, - "inputVariable": [ + "inputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -1661,41 +1993,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInput" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" - } - ], + "kind": "Template", "value": "exampleValue", - "valueType": "string" + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" } } ], - "outputVariable": [ + "outputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -1703,41 +2043,49 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyOutput" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" - } - ], + "kind": "Template", "value": "exampleValue", - "valueType": "string" + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" } } ], - "inoutputVariable": [ + "inoutputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInOutput", + "displayName": [ + { + "language": "en-US", + "text": "ExampleProperty" + }, + { + "language": "de", + "text": "BeispielProperty" + } + ], "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -1745,30 +2093,28 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" } ] }, - "qualifiers": [ - { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" - } - ], + "kind": "Template", "value": "exampleValue", - "valueType": "string" + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + }, + "valueType": "xs:string" } } ] @@ -1778,7 +2124,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Capability object" }, { @@ -1786,128 +2132,151 @@ "text": "Beispiel Capability Element" } ], - "modelType": { - "name": "Capability" - }, + "modelType": "Capability", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Capabilities/ExampleCapability", - "local": false + "value": "http://acplt.org/Capabilities/ExampleCapability" } ] } }, { - "idShort": "ExampleBasicEvent", + "idShort": "ExampleBasicEventElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example BasicEvent object" + "language": "en-US", + "text": "Example BasicEventElement object" }, { "language": "de", - "text": "Beispiel BasicEvent Element" + "text": "Beispiel BasicEventElement Element" } ], - "modelType": { - "name": "BasicEvent" - }, + "modelType": "BasicEventElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Events/ExampleBasicEvent", - "local": false + "value": "http://acplt.org/Events/ExampleBasicEventElement" } ] }, "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" }, { - "idShort": "ExampleSubmodelCollectionOrdered", + "idShort": "ExampleSubmodelCollection", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionOrdered object" + "language": "en-US", + "text": "Example SubmodelElementCollection object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionOrdered Element" + "text": "Beispiel SubmodelElementCollection Element" } ], - "modelType": { - "name": "SubmodelElementCollection" - }, + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, "value": [ { - "idShort": "ExampleProperty", - "category": "CONSTANT", + "idShort": "ExampleBlob", + "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example Property object" + "language": "en-US", + "text": "Example Blob object" }, { "language": "de", - "text": "Beispiel Property Element" + "text": "Beispiel Blob Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Blob", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Blobs/ExampleBlob" } ] }, - "qualifiers": [ + "contentType": "application/pdf", + "value": "AQIDBAU=" + }, + { + "idShort": "ExampleFile", + "category": "PARAMETER", + "description": [ { - "modelType": { - "name": "Qualifier" - }, - "valueType": "string", - "type": "http://acplt.org/Qualifier/ExampleQualifier" + "language": "en-US", + "text": "Example File object" + }, + { + "language": "de", + "text": "Beispiel File Element" } ], - "value": "exampleValue", - "valueType": "string" + "modelType": "File", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Files/ExampleFile" + } + ] + }, + "value": "/TestFile.pdf", + "contentType": "application/pdf" }, { "idShort": "ExampleMultiLanguageProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example MultiLanguageProperty object" }, { @@ -1915,22 +2284,19 @@ "text": "Beispiel MulitLanguageProperty Element" } ], - "modelType": { - "name": "MultiLanguageProperty" - }, + "modelType": "MultiLanguageProperty", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty", - "local": false + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" } ] }, "value": [ { - "language": "en-us", + "language": "en-US", "text": "Example value of a MultiLanguageProperty element" }, { @@ -1940,129 +2306,70 @@ ] }, { - "idShort": "ExampleRange", - "category": "PARAMETER", + "idShort": "ExampleProperty", + "category": "CONSTANT", "description": [ { - "language": "en-us", - "text": "Example Range object" + "language": "en-US", + "text": "Example Property object" }, { "language": "de", - "text": "Beispiel Range Element" + "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, - "valueType": "int", - "min": "0", - "max": "100" - } - ], - "ordered": true - }, - { - "idShort": "ExampleSubmodelCollectionUnordered", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" - }, - { - "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" - } - ], - "modelType": { - "name": "SubmodelElementCollection" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false - } - ] - }, - "value": [ - { - "idShort": "ExampleBlob", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example Blob object" - }, + "qualifiers": [ { - "language": "de", - "text": "Beispiel Blob Element" + "valueType": "xs:string", + "type": "http://acplt.org/Qualifier/ExampleQualifier" } ], - "modelType": { - "name": "Blob" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Blobs/ExampleBlob", - "local": false - } - ] - }, - "mimeType": "application/pdf", - "value": "AQIDBAU=" + "value": "exampleValue", + "valueType": "xs:string" }, { - "idShort": "ExampleFile", + "idShort": "ExampleRange", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example File object" + "language": "en-US", + "text": "Example Range object" }, { "language": "de", - "text": "Beispiel File Element" + "text": "Beispiel Range Element" } ], - "modelType": { - "name": "File" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, - "value": "/TestFile.pdf", - "mimeType": "application/pdf" + "valueType": "xs:int", + "min": "0", + "max": "100" }, { "idShort": "ExampleReferenceElement", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Reference Element object" }, { @@ -2070,32 +2377,31 @@ "text": "Beispiel Reference Element Element" } ], - "modelType": { - "name": "ReferenceElement" - }, + "modelType": "ReferenceElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement", - "local": false + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" } ] }, "value": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } } - ], - "ordered": false + ] } ] }, @@ -2103,7 +2409,7 @@ "idShort": "TestSubmodel", "description": [ { - "language": "en-us", + "language": "en-US", "text": "An example submodel for the test application" }, { @@ -2111,24 +2417,18 @@ "text": "Ein Beispiel-Teilmodell f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "Submodel" - }, - "identification": { - "id": "https://acplt.org/Test_Submodel_Template", - "idType": "IRI" - }, + "modelType": "Submodel", + "id": "https://acplt.org/Test_Submodel_Template", "administration": { - "version": "0.9", + "version": "9", "revision": "0" }, "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel", - "local": false + "value": "http://acplt.org/SubmodelTemplates/ExampleSubmodel" } ] }, @@ -2139,7 +2439,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example RelationshipElement object" }, { @@ -2147,37 +2447,40 @@ "text": "Beispiel RelationshipElement Element" } ], - "modelType": { - "name": "RelationshipElement" - }, + "modelType": "RelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleRelationshipElement" } ] }, "kind": "Template", "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } @@ -2187,7 +2490,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example AnnotatedRelationshipElement object" }, { @@ -2195,37 +2498,40 @@ "text": "Beispiel AnnotatedRelationshipElement Element" } ], - "modelType": { - "name": "AnnotatedRelationshipElement" - }, + "modelType": "AnnotatedRelationshipElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement", - "local": false + "value": "http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement" } ] }, "kind": "Template", "first": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] }, "second": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] } @@ -2235,7 +2541,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Operation object" }, { @@ -2243,28 +2549,25 @@ "text": "Beispiel Operation Element" } ], - "modelType": { - "name": "Operation" - }, + "modelType": "Operation", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Operations/ExampleOperation", - "local": false + "value": "http://acplt.org/Operations/ExampleOperation" } ] }, "kind": "Template", - "inputVariable": [ + "inputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInput", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2272,33 +2575,29 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInput" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" } } ], - "outputVariable": [ + "outputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyOutput", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2306,33 +2605,29 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyOutput" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" } } ], - "inoutputVariable": [ + "inoutputVariables": [ { "value": { - "idShort": "ExampleProperty", + "idShort": "ExamplePropertyInOutput", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2340,22 +2635,18 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExamplePropertyInOutput" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" } } ] @@ -2365,7 +2656,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Capability object" }, { @@ -2373,82 +2664,126 @@ "text": "Beispiel Capability Element" } ], - "modelType": { - "name": "Capability" - }, + "modelType": "Capability", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Capabilities/ExampleCapability", - "local": false + "value": "http://acplt.org/Capabilities/ExampleCapability" } ] }, "kind": "Template" }, { - "idShort": "ExampleBasicEvent", + "idShort": "ExampleBasicEventElement", "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example BasicEvent object" + "language": "en-US", + "text": "Example BasicEventElement object" }, { "language": "de", - "text": "Beispiel BasicEvent Element" + "text": "Beispiel BasicEventElement Element" } ], - "modelType": { - "name": "BasicEvent" - }, + "modelType": "BasicEventElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Events/ExampleBasicEvent", - "local": false + "value": "http://acplt.org/Events/ExampleBasicEventElement" } ] }, "kind": "Template", "observed": { + "type": "ModelReference", "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/Test_Submodel" + }, { "type": "Property", - "idType": "IdShort", - "value": "ExampleProperty", - "local": true + "value": "ExampleProperty" } ] - } + }, + "direction": "output", + "state": "on", + "messageTopic": "ExampleTopic", + "messageBroker": { + "type": "ModelReference", + "keys": [ + { + "type": "Submodel", + "value": "http://acplt.org/ExampleMessageBroker" + } + ] + }, + "lastUpdate": "2022-11-12T23:50:23.123456+00:00", + "minInterval": "PT0.000001S", + "maxInterval": "P1Y2M3DT4H5M6.123456S" }, { - "idShort": "ExampleSubmodelCollectionOrdered", + "idShort": "ExampleSubmodelList", + "typeValueListElement": "SubmodelElementCollection", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "orderRelevant": true, "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionOrdered object" + "language": "en-US", + "text": "Example SubmodelElementList object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionOrdered Element" + "text": "Beispiel SubmodelElementList Element" } ], - "modelType": { - "name": "SubmodelElementCollection" + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] }, + "kind": "Template", + "value": [ + { + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementCollection object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementCollection Element" + } + ], + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, @@ -2459,7 +2794,7 @@ "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Property object" }, { @@ -2467,29 +2802,25 @@ "text": "Beispiel Property Element" } ], - "modelType": { - "name": "Property" - }, + "modelType": "Property", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Properties/ExampleProperty", - "local": false + "value": "http://acplt.org/Properties/ExampleProperty" } ] }, "kind": "Template", - "value": null, - "valueType": "string" + "valueType": "xs:string" }, { "idShort": "ExampleMultiLanguageProperty", "category": "CONSTANT", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example MultiLanguageProperty object" }, { @@ -2497,16 +2828,13 @@ "text": "Beispiel MulitLanguageProperty Element" } ], - "modelType": { - "name": "MultiLanguageProperty" - }, + "modelType": "MultiLanguageProperty", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty", - "local": false + "value": "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty" } ] }, @@ -2517,7 +2845,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Range object" }, { @@ -2525,22 +2853,18 @@ "text": "Beispiel Range Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, "kind": "Template", - "valueType": "int", - "min": null, + "valueType": "xs:int", "max": "100" }, { @@ -2548,7 +2872,7 @@ "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Range object" }, { @@ -2556,61 +2880,26 @@ "text": "Beispiel Range Element" } ], - "modelType": { - "name": "Range" - }, + "modelType": "Range", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Ranges/ExampleRange", - "local": false + "value": "http://acplt.org/Ranges/ExampleRange" } ] }, "kind": "Template", - "valueType": "int", - "min": "0", - "max": null - } - ], - "ordered": true - }, - { - "idShort": "ExampleSubmodelCollectionUnordered", - "category": "PARAMETER", - "description": [ - { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" + "valueType": "xs:int", + "min": "0" }, - { - "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" - } - ], - "modelType": { - "name": "SubmodelElementCollection" - }, - "semanticId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false - } - ] - }, - "kind": "Template", - "value": [ { "idShort": "ExampleBlob", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Blob object" }, { @@ -2618,28 +2907,25 @@ "text": "Beispiel Blob Element" } ], - "modelType": { - "name": "Blob" - }, + "modelType": "Blob", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Blobs/ExampleBlob", - "local": false + "value": "http://acplt.org/Blobs/ExampleBlob" } ] }, "kind": "Template", - "mimeType": "application/pdf" + "contentType": "application/pdf" }, { "idShort": "ExampleFile", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example File object" }, { @@ -2647,29 +2933,25 @@ "text": "Beispiel File Element" } ], - "modelType": { - "name": "File" - }, + "modelType": "File", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Files/ExampleFile", - "local": false + "value": "http://acplt.org/Files/ExampleFile" } ] }, "kind": "Template", - "value": null, - "mimeType": "application/pdf" + "contentType": "application/pdf" }, { "idShort": "ExampleReferenceElement", "category": "PARAMETER", "description": [ { - "language": "en-us", + "language": "en-US", "text": "Example Reference Element object" }, { @@ -2677,134 +2959,83 @@ "text": "Beispiel Reference Element Element" } ], - "modelType": { - "name": "ReferenceElement" - }, + "modelType": "ReferenceElement", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement", - "local": false + "value": "http://acplt.org/ReferenceElements/ExampleReferenceElement" } ] }, "kind": "Template" } - ], - "ordered": false + ] }, - { - "idShort": "ExampleSubmodelCollectionUnordered2", + { "category": "PARAMETER", "description": [ { - "language": "en-us", - "text": "Example SubmodelElementCollectionUnordered object" + "language": "en-US", + "text": "Example SubmodelElementCollection object" }, { "language": "de", - "text": "Beispiel SubmodelElementCollectionUnordered Element" + "text": "Beispiel SubmodelElementCollection Element" } ], - "modelType": { - "name": "SubmodelElementCollection" - }, + "modelType": "SubmodelElementCollection", "semanticId": { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered", - "local": false + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" } ] }, - "kind": "Template", - "ordered": false - } - ] - } - ], - "assets": [ - { - "idShort": "Test_Asset", - "description": [ - { - "language": "en-us", - "text": "An example asset for the test application" - }, - { - "language": "de", - "text": "Ein Beispiel-Asset f\u00fcr eine Test-Anwendung" + "kind": "Template" } - ], - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset", - "idType": "IRI" - }, - "administration": { - "version": "0.9", - "revision": "0" - }, - "kind": "Instance", - "assetIdentificationModel": { - "keys": [ - { - "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/Identification", - "local": false - } - ] - }, - "billOfMaterial": { - "keys": [ - { - "type": "Submodel", - "idType": "IRI", - "value": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", - "local": false - } - ] - } - }, - { - "idShort": "", - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset_Mandatory", - "idType": "IRI" - }, - "kind": "Instance" - }, - { - "idShort": "Test_Asset", - "description": [ - { - "language": "en-us", - "text": "An example asset for the test application" + ] }, { - "language": "de", - "text": "Ein Beispiel-Asset f\u00fcr eine Test-Anwendung" + "idShort": "ExampleSubmodelList2", + "typeValueListElement": "Capability", + "semanticIdListElement": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection" + } + ] + }, + "orderRelevant": true, + "category": "PARAMETER", + "description": [ + { + "language": "en-US", + "text": "Example SubmodelElementList object" + }, + { + "language": "de", + "text": "Beispiel SubmodelElementList Element" + } + ], + "modelType": "SubmodelElementList", + "semanticId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList" + } + ] + }, + "kind": "Template" } - ], - "modelType": { - "name": "Asset" - }, - "identification": { - "id": "https://acplt.org/Test_Asset_Missing", - "idType": "IRI" - }, - "administration": {}, - "kind": "Instance" + ] } ], "conceptDescriptions": [ @@ -2812,195 +3043,168 @@ "idShort": "TestConceptDescription", "description": [ { - "language": "en-us", - "text": "An example concept description for the test application" + "language": "en-US", + "text": "An example concept description for the test application" }, { "language": "de", "text": "Ein Beispiel-ConceptDescription f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "https://acplt.org/Test_ConceptDescription", - "idType": "IRI" - }, + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription", "administration": { - "version": "0.9", - "revision": "0" + "version": "9", + "revision": "0", + "creator": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_ConceptDescription" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription", + "embeddedDataSpecifications": [ + { + "dataSpecification": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0" + } + ] + }, + "dataSpecificationContent": { + "modelType": "DataSpecificationIec61360", + "preferredName": [ + { + "language": "de", + "text": "Test Specification" + }, + { + "language": "en-US", + "text": "TestSpecification" + } + ], + "dataType": "REAL_MEASURE", + "definition": [ + { + "language": "de", + "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" + }, + { + "language": "en-US", + "text": "This is a DataSpecification for testing purposes" + } + ], + "shortName": [ + { + "language": "de", + "text": "Test Spec" + }, + { + "language": "en-US", + "text": "TestSpec" + } + ], + "unit": "SpaceUnit", + "unitId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Units/SpaceUnit" + } + ] + }, + "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", + "symbol": "SU", + "valueFormat": "M", + "valueList": { + "valueReferencePairs": [ + { + "value": "exampleValue", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId" + } + ] + } + }, + { + "value": "exampleValue2", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/ValueId/ExampleValueId2" + } + ] + } + } + ] + }, + "value": "TEST", + "valueId": { + "type": "ExternalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/Values/TestValueId" + } + ] + }, + "levelType": { + "min": true, + "max": true, + "nom": false, + "typ": false + } + } + } + ] }, "isCaseOf": [ { + "type": "ExternalReference", "keys": [ { "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription", - "local": false + "value": "http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription" } ] } ] }, { - "idShort": "", - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "https://acplt.org/Test_ConceptDescription_Mandatory", - "idType": "IRI" - } + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription_Mandatory" }, { "idShort": "TestConceptDescription", "description": [ { - "language": "en-us", - "text": "An example concept description for the test application" + "language": "en-US", + "text": "An example concept description for the test application" }, { "language": "de", "text": "Ein Beispiel-ConceptDescription f\u00fcr eine Test-Anwendung" } ], - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "https://acplt.org/Test_ConceptDescription_Missing", - "idType": "IRI" - }, + "modelType": "ConceptDescription", + "id": "https://acplt.org/Test_ConceptDescription_Missing", "administration": { - "version": "0.9", + "version": "9", "revision": "0" } - }, - { - "idShort": "TestSpec_01", - "modelType": { - "name": "ConceptDescription" - }, - "identification": { - "id": "http://acplt.org/DataSpecifciations/Example/Identification", - "idType": "IRI" - }, - "administration": { - "version": "0.9", - "revision": "0" - }, - "isCaseOf": [ - { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ReferenceElements/ConceptDescriptionX", - "local": false - } - ] - } - ], - "embeddedDataSpecifications": [ - { - "dataSpecification": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0", - "local": false - } - ] - }, - "dataSpecificationContent": { - "preferredName": [ - { - "language": "de", - "text": "Test Specification" - }, - { - "language": "en-us", - "text": "TestSpecification" - } - ], - "dataType": "REAL_MEASURE", - "definition": [ - { - "language": "de", - "text": "Dies ist eine Data Specification f\u00fcr Testzwecke" - }, - { - "language": "en-us", - "text": "This is a DataSpecification for testing purposes" - } - ], - "shortName": [ - { - "language": "de", - "text": "Test Spec" - }, - { - "language": "en-us", - "text": "TestSpec" - } - ], - "unit": "SpaceUnit", - "unitId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/Units/SpaceUnit", - "local": false - } - ] - }, - "sourceOfDefinition": "http://acplt.org/DataSpec/ExampleDef", - "symbol": "SU", - "valueFormat": "string", - "valueList": { - "valueReferencePairTypes": [ - { - "value": "exampleValue2", - "valueId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId2", - "local": false - } - ] - }, - "valueType": "string" - }, - { - "value": "exampleValue", - "valueId": { - "keys": [ - { - "type": "GlobalReference", - "idType": "IRI", - "value": "http://acplt.org/ValueId/ExampleValueId", - "local": false - } - ] - }, - "valueType": "string" - } - ] - }, - "value": "TEST", - "levelType": [ - "Min", - "Max" - ] - } - } - ] } ] -} +} \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml index c99808071..061ee58b6 100644 --- a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml +++ b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml @@ -1,1684 +1,2832 @@ - + - TestAssetAdministrationShell + TestAssetAdministrationShell123 - An Example Asset Administration Shell for the test application - Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + - https://acplt.org/Test_AssetAdministrationShell123 - 0.9 + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell + + + + http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell + https://acplt.org/Test_AssetAdministrationShell + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + ModelReference - https://acplt.org/TestAssetAdministrationShell2 + + AssetAdministrationShell + https://acplt.org/TestAssetAdministrationShell2 + - - - https://acplt.org/Test_Asset - - - - + + Instance + http://acplt.org/TestAsset/ + + + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + http://acplt.org/TestAssetType/ + + file:///path/to/thumbnail.png + image/png + + + + + ModelReference + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + + + - https://acplt.org/Test_Submodel + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/Identification + - - + + + ModelReference + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + - http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + + Submodel + https://acplt.org/Test_Submodel + - - + + + ModelReference - http://acplt.org/Submodels/Assets/TestAsset/Identification + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + - - - - - TestConceptDictionary - - An example concept dictionary for the test application - Ein Beispiel-ConceptDictionary für eine Test-Anwendung - - - - - https://acplt.org/Test_ConceptDescription - - - - - + + - - https://acplt.org/Test_AssetAdministrationShell_Mandatory - - - https://acplt.org/Test_Asset_Mandatory - - - - + https://acplt.org/Test_AssetAdministrationShell_Mandatory + + Instance + http://acplt.org/Test_Asset_Mandatory/ + + + + ModelReference - https://acplt.org/Test_Submodel2_Mandatory + + Submodel + https://acplt.org/Test_Submodel2_Mandatory + - - + + + ModelReference - https://acplt.org/Test_Submodel_Mandatory + + Submodel + https://acplt.org/Test_Submodel_Mandatory + - - - - - TestConceptDictionary - - - + + - - https://acplt.org/Test_AssetAdministrationShell2_Mandatory - - - https://acplt.org/Test_Asset_Mandatory - - + https://acplt.org/Test_AssetAdministrationShell2_Mandatory + + Instance + http://acplt.org/TestAsset2_Mandatory/ + TestAssetAdministrationShell - An Example Asset Administration Shell for the test application - Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + - https://acplt.org/Test_AssetAdministrationShell_Missing - 0.9 + 9 0 - - - https://acplt.org/Test_Asset_Missing - - - - - - https://acplt.org/Test_Submodel_Missing - - - - - - ExampleView - - - - https://acplt.org/Test_Submodel_Missing - - - - - - ExampleView2 - - - - - - TestConceptDictionary - - An example concept dictionary for the test application - Ein Beispiel-ConceptDictionary für eine Test-Anwendung - - - + https://acplt.org/Test_AssetAdministrationShell_Missing + + Instance + http://acplt.org/Test_Asset_Missing/ + + + TestKey + TestValue + + ExternalReference - https://acplt.org/Test_ConceptDescription_Missing + + GlobalReference + http://acplt.org/SpecificAssetId/ + - - - - + + + + + file:///TestFile.pdf + application/pdf + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Missing + + + + - - - Test_Asset - - An example asset for the test application - Ein Beispiel-Asset für eine Test-Anwendung - - https://acplt.org/Test_Asset - - 0.9 - 0 - - - - http://acplt.org/Submodels/Assets/TestAsset/Identification - - - - - http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial - - - Instance - - - - https://acplt.org/Test_Asset_Mandatory - Instance - - - Test_Asset - - An example asset for the test application - Ein Beispiel-Asset für eine Test-Anwendung - - https://acplt.org/Test_Asset_Missing - - Instance - - Identification - An example asset identification submodel for the test application - Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + + en-US + An example asset identification submodel for the test application + + + de + Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + - http://acplt.org/Submodels/Assets/TestAsset/Identification - 0.9 + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/TestAsset/Identification + + + + http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification + http://acplt.org/Submodels/Assets/TestAsset/Identification Instance + ModelReference - http://acplt.org/SubmodelTemplates/AssetIdentification + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + - - - ManufacturerName - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - 0173-1#02-AAO677#002 - - - - - http://acplt.org/Qualifier/ExampleQualifier - int - + + + + ExampleExtension + xs:string + ExampleExtensionValue + + + ModelReference - http://acplt.org/ValueId/ExampleValueId + + AssetAdministrationShell + http://acplt.org/RefersTo/ExampleRefersTo + - - 100 - + + + + + PARAMETER + ManufacturerName + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + 0173-1#02-AAO677#002 + + + + + + ConceptQualifier + http://acplt.org/Qualifier/ExampleQualifier + xs:int + 100 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + - - http://acplt.org/Qualifier/ExampleQualifier2 - int - - - http://acplt.org/ValueId/ExampleValueId - - - 50 - + TemplateQualifier + http://acplt.org/Qualifier/ExampleQualifier2 + xs:int + 50 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + - string - ACPLT - - - http://acplt.org/ValueId/ExampleValueId - - - - - - - InstanceId - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber - - - string - 978-8234-234-342 - - - http://acplt.org/ValueId/ExampleValueId - - - - + + xs:string + ACPLT + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + PARAMETER + InstanceId + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + ValueQualifier + http://acplt.org/Qualifier/ExampleQualifier3 + xs:dateTime + 2023-04-07T16:59:54.870123 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + xs:string + 978-8234-234-342 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + BillOfMaterial - An example bill of material submodel for the test application - Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + + en-US + An example bill of material submodel for the test application + + + de + Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + - http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial - 0.9 + 9 + http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial Instance + ModelReference - http://acplt.org/SubmodelTemplates/BillOfMaterial + + Submodel + http://acplt.org/SubmodelTemplates/BillOfMaterial + - - - ExampleEntity - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber - - - - - - ExampleProperty2 - CONSTANT - - Example Property object - Beispiel Property Element - - Instance - - - http://acplt.org/Properties/ExampleProperty - - - string - exampleValue2 - - - http://acplt.org/ValueId/ExampleValueId - - - - - - - ExampleProperty - CONSTANT - - Example Property object - Beispiel Property Element - - Instance - - - http://acplt.org/Properties/ExampleProperty - - - - - - - - - - - http://acplt.org/ValueId/ExampleValueId - - - - - - string - exampleValue - - - http://acplt.org/ValueId/ExampleValueId - - - - - - CoManagedEntity - - - - - ExampleEntity2 - - Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. - Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist - - Instance - - - http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber - - - - SelfManagedEntity - - - https://acplt.org/Test_Asset2 - - - - + + PARAMETER + ExampleEntity + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + CONSTANT + ExampleProperty2 + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + SelfManagedEntity + http://acplt.org/TestAsset/ + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + + PARAMETER + ExampleEntity2 + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + CoManagedEntity + TestSubmodel - An example submodel for the test application - Ein Beispiel-Teilmodell für eine Test-Anwendung + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + - https://acplt.org/Test_Submodel - 0.9 + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_Submodel + + + + https://acplt.org/Test_Submodel Instance + ExternalReference - http://acplt.org/SubmodelTemplates/ExampleSubmodel + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + - - - ExampleRelationshipElement - PARAMETER - - Example RelationshipElement object - Beispiel RelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty2 - - - - - - - ExampleAnnotatedRelationshipElement - PARAMETER - - Example AnnotatedRelationshipElement object - Beispiel AnnotatedRelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty2 - - - - - - ExampleAnnotatedProperty - Instance - string - exampleValue - - - - - ExampleAnnotatedRange - Instance - integer - 1 - 5 - - - - - - - - ExampleOperation - PARAMETER - - Example Operation object - Beispiel Operation Element - - Instance - - - http://acplt.org/Operations/ExampleOperation - - - + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ModelReference + + + ConceptDescription + https://acplt.org/Test_ConceptDescription + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + - ExampleProperty CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + - string + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - + + + + - ExampleProperty CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + - string + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - + + + + - ExampleProperty CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + - string + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - - - ExampleCapability - PARAMETER - - Example Capability object - Beispiel Capability Element - - Instance - - - http://acplt.org/Capabilities/ExampleCapability - - - - - - - ExampleBasicEvent - PARAMETER - - Example BasicEvent object - Beispiel BasicEvent Element - - Instance - - - http://acplt.org/Events/ExampleBasicEvent - - - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - PARAMETER - - Example SubmodelElementCollectionOrdered object - Beispiel SubmodelElementCollectionOrdered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered - - - - + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleFileURI + + + en-US + Details of the Asset Administration Shell — An example for an external file reference + + + de + Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5 + application/pdf + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + Property + xs:string + - ExampleProperty CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExampleProperty + - string + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId1 + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId2 + + + + + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + xs:string exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - ExampleMultiLanguageProperty + CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example MultiLanguageProperty object - Beispiel MulitLanguageProperty Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty2/SupplementalId + + + + + xs:string + exampleValue + ExternalReference - http://acplt.org/ValueId/ExampleMultiLanguageValueId + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - Example value of a MultiLanguageProperty element - Beispielswert für ein MulitLanguageProperty-Element - - - - - - ExampleRange - PARAMETER - - Example Range object - Beispiel Range Element - - Instance - - - http://acplt.org/Ranges/ExampleRange - - - int - 0 - 100 - - - - true - false - - - - - ExampleSubmodelCollectionUnordered - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - + + + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MultiLanguageProperty Element + + + + ExternalReference + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/Referred + + + + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleMultiLanguageValueId + + + + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + + + + + https://acplt.org/Test_Submodel_Mandatory + Instance + + + ExampleRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleAnnotatedRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleOperation + + + ExampleCapability + + + ExampleBasicEventElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + input + off + + + ExampleSubmodelList + SubmodelElementCollection + + + ExampleBlob - PARAMETER - - Example Blob object - Beispiel Blob Element - - Instance - - - http://acplt.org/Blobs/ExampleBlob - - - AQIDBAU= - application/pdf + + application/pdf - - ExampleFile - PARAMETER - - Example File object - Beispiel File Element - - Instance - - - http://acplt.org/Files/ExampleFile - - - application/pdf - /TestFile.pdf - - - - - ExampleFileURI - CONSTANT - - Details of the Asset Administration Shell—An example for an external file reference - Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei - - Instance - - - http://acplt.org/Files/ExampleFile - - - application/pdf - https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5 + application/pdf - - - - ExampleReferenceElement + PARAMETER - - Example Reference Element object - Beispiel Reference Element Element - - Instance - - - http://acplt.org/ReferenceElements/ExampleReferenceElement - - - - - ExampleProperty - - - - - - false - false - - - - - - - https://acplt.org/Test_Submodel_Mandatory - Instance - - - - ExampleRelationshipElement - Instance - - - ExampleProperty - - - - - ExampleProperty - - - - - - - ExampleAnnotatedRelationshipElement - Instance - - - ExampleProperty - - - - - ExampleProperty - - - - - - - - ExampleOperation - Instance - - - - - ExampleCapability - Instance - - - - - ExampleBasicEvent - Instance - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - Instance - - + ExampleMultiLanguageProperty + + PARAMETER ExampleProperty - Instance - string + xs:string - - - - ExampleMultiLanguageProperty - Instance - - - + PARAMETER ExampleRange - Instance - int + xs:int - - - true - false - - - - - ExampleSubmodelCollectionUnordered - Instance - - - - ExampleBlob - Instance - - application/pdf - - - - - ExampleFile - Instance - application/pdf - - - + PARAMETER ExampleReferenceElement - Instance - - - false - false - - - - - ExampleSubmodelCollectionUnordered2 - Instance - - false - false - - + + + + + + + + ExampleSubmodelList2 + Capability + - - https://acplt.org/Test_Submodel2_Mandatory + https://acplt.org/Test_Submodel2_Mandatory Instance - TestSubmodel - An example submodel for the test application - Ein Beispiel-Teilmodell für eine Test-Anwendung + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + - https://acplt.org/Test_Submodel_Missing - 0.9 + 9 0 + https://acplt.org/Test_Submodel_Missing Instance + ExternalReference - http://acplt.org/SubmodelTemplates/ExampleSubmodel + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + - - - ExampleRelationshipElement - PARAMETER - - Example RelationshipElement object - Beispiel RelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - - ExampleAnnotatedRelationshipElement - PARAMETER - - Example AnnotatedRelationshipElement object - Beispiel AnnotatedRelationshipElement Element - - Instance - - - http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - ExampleAnnotatedRange - Instance - integer - 1 - 5 - - - - - ExampleAnnotatedProperty - Instance - string - exampleValue - - - - - - - - ExampleOperation - PARAMETER - - Example Operation object - Beispiel Operation Element - - Instance - - - http://acplt.org/Operations/ExampleOperation - - - + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + - ExampleProperty CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string + xs:string exampleValue - - - - - - - ExampleProperty - CONSTANT - - Example Property object - Beispiel Property Element - - Instance - + + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string - exampleValue + - - + + + + - ExampleProperty CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string + xs:string exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + - - - - - - ExampleCapability - PARAMETER - - Example Capability object - Beispiel Capability Element - - Instance - - - http://acplt.org/Capabilities/ExampleCapability - - - - - - - ExampleBasicEvent - PARAMETER - - Example BasicEvent object - Beispiel BasicEvent Element - - Instance - - - http://acplt.org/Events/ExampleBasicEvent - - - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - PARAMETER - - Example SubmodelElementCollectionOrdered object - Beispiel SubmodelElementCollectionOrdered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered - - - - + + + + + - ExampleProperty CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Instance + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + - - - http://acplt.org/Qualifier/ExampleQualifier - string - - - string + xs:string exampleValue - - - - - ExampleMultiLanguageProperty - CONSTANT - - Example MultiLanguageProperty object - Beispiel MulitLanguageProperty Element - - Instance - - - http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty - - - - Example value of a MultiLanguageProperty element - Beispielswert für ein MulitLanguageProperty-Element - - - - - - ExampleRange - PARAMETER - - Example Range object - Beispiel Range Element - - Instance - - - http://acplt.org/Ranges/ExampleRange - - - int - 0 - 100 - - - - true - false - - - - - ExampleSubmodelCollectionUnordered - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Instance - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - - - ExampleBlob - PARAMETER - - Example Blob object - Beispiel Blob Element - - Instance - - - http://acplt.org/Blobs/ExampleBlob - - - AQIDBAU= - application/pdf - - - - - ExampleFile - PARAMETER - - Example File object - Beispiel File Element - - Instance - - - http://acplt.org/Files/ExampleFile - - - application/pdf - /TestFile.pdf - - - - - ExampleReferenceElement - PARAMETER - - Example Reference Element object - Beispiel Reference Element Element - - Instance - - - http://acplt.org/ReferenceElements/ExampleReferenceElement - - - + + ExternalReference - ExampleProperty + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + - - - - - false - false - - + + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + http://acplt.org/Qualifier/ExampleQualifier + xs:string + + + xs:string + exampleValue + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + TestSubmodel - An example submodel for the test application - Ein Beispiel-Teilmodell für eine Test-Anwendung + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + - https://acplt.org/Test_Submodel_Template - 0.9 + 9 0 + https://acplt.org/Test_Submodel_Template Template + ExternalReference - http://acplt.org/SubmodelTemplates/ExampleSubmodel + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + - - - ExampleRelationshipElement - PARAMETER - - Example RelationshipElement object - Beispiel RelationshipElement Element - - Template - - - http://acplt.org/RelationshipElements/ExampleRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - - ExampleAnnotatedRelationshipElement - PARAMETER - - Example AnnotatedRelationshipElement object - Beispiel AnnotatedRelationshipElement Element - - Template - - - http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement - - - - - ExampleProperty - - - - - ExampleProperty - - - - - - - - ExampleOperation - PARAMETER - - Example Operation object - Beispiel Operation Element - - Template - - - http://acplt.org/Operations/ExampleOperation - - - + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + - ExampleProperty CONSTANT + ExamplePropertyInput - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + - string + xs:string - - + + + + - ExampleProperty CONSTANT + ExamplePropertyOutput - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + - string + xs:string - - + + + + - ExampleProperty CONSTANT + ExamplePropertyInOutput - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + - string + xs:string - - - - - - ExampleCapability - PARAMETER - - Example Capability object - Beispiel Capability Element - - Template - - - http://acplt.org/Capabilities/ExampleCapability - - - - - - - ExampleBasicEvent - PARAMETER - - Example BasicEvent object - Beispiel BasicEvent Element - - Template - - - http://acplt.org/Events/ExampleBasicEvent - - - - - ExampleProperty - - - - - - - ExampleSubmodelCollectionOrdered - PARAMETER - - Example SubmodelElementCollectionOrdered object - Beispiel SubmodelElementCollectionOrdered Element - - Template - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered - - - - + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + SubmodelElementCollection + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + - ExampleProperty CONSTANT + ExampleProperty - Example Property object - Beispiel Property Element + + en-US + Example Property object + + + de + Beispiel Property Element + - Template + ExternalReference - http://acplt.org/Properties/ExampleProperty + + GlobalReference + http://acplt.org/Properties/ExampleProperty + - string + xs:string - - - ExampleMultiLanguageProperty CONSTANT + ExampleMultiLanguageProperty - Example MultiLanguageProperty object - Beispiel MulitLanguageProperty Element + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + - Template + ExternalReference - http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + - - - ExampleRange PARAMETER + ExampleRange - Example Range object - Beispiel Range Element + + en-US + Example Range object + + + de + Beispiel Range Element + - Template + ExternalReference - http://acplt.org/Ranges/ExampleRange + + GlobalReference + http://acplt.org/Ranges/ExampleRange + - int + xs:int 100 - - - ExampleRange2 PARAMETER + ExampleRange2 - Example Range object - Beispiel Range Element + + en-US + Example Range object + + + de + Beispiel Range Element + - Template + ExternalReference - http://acplt.org/Ranges/ExampleRange + + GlobalReference + http://acplt.org/Ranges/ExampleRange + - int + xs:int 0 - - - true - false - - - - - ExampleSubmodelCollectionUnordered - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Template - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - - ExampleBlob PARAMETER + ExampleBlob - Example Blob object - Beispiel Blob Element + + en-US + Example Blob object + + + de + Beispiel Blob Element + - Template + ExternalReference - http://acplt.org/Blobs/ExampleBlob + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + - application/pdf + application/pdf - - - ExampleFile PARAMETER + ExampleFile - Example File object - Beispiel File Element + + en-US + Example File object + + + de + Beispiel File Element + - Template + ExternalReference - http://acplt.org/Files/ExampleFile + + GlobalReference + http://acplt.org/Files/ExampleFile + - application/pdf + application/pdf - - - ExampleReferenceElement PARAMETER + ExampleReferenceElement - Example Reference Element object - Beispiel Reference Element Element + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + - Template + ExternalReference - http://acplt.org/ReferenceElements/ExampleReferenceElement + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + - - - false - false - - - - - ExampleSubmodelCollectionUnordered2 - PARAMETER - - Example SubmodelElementCollectionUnordered object - Beispiel SubmodelElementCollectionUnordered Element - - Template - - - http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered - - - - false - false - - + + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + + + PARAMETER + ExampleSubmodelList2 + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + Capability + @@ -1686,102 +2834,158 @@ TestConceptDescription - An example concept description for the test application - Ein Beispiel-ConceptDescription für eine Test-Anwendung + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + - https://acplt.org/Test_ConceptDescription - 0.9 + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + 9 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_ConceptDescription + + + + http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription + https://acplt.org/Test_ConceptDescription - - http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription - + + ExternalReference + + + GlobalReference + http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription + + + - - https://acplt.org/Test_ConceptDescription_Mandatory + https://acplt.org/Test_ConceptDescription_Mandatory TestConceptDescription - An example concept description for the test application - Ein Beispiel-ConceptDescription für eine Test-Anwendung + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + - https://acplt.org/Test_ConceptDescription_Missing - 0.9 + 9 0 - - - TestSpec_01 - http://acplt.org/DataSpecifciations/Example/Identification - - 0.9 - 0 - - - - - - Test Specification - TestSpecification - - - Test Spec - TestSpec - - SpaceUnit - - - http://acplt.org/Units/SpaceUnit - - - http://acplt.org/DataSpec/ExampleDef - SU - REAL_MEASURE - - Dies ist eine Data Specification für Testzwecke - This is a DataSpecification for testing purposes - - string - - - - - http://acplt.org/ValueId/ExampleValueId - - - exampleValue - - - - - http://acplt.org/ValueId/ExampleValueId2 - - - exampleValue2 - - - TEST - Max - Min - - - - - http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0 - - - - - - http://acplt.org/ReferenceElements/ConceptDescriptionX - - + https://acplt.org/Test_ConceptDescription_Missing - \ No newline at end of file + diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/TestFile.pdf b/test/compliance_tool/files/test_demo_full_example_xml_aasx/TestFile.pdf new file mode 100644 index 000000000..2bccbec5f Binary files /dev/null and b/test/compliance_tool/files/test_demo_full_example_xml_aasx/TestFile.pdf differ diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/[Content_Types].xml b/test/compliance_tool/files/test_demo_full_example_xml_aasx/[Content_Types].xml new file mode 100644 index 000000000..efab09eb1 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_aasx/[Content_Types].xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/_rels/.rels b/test/compliance_tool/files/test_demo_full_example_xml_aasx/_rels/.rels new file mode 100644 index 000000000..9758543f3 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_aasx/_rels/.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/_rels/aasx-origin.rels b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/_rels/aasx-origin.rels new file mode 100644 index 000000000..fc764b657 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/_rels/aasx-origin.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/_rels/data.xml.rels b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/_rels/data.xml.rels new file mode 100644 index 000000000..43350edd0 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/_rels/data.xml.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/aasx-origin b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/aasx-origin new file mode 100644 index 000000000..e69de29bb diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/data.xml b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/data.xml new file mode 100644 index 000000000..c0eb40769 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_aasx/aasx/data.xml @@ -0,0 +1,2999 @@ + + + + + TestAssetAdministrationShell + + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell + + + + http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell + + https://acplt.org/Test_AssetAdministrationShell + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + + ModelReference + + + AssetAdministrationShell + https://acplt.org/TestAssetAdministrationShell2 + + + + + Instance + http://acplt.org/TestAsset/ + + + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + file:///path/to/thumbnail.png + image/png + + + + + ModelReference + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + + + + + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/Identification + + + + + ModelReference + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + Submodel + https://acplt.org/Test_Submodel + + + + + ModelReference + + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Template + + + + + + + https://acplt.org/Test_AssetAdministrationShell_Mandatory + + Instance + http://acplt.org/Test_Asset_Mandatory/ + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel2_Mandatory + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Mandatory + + + + + + + https://acplt.org/Test_AssetAdministrationShell2_Mandatory + + Instance + http://acplt.org/TestAsset2_Mandatory/ + + + + TestAssetAdministrationShell + + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_AssetAdministrationShell_Missing + + Instance + http://acplt.org/Test_Asset_Missing/ + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + file:///TestFile.pdf + application/pdf + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Missing + + + + + + + + + Identification + + + en-US + An example asset identification submodel for the test application + + + de + Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/TestAsset/Identification + + + + http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification + + http://acplt.org/Submodels/Assets/TestAsset/Identification + Instance + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + + + + + + + + ExampleExtension + xs:string + ExampleExtensionValue + + + ModelReference + + + AssetAdministrationShell + http://acplt.org/RefersTo/ExampleRefersTo + + + + + + + PARAMETER + ManufacturerName + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + 0173-1#02-AAO677#002 + + + + + + ConceptQualifier + http://acplt.org/Qualifier/ExampleQualifier + xs:int + 100 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + TemplateQualifier + http://acplt.org/Qualifier/ExampleQualifier2 + xs:int + 50 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + xs:string + ACPLT + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + PARAMETER + InstanceId + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + ValueQualifier + http://acplt.org/Qualifier/ExampleQualifier3 + xs:dateTime + 2023-04-07T16:59:54.870123 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + xs:string + 978-8234-234-342 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + BillOfMaterial + + + en-US + An example bill of material submodel for the test application + + + de + Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + + + + 9 + http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial + + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + Instance + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/BillOfMaterial + + + + + + PARAMETER + ExampleEntity + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + CONSTANT + ExampleProperty2 + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + SelfManagedEntity + http://acplt.org/TestAsset/ + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + + PARAMETER + ExampleEntity2 + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + CoManagedEntity + + + + + TestSubmodel + + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_Submodel + + + + + https://acplt.org/Test_Submodel + Instance + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ModelReference + + + ConceptDescription + https://acplt.org/Test_ConceptDescription + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + + + + CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleFileURI + + + en-US + Details of the Asset Administration Shell — An example for an external file reference + + + de + Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5 + application/pdf + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + Property + xs:string + + + CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId1 + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId2 + + + + + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty2/SupplementalId + + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MultiLanguageProperty Element + + + + ExternalReference + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/Referred + + + + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleMultiLanguageValueId + + + + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + + + + + https://acplt.org/Test_Submodel_Mandatory + Instance + + + ExampleRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleAnnotatedRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleOperation + + + ExampleCapability + + + ExampleBasicEventElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + input + off + + + ExampleSubmodelList + SubmodelElementCollection + + + + + ExampleBlob + + application/pdf + + + ExampleFile + application/pdf + + + PARAMETER + ExampleMultiLanguageProperty + + + PARAMETER + ExampleProperty + xs:string + + + PARAMETER + ExampleRange + xs:int + + + PARAMETER + ExampleReferenceElement + + + + + + + + + ExampleSubmodelList2 + Capability + + + + + https://acplt.org/Test_Submodel2_Mandatory + Instance + + + TestSubmodel + + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_Submodel_Missing + Instance + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + + + + CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + http://acplt.org/Qualifier/ExampleQualifier + xs:string + + + xs:string + exampleValue + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + + + + + TestSubmodel + + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_Submodel_Template + Template + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + + + + CONSTANT + ExamplePropertyInput + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + + + + xs:string + + + + + + + + + CONSTANT + ExamplePropertyOutput + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + + + + xs:string + + + + + + + + + CONSTANT + ExamplePropertyInOutput + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + + + + xs:string + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + SubmodelElementCollection + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 100 + + + PARAMETER + ExampleRange2 + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + application/pdf + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + + + PARAMETER + ExampleSubmodelList2 + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + Capability + + + + + + + TestConceptDescription + + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + + + + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_ConceptDescription + + + + http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription + + https://acplt.org/Test_ConceptDescription + + + ExternalReference + + + GlobalReference + http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription + + + + + + + https://acplt.org/Test_ConceptDescription_Mandatory + + + TestConceptDescription + + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_ConceptDescription_Missing + + + diff --git a/test/compliance_tool/files/test_demo_full_example_xml_aasx/docProps/core.xml b/test/compliance_tool/files/test_demo_full_example_xml_aasx/docProps/core.xml new file mode 100644 index 000000000..5f0e65331 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_aasx/docProps/core.xml @@ -0,0 +1 @@ +2020-01-01T00:00:00Eclipse BaSyx Python Testing FrameworkTest_DescriptionEclipse BaSyx Python Testing Framework Compliance Tool2020-01-01T00:00:011.0Test Title2.0.1 \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/TestFile.pdf b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/TestFile.pdf new file mode 100644 index 000000000..2bccbec5f Binary files /dev/null and b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/TestFile.pdf differ diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/[Content_Types].xml b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/[Content_Types].xml new file mode 100644 index 000000000..efab09eb1 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/[Content_Types].xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/_rels/.rels b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/_rels/.rels new file mode 100644 index 000000000..9758543f3 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/_rels/.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/_rels/aasx-origin.rels b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/_rels/aasx-origin.rels new file mode 100644 index 000000000..fc764b657 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/_rels/aasx-origin.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/_rels/data.xml.rels b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/_rels/data.xml.rels new file mode 100644 index 000000000..43350edd0 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/_rels/data.xml.rels @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/aasx-origin b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/aasx-origin new file mode 100644 index 000000000..e69de29bb diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml new file mode 100644 index 000000000..5e952db2f --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml @@ -0,0 +1,2999 @@ + + + + + TestAssetAdministrationShell123 + + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell + + + + http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell + + https://acplt.org/Test_AssetAdministrationShell + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + + ModelReference + + + AssetAdministrationShell + https://acplt.org/TestAssetAdministrationShell2 + + + + + Instance + http://acplt.org/TestAsset/ + + + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + file:///path/to/thumbnail.png + image/png + + + + + ModelReference + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + + + + + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/Identification + + + + + ModelReference + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + Submodel + https://acplt.org/Test_Submodel + + + + + ModelReference + + + Submodel + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Template + + + + + + + https://acplt.org/Test_AssetAdministrationShell_Mandatory + + Instance + http://acplt.org/Test_Asset_Mandatory/ + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel2_Mandatory + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Mandatory + + + + + + + https://acplt.org/Test_AssetAdministrationShell2_Mandatory + + Instance + http://acplt.org/TestAsset2_Mandatory/ + + + + TestAssetAdministrationShell + + + en-US + An Example Asset Administration Shell for the test application + + + de + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_AssetAdministrationShell_Missing + + Instance + http://acplt.org/Test_Asset_Missing/ + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + file:///TestFile.pdf + application/pdf + + + + + ModelReference + + + Submodel + https://acplt.org/Test_Submodel_Missing + + + + + + + + + Identification + + + en-US + An example asset identification submodel for the test application + + + de + Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/TestAsset/Identification + + + + http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification + + http://acplt.org/Submodels/Assets/TestAsset/Identification + Instance + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/AssetIdentification + + + + + + + + ExampleExtension + xs:string + ExampleExtensionValue + + + ModelReference + + + AssetAdministrationShell + http://acplt.org/RefersTo/ExampleRefersTo + + + + + + + PARAMETER + ManufacturerName + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + 0173-1#02-AAO677#002 + + + + + + ConceptQualifier + http://acplt.org/Qualifier/ExampleQualifier + xs:int + 100 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + TemplateQualifier + http://acplt.org/Qualifier/ExampleQualifier2 + xs:int + 50 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + xs:string + ACPLT + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + PARAMETER + InstanceId + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + ValueQualifier + http://acplt.org/Qualifier/ExampleQualifier3 + xs:dateTime + 2023-04-07T16:59:54.870123 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + xs:string + 978-8234-234-342 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + BillOfMaterial + + + en-US + An example bill of material submodel for the test application + + + de + Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + + + + 9 + http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial + + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + Instance + + ModelReference + + + Submodel + http://acplt.org/SubmodelTemplates/BillOfMaterial + + + + + + PARAMETER + ExampleEntity + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + CONSTANT + ExampleProperty2 + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + SelfManagedEntity + http://acplt.org/TestAsset/ + + + TestKey + TestValue + + ExternalReference + + + GlobalReference + http://acplt.org/SpecificAssetId/ + + + + + + + + PARAMETER + ExampleEntity2 + + + en-US + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + de + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ExternalReference + + + GlobalReference + http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + CoManagedEntity + + + + + TestSubmodel + + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_Submodel + + + + + https://acplt.org/Test_Submodel + Instance + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ModelReference + + + ConceptDescription + https://acplt.org/Test_ConceptDescription + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty2 + + + + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + + + + CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleFileURI + + + en-US + Details of the Asset Administration Shell — An example for an external file reference + + + de + Details of the Asset Administration Shell – Ein Beispiel für eine extern referenzierte Datei + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-Administration-Shell-Part1.pdf?__blob=publicationFile&v=5 + application/pdf + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + Property + xs:string + + + CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId1 + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/SupplementalId2 + + + + + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + CONSTANT + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty2/SupplementalId + + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MultiLanguageProperty Element + + + + ExternalReference + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty/Referred + + + + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleMultiLanguageValueId + + + + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + + + + + https://acplt.org/Test_Submodel_Mandatory + Instance + + + ExampleRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleAnnotatedRelationshipElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + ExampleOperation + + + ExampleCapability + + + ExampleBasicEventElement + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + input + off + + + ExampleSubmodelList + SubmodelElementCollection + + + + + ExampleBlob + + application/pdf + + + ExampleFile + application/pdf + + + PARAMETER + ExampleMultiLanguageProperty + + + PARAMETER + ExampleProperty + xs:string + + + PARAMETER + ExampleRange + xs:int + + + PARAMETER + ExampleReferenceElement + + + + + + + + + ExampleSubmodelList2 + Capability + + + + + https://acplt.org/Test_Submodel2_Mandatory + Instance + + + TestSubmodel + + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_Submodel_Missing + Instance + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRange + xs:integer + 1 + 5 + + + PARAMETER + ExampleAnnotatedProperty + xs:string + exampleValue + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + + + + CONSTANT + ExamplePropertyInput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + + + CONSTANT + ExamplePropertyInOutput + + + en-US + ExampleProperty + + + de + BeispielProperty + + + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + + + + xs:string + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelCollection + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + application/pdf + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + en-US + Example value of a MultiLanguageProperty element + + + de + Beispielswert für ein MulitLanguageProperty-Element + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + + + http://acplt.org/Qualifier/ExampleQualifier + xs:string + + + xs:string + exampleValue + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + 100 + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + + + + + TestSubmodel + + + en-US + An example submodel for the test application + + + de + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_Submodel_Template + Template + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + + PARAMETER + ExampleRelationshipElement + + + en-US + Example RelationshipElement object + + + de + Beispiel RelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleAnnotatedRelationshipElement + + + en-US + Example AnnotatedRelationshipElement object + + + de + Beispiel AnnotatedRelationshipElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + + + PARAMETER + ExampleOperation + + + en-US + Example Operation object + + + de + Beispiel Operation Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Operations/ExampleOperation + + + + + + + + CONSTANT + ExamplePropertyInput + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInput + + + + xs:string + + + + + + + + + CONSTANT + ExamplePropertyOutput + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyOutput + + + + xs:string + + + + + + + + + CONSTANT + ExamplePropertyInOutput + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExamplePropertyInOutput + + + + xs:string + + + + + + + PARAMETER + ExampleCapability + + + en-US + Example Capability object + + + de + Beispiel Capability Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Capabilities/ExampleCapability + + + + + + PARAMETER + ExampleBasicEventElement + + + en-US + Example BasicEventElement object + + + de + Beispiel BasicEventElement Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Events/ExampleBasicEventElement + + + + + ModelReference + + + Submodel + http://acplt.org/Test_Submodel + + + Property + ExampleProperty + + + + output + on + ExampleTopic + + ModelReference + + + Submodel + http://acplt.org/ExampleMessageBroker + + + + 2022-11-12T23:50:23.123456+00:00 + PT0.000001S + P1Y2M3DT4H5M6.123456S + + + PARAMETER + ExampleSubmodelList + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + SubmodelElementCollection + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + CONSTANT + ExampleProperty + + + en-US + Example Property object + + + de + Beispiel Property Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Properties/ExampleProperty + + + + xs:string + + + CONSTANT + ExampleMultiLanguageProperty + + + en-US + Example MultiLanguageProperty object + + + de + Beispiel MulitLanguageProperty Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + PARAMETER + ExampleRange + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 100 + + + PARAMETER + ExampleRange2 + + + en-US + Example Range object + + + de + Beispiel Range Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Ranges/ExampleRange + + + + xs:int + 0 + + + PARAMETER + ExampleBlob + + + en-US + Example Blob object + + + de + Beispiel Blob Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Blobs/ExampleBlob + + + + + application/pdf + + + PARAMETER + ExampleFile + + + en-US + Example File object + + + de + Beispiel File Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/Files/ExampleFile + + + + application/pdf + + + PARAMETER + ExampleReferenceElement + + + en-US + Example Reference Element object + + + de + Beispiel Reference Element Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + + + + PARAMETER + + + en-US + Example SubmodelElementCollection object + + + de + Beispiel SubmodelElementCollection Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + + + + + PARAMETER + ExampleSubmodelList2 + + + en-US + Example SubmodelElementList object + + + de + Beispiel SubmodelElementList Element + + + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementLists/ExampleSubmodelElementList + + + + true + + ExternalReference + + + GlobalReference + http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollection + + + + Capability + + + + + + + TestConceptDescription + + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + + + + + + + ExternalReference + + + GlobalReference + https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0 + + + + + + + + de + Test Specification + + + en-US + TestSpecification + + + + + de + Test Spec + + + en-US + TestSpec + + + SpaceUnit + + ExternalReference + + + GlobalReference + http://acplt.org/Units/SpaceUnit + + + + http://acplt.org/DataSpec/ExampleDef + SU + REAL_MEASURE + + + de + Dies ist eine Data Specification für Testzwecke + + + en-US + This is a DataSpecification for testing purposes + + + M + + + + exampleValue + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId + + + + + + exampleValue2 + + ExternalReference + + + GlobalReference + http://acplt.org/ValueId/ExampleValueId2 + + + + + + + TEST + + true + false + false + true + + + + + + 9 + 0 + + ExternalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_ConceptDescription + + + + http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription + + https://acplt.org/Test_ConceptDescription + + + ExternalReference + + + GlobalReference + http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription + + + + + + + https://acplt.org/Test_ConceptDescription_Mandatory + + + TestConceptDescription + + + en-US + An example concept description for the test application + + + de + Ein Beispiel-ConceptDescription für eine Test-Anwendung + + + + 9 + 0 + + https://acplt.org/Test_ConceptDescription_Missing + + + diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/docProps/core.xml b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/docProps/core.xml new file mode 100644 index 000000000..4dc0b87c5 --- /dev/null +++ b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute_aasx/docProps/core.xml @@ -0,0 +1 @@ +2020-01-01T00:00:00PyI40AAS Testing FrameworkTest_DescriptionPyI40AAS Testing Framework Compliance Tool2020-01-01T00:00:011.0Test Title2.0.1 \ No newline at end of file diff --git a/test/compliance_tool/files/test_deserializable_aas_warning.json b/test/compliance_tool/files/test_deserializable_aas_warning.json index 448bccdc9..35da52c24 100644 --- a/test/compliance_tool/files/test_deserializable_aas_warning.json +++ b/test/compliance_tool/files/test_deserializable_aas_warning.json @@ -1,6 +1,16 @@ { - "assetAdministrationShells":[{"identification":{"id":"https://acplt.org/Test_AssetAdministrationShell","idType":"IRI"},"idShort":"TestAssetAdministrationShell","administration":{"revision":"0"}, "modelType":{"name":"AssetAdministrationShell"},"asset":{"keys":[{"idType":"IRI","local":false,"type":"Asset","value":"https://acplt.org/Test_Asset"}]}}], - "assets": [], - "submodels": [], - "conceptDescriptions": [] + "assetAdministrationShells": [ + { + "id": "https://acplt.org/Test_AssetAdministrationShell", + "idShort": "TestAssetAdministrationShell", + "administration": { + "revision": "0" + }, + "modelType": "AssetAdministrationShell", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/TestAsset/" + } + } + ] } \ No newline at end of file diff --git a/test/compliance_tool/files/test_deserializable_aas_warning.xml b/test/compliance_tool/files/test_deserializable_aas_warning.xml index dd4633477..53f72ab71 100644 --- a/test/compliance_tool/files/test_deserializable_aas_warning.xml +++ b/test/compliance_tool/files/test_deserializable_aas_warning.xml @@ -1,2 +1,16 @@ -TestAssetAdministrationShellhttps://acplt.org/Test_AssetAdministrationShell0https://acplt.org/Test_Asset \ No newline at end of file + + + + TestAssetAdministrationShell + + 0 + + https://acplt.org/Test_AssetAdministrationShell + + Instance + http://acplt.org/TestAsset/ + + + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_empty.aasx b/test/compliance_tool/files/test_empty.aasx deleted file mode 100644 index e6de973a0..000000000 Binary files a/test/compliance_tool/files/test_empty.aasx and /dev/null differ diff --git a/test/compliance_tool/files/test_empty.json b/test/compliance_tool/files/test_empty.json index 698e12f63..9e26dfeeb 100644 --- a/test/compliance_tool/files/test_empty.json +++ b/test/compliance_tool/files/test_empty.json @@ -1,6 +1 @@ -{ - "assetAdministrationShells": [], - "assets": [], - "submodels": [], - "conceptDescriptions": [] -} \ No newline at end of file +{} \ No newline at end of file diff --git a/test/compliance_tool/files/test_empty.xml b/test/compliance_tool/files/test_empty.xml index 3e5f1f166..0329f4b5a 100644 --- a/test/compliance_tool/files/test_empty.xml +++ b/test/compliance_tool/files/test_empty.xml @@ -1,2 +1,3 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/test/compliance_tool/files/test_empty_aasx/[Content_Types].xml b/test/compliance_tool/files/test_empty_aasx/[Content_Types].xml new file mode 100644 index 000000000..18520c7e8 --- /dev/null +++ b/test/compliance_tool/files/test_empty_aasx/[Content_Types].xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/compliance_tool/files/test_empty_aasx/_rels/.rels b/test/compliance_tool/files/test_empty_aasx/_rels/.rels new file mode 100644 index 000000000..9c5de6cf4 --- /dev/null +++ b/test/compliance_tool/files/test_empty_aasx/_rels/.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/compliance_tool/files/test_empty_aasx/aasx/_rels/aasx-origin.rels b/test/compliance_tool/files/test_empty_aasx/aasx/_rels/aasx-origin.rels new file mode 100644 index 000000000..7b813240b --- /dev/null +++ b/test/compliance_tool/files/test_empty_aasx/aasx/_rels/aasx-origin.rels @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/compliance_tool/files/test_empty_aasx/aasx/aasx-origin b/test/compliance_tool/files/test_empty_aasx/aasx/aasx-origin new file mode 100644 index 000000000..e69de29bb diff --git a/test/compliance_tool/files/test_empty_aasx/docProps/core.xml b/test/compliance_tool/files/test_empty_aasx/docProps/core.xml new file mode 100644 index 000000000..344bc075a --- /dev/null +++ b/test/compliance_tool/files/test_empty_aasx/docProps/core.xml @@ -0,0 +1 @@ +2020-09-25T16:07:16.936996PyI40AAS Testing Framework \ No newline at end of file diff --git a/test/compliance_tool/files/test_missing_submodels.json b/test/compliance_tool/files/test_missing_submodels.json deleted file mode 100644 index a7730c34e..000000000 --- a/test/compliance_tool/files/test_missing_submodels.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "assetAdministrationShells": [], - "assets": [], - "conceptDescriptions": [] -} \ No newline at end of file diff --git a/test/compliance_tool/files/test_missing_submodels.xml b/test/compliance_tool/files/test_missing_submodels.xml deleted file mode 100644 index e22650bbc..000000000 --- a/test/compliance_tool/files/test_missing_submodels.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/test/compliance_tool/files/test_not_deserializable.json b/test/compliance_tool/files/test_not_deserializable.json index 04841c26f..9a0c369d9 100644 --- a/test/compliance_tool/files/test_not_deserializable.json +++ b/test/compliance_tool/files/test_not_deserializable.json @@ -1,6 +1,5 @@ { "assetAdministrationShells": [], - "assets": [], "submodels": [] "conceptDescriptions": [] } \ No newline at end of file diff --git a/test/compliance_tool/files/test_not_deserializable_aas.json b/test/compliance_tool/files/test_not_deserializable_aas.json index 8b8869c39..cf239e8b7 100644 --- a/test/compliance_tool/files/test_not_deserializable_aas.json +++ b/test/compliance_tool/files/test_not_deserializable_aas.json @@ -1,6 +1,15 @@ { - "assetAdministrationShells":[{"identification":{"id":"https://acplt.org/Test_AssetAdministrationShell","idType":"IRI"},"idShort":"TestAssetAdministrationShell","modelType":{"name":"Test"},"asset":{"keys":[{"idType":"IRI","local":false,"type":"Asset","value":"https://acplt.org/Test_Asset"}]}}], - "assets": [], - "submodels": [], - "conceptDescriptions": [] + "assetAdministrationShells": [ + { + "id": "https://acplt.org/Test_AssetAdministrationShell", + "idShort": "TestAssetAdministrationShell", + "modelType": "Test", + "assetInformation": { + "assetKind": "Instance", + "globalAssetId": "http://acplt.org/Test_Asset/" + } + } + ], + "submodels": [], + "conceptDescriptions": [] } \ No newline at end of file diff --git a/test/compliance_tool/files/test_not_deserializable_aas.xml b/test/compliance_tool/files/test_not_deserializable_aas.xml index 179844242..d673e80ec 100644 --- a/test/compliance_tool/files/test_not_deserializable_aas.xml +++ b/test/compliance_tool/files/test_not_deserializable_aas.xml @@ -1,2 +1,13 @@ -https://acplt.org/Test_Submodel2_MandatoryInstance \ No newline at end of file + + + + + https://acplt.org/Test_Submodel2_Mandatory + Instance + + + + + + \ No newline at end of file diff --git a/test/compliance_tool/test_aas_compliance_tool.py b/test/compliance_tool/test_aas_compliance_tool.py index a45d88adf..8cd3004db 100644 --- a/test/compliance_tool/test_aas_compliance_tool.py +++ b/test/compliance_tool/test_aas_compliance_tool.py @@ -101,13 +101,13 @@ def test_parse_args(self) -> None: # test verbose output = _run_compliance_tool("e", os.path.join(test_file_path, "test_demo_full_example.json"), "--json", "-v") self.assertEqual(0, output.returncode) - self.assertNotIn('ERROR', str(output.stdout)) + self.assertNotIn('ERROR', str(output.stderr)) self.assertNotIn('INFO', str(output.stdout)) output = _run_compliance_tool("e", os.path.join(test_file_path, "test_demo_full_example.json"), "--json", "-v", "-v") self.assertEqual(0, output.returncode) - self.assertNotIn('ERROR', str(output.stdout)) + self.assertNotIn('ERROR', str(output.stderr)) self.assertIn('INFO', str(output.stdout)) # test quite @@ -254,19 +254,38 @@ def test_aasx_create_example(self) -> None: os.unlink(filename) - def test_aasx_deseralization(self) -> None: + def test_aasx_deseralization_xml(self) -> None: test_file_path = os.path.join(os.path.dirname(__file__), 'files') - output = _run_compliance_tool("d", os.path.join(test_file_path, "test_demo_full_example.aasx"), "--xml", + output = _run_compliance_tool("d", os.path.join(test_file_path, "test_demo_full_example_xml.aasx"), "--xml", "--aasx") self.assertEqual(0, output.returncode) self.assertIn('SUCCESS: Open file', str(output.stdout)) self.assertIn('SUCCESS: Read file', str(output.stdout)) - def test_aasx_example(self) -> None: + def test_aasx_example_xml(self) -> None: test_file_path = os.path.join(os.path.dirname(__file__), 'files') - output = _run_compliance_tool("e", os.path.join(test_file_path, "test_demo_full_example.aasx"), "--xml", + output = _run_compliance_tool("e", os.path.join(test_file_path, "test_demo_full_example_xml.aasx"), "--xml", + "--aasx") + self.assertEqual(0, output.returncode) + self.assertIn('SUCCESS: Open file', str(output.stdout)) + self.assertIn('SUCCESS: Read file', str(output.stdout)) + self.assertIn('SUCCESS: Check if data is equal to example data', str(output.stdout)) + + def test_aasx_deseralization_json(self) -> None: + test_file_path = os.path.join(os.path.dirname(__file__), 'files') + + output = _run_compliance_tool("d", os.path.join(test_file_path, "test_demo_full_example_json.aasx"), "--json", + "--aasx") + self.assertEqual(0, output.returncode) + self.assertIn('SUCCESS: Open file', str(output.stdout)) + self.assertIn('SUCCESS: Read file', str(output.stdout)) + + def test_aasx_example_json(self) -> None: + test_file_path = os.path.join(os.path.dirname(__file__), 'files') + + output = _run_compliance_tool("e", os.path.join(test_file_path, "test_demo_full_example_json.aasx"), "--json", "--aasx") self.assertEqual(0, output.returncode) self.assertIn('SUCCESS: Open file', str(output.stdout)) @@ -276,8 +295,9 @@ def test_aasx_example(self) -> None: def test_aasx_file(self) -> None: test_file_path = os.path.join(os.path.dirname(__file__), 'files') - output = _run_compliance_tool("f", os.path.join(test_file_path, "test_demo_full_example.aasx"), - os.path.join(test_file_path, "test_demo_full_example.aasx"), "--xml", "--aasx") + output = _run_compliance_tool("f", os.path.join(test_file_path, "test_demo_full_example_xml.aasx"), + os.path.join(test_file_path, "test_demo_full_example_xml.aasx"), "--xml", + "--aasx") self.assertEqual(0, output.returncode) self.assertIn('SUCCESS: Open first file', str(output.stdout)) self.assertIn('SUCCESS: Read file', str(output.stdout)) diff --git a/test/compliance_tool/test_compliance_check_aasx.py b/test/compliance_tool/test_compliance_check_aasx.py index 5abb5a74a..78d9e04b7 100644 --- a/test/compliance_tool/test_compliance_check_aasx.py +++ b/test/compliance_tool/test_compliance_check_aasx.py @@ -26,7 +26,14 @@ def test_check_deserialization(self) -> None: # Todo add more tests for checking wrong aasx files manager.steps = [] - file_path_5 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') + file_path_5 = os.path.join(script_dir, 'files/test_demo_full_example_xml.aasx') + compliance_tool.check_deserialization(file_path_5, manager) + self.assertEqual(2, len(manager.steps)) + self.assertEqual(Status.SUCCESS, manager.steps[0].status) + self.assertEqual(Status.SUCCESS, manager.steps[1].status) + + manager.steps = [] + file_path_5 = os.path.join(script_dir, 'files/test_demo_full_example_json.aasx') compliance_tool.check_deserialization(file_path_5, manager) self.assertEqual(2, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -36,7 +43,7 @@ def test_check_aas_example(self) -> None: manager = ComplianceToolStateManager() script_dir = os.path.dirname(__file__) - file_path_2 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') + file_path_2 = os.path.join(script_dir, 'files/test_demo_full_example_xml.aasx') compliance_tool.check_aas_example(file_path_2, manager) self.assertEqual(4, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -45,7 +52,7 @@ def test_check_aas_example(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[3].status) manager.steps = [] - file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example2.aasx') + file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example_json.aasx') compliance_tool.check_aas_example(file_path_3, manager) self.assertEqual(4, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -54,15 +61,15 @@ def test_check_aas_example(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[3].status) manager.steps = [] - file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_wrong_attribute.aasx') + file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_xml_wrong_attribute.aasx') compliance_tool.check_aas_example(file_path_4, manager) self.assertEqual(4, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.SUCCESS, manager.steps[1].status) self.assertEqual(Status.FAILED, manager.steps[2].status) self.assertEqual('FAILED: Check if data is equal to example data\n - ERROR: Attribute id_short of ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must be == TestAssetAdministrationShell (value=\'TestAssetAdministrationShell2\')', + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', manager.format_step(2, verbose_level=1)) self.assertEqual(Status.NOT_EXECUTED, manager.steps[3].status) @@ -70,7 +77,7 @@ def test_check_aasx_files_equivalence(self) -> None: manager = ComplianceToolStateManager() script_dir = os.path.dirname(__file__) - file_path_1 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') + file_path_1 = os.path.join(script_dir, 'files/test_demo_full_example_xml.aasx') file_path_2 = os.path.join(script_dir, 'files/test_empty.aasx') compliance_tool.check_aasx_files_equivalence(file_path_1, file_path_2, manager) self.assertEqual(6, len(manager.steps)) @@ -92,8 +99,8 @@ def test_check_aasx_files_equivalence(self) -> None: self.assertEqual(Status.NOT_EXECUTED, manager.steps[5].status) manager.steps = [] - file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') - file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') + file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example_xml.aasx') + file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_json.aasx') compliance_tool.check_aasx_files_equivalence(file_path_3, file_path_4, manager) self.assertEqual(6, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -104,8 +111,8 @@ def test_check_aasx_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[5].status) manager.steps = [] - file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') - file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_wrong_attribute.aasx') + file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example_xml.aasx') + file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_xml_wrong_attribute.aasx') compliance_tool.check_aasx_files_equivalence(file_path_3, file_path_4, manager) self.assertEqual(6, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -114,8 +121,8 @@ def test_check_aasx_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[3].status) self.assertEqual(Status.FAILED, manager.steps[4].status) self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Attribute id_short of ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must be == TestAssetAdministrationShell2 (value=\'TestAssetAdministrationShell\')', + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell123 (value=\'TestAssetAdministrationShell\')', manager.format_step(4, verbose_level=1)) manager.steps = [] @@ -127,8 +134,8 @@ def test_check_aasx_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[3].status) self.assertEqual(Status.FAILED, manager.steps[4].status) self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Attribute id_short of ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must be == TestAssetAdministrationShell (value=\'TestAssetAdministrationShell2\')', + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', manager.format_step(4, verbose_level=1)) self.assertEqual(Status.NOT_EXECUTED, manager.steps[5].status) @@ -136,22 +143,29 @@ def test_check_schema(self): manager = ComplianceToolStateManager() script_dir = os.path.dirname(__file__) - file_path_2 = os.path.join(script_dir, 'files/test_demo_full_example.aasx') + file_path_2 = os.path.join(script_dir, 'files/test_demo_full_example_json.aasx') compliance_tool.check_schema(file_path_2, manager) - self.assertEqual(10, len(manager.steps)) - for i in range(10): + self.assertEqual(4, len(manager.steps)) + for i in range(4): self.assertEqual(Status.SUCCESS, manager.steps[i].status) manager.steps = [] - file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example2.aasx') + file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example_xml.aasx') compliance_tool.check_schema(file_path_3, manager) self.assertEqual(4, len(manager.steps)) for i in range(4): self.assertEqual(Status.SUCCESS, manager.steps[i].status) manager.steps = [] - file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_wrong_attribute.aasx') + file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_xml_wrong_attribute.aasx') compliance_tool.check_schema(file_path_4, manager) - self.assertEqual(10, len(manager.steps)) - for i in range(10): + self.assertEqual(4, len(manager.steps)) + for i in range(4): + self.assertEqual(Status.SUCCESS, manager.steps[i].status) + + manager.steps = [] + file_path_5 = os.path.join(script_dir, 'files/test_empty.aasx') + compliance_tool.check_schema(file_path_5, manager) + self.assertEqual(2, len(manager.steps)) + for i in range(2): self.assertEqual(Status.SUCCESS, manager.steps[i].status) diff --git a/test/compliance_tool/test_compliance_check_json.py b/test/compliance_tool/test_compliance_check_json.py index 87ed5b5cd..b6201d108 100644 --- a/test/compliance_tool/test_compliance_check_json.py +++ b/test/compliance_tool/test_compliance_check_json.py @@ -30,19 +30,18 @@ def test_check_schema(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.FAILED, manager.steps[1].status) self.assertEqual(Status.NOT_EXECUTED, manager.steps[2].status) - self.assertIn("Expecting ',' delimiter: line 5 column 2 (char 69)", manager.format_step(1, verbose_level=1)) + self.assertIn("Expecting ',' delimiter: line 4 column 2 (char 54)", manager.format_step(1, verbose_level=1)) manager.steps = [] - file_path_3 = os.path.join(script_dir, 'files/test_missing_submodels.json') + file_path_3 = os.path.join(script_dir, 'files/test_empty.json') compliance_tool.check_schema(file_path_3, manager) self.assertEqual(3, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.SUCCESS, manager.steps[1].status) - self.assertEqual(Status.FAILED, manager.steps[2].status) - self.assertIn("'submodels' is a required property", manager.format_step(2, verbose_level=1)) + self.assertEqual(Status.SUCCESS, manager.steps[2].status) manager.steps = [] - file_path_4 = os.path.join(script_dir, 'files/test_empty.json') + file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example.json') compliance_tool.check_schema(file_path_4, manager) self.assertEqual(3, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -50,7 +49,7 @@ def test_check_schema(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[2].status) manager.steps = [] - file_path_5 = os.path.join(script_dir, 'files/test_demo_full_example.json') + file_path_5 = os.path.join(script_dir, 'files/test_demo_full_example_wrong_attribute.json') compliance_tool.check_schema(file_path_5, manager) self.assertEqual(3, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) @@ -129,8 +128,8 @@ def test_check_aas_example(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[1].status) self.assertEqual(Status.FAILED, manager.steps[2].status) self.assertEqual('FAILED: Check if data is equal to example data\n - ERROR: Attribute id_short of ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must be == TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', manager.format_step(2, verbose_level=1)) def test_check_json_files_equivalence(self) -> None: @@ -178,8 +177,8 @@ def test_check_json_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[3].status) self.assertEqual(Status.FAILED, manager.steps[4].status) self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Attribute id_short of ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must be == TestAssetAdministrationShell123 (value=\'TestAssetAdministrationShell\')', + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell123 (value=\'TestAssetAdministrationShell\')', manager.format_step(4, verbose_level=1)) manager.steps = [] @@ -191,6 +190,6 @@ def test_check_json_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[3].status) self.assertEqual(Status.FAILED, manager.steps[4].status) self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Attribute id_short of ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must be == TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', manager.format_step(4, verbose_level=1)) diff --git a/test/compliance_tool/test_compliance_check_xml.py b/test/compliance_tool/test_compliance_check_xml.py index 3ce9534bb..a1658e508 100644 --- a/test/compliance_tool/test_compliance_check_xml.py +++ b/test/compliance_tool/test_compliance_check_xml.py @@ -24,24 +24,24 @@ def test_check_schema(self) -> None: self.assertIn("No such file or directory", manager.format_step(0, verbose_level=1)) manager.steps = [] - file_path_3 = os.path.join(script_dir, 'files/test_missing_submodels.xml') - compliance_tool.check_schema(file_path_3, manager) + file_path_2 = os.path.join(script_dir, 'files/test_empty.xml') + compliance_tool.check_schema(file_path_2, manager) self.assertEqual(3, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.SUCCESS, manager.steps[1].status) self.assertEqual(Status.SUCCESS, manager.steps[2].status) manager.steps = [] - file_path_4 = os.path.join(script_dir, 'files/test_empty.xml') - compliance_tool.check_schema(file_path_4, manager) + file_path_3 = os.path.join(script_dir, 'files/test_demo_full_example.xml') + compliance_tool.check_schema(file_path_3, manager) self.assertEqual(3, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.SUCCESS, manager.steps[1].status) self.assertEqual(Status.SUCCESS, manager.steps[2].status) manager.steps = [] - file_path_5 = os.path.join(script_dir, 'files/test_demo_full_example.xml') - compliance_tool.check_schema(file_path_5, manager) + file_path_4 = os.path.join(script_dir, 'files/test_demo_full_example_wrong_attribute.xml') + compliance_tool.check_schema(file_path_4, manager) self.assertEqual(3, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.SUCCESS, manager.steps[1].status) @@ -74,7 +74,7 @@ def test_check_deserialization(self) -> None: self.assertEqual(2, len(manager.steps)) self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.FAILED, manager.steps[1].status) - self.assertIn("ValueError: A revision requires a version", manager.format_step(1, verbose_level=1)) + self.assertIn("AASConstraintViolation: A revision requires a version", manager.format_step(1, verbose_level=1)) manager.steps = [] file_path_4 = os.path.join(script_dir, 'files/test_empty.xml') @@ -119,11 +119,9 @@ def test_check_aas_example(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[0].status) self.assertEqual(Status.SUCCESS, manager.steps[1].status) self.assertEqual(Status.FAILED, manager.steps[2].status) - self.assertEqual('FAILED: Check if data is equal to example data\n - ERROR: Asset administration shell ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must exist in given asset administrationshell list ()\n - ERROR: Given asset administration ' - 'shell list must not have extra asset administration shells (value={AssetAdministrationShell' - '[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell123)]})', + self.assertEqual('FAILED: Check if data is equal to example data\n - ERROR: Attribute id_short of ' + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', manager.format_step(2, verbose_level=1)) def test_check_xml_files_equivalence(self) -> None: @@ -170,11 +168,9 @@ def test_check_xml_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[2].status) self.assertEqual(Status.SUCCESS, manager.steps[3].status) self.assertEqual(Status.FAILED, manager.steps[4].status) - self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Asset administration shell ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell123)] ' - 'must exist in given asset administrationshell list ()\n - ERROR: Given asset administration ' - 'shell list must not have extra asset administration shells (value={AssetAdministrationShell' - '[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)]})', + self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Attribute id_short of ' + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell123 (value=\'TestAssetAdministrationShell\')', manager.format_step(4, verbose_level=1)) manager.steps = [] @@ -185,9 +181,7 @@ def test_check_xml_files_equivalence(self) -> None: self.assertEqual(Status.SUCCESS, manager.steps[2].status) self.assertEqual(Status.SUCCESS, manager.steps[3].status) self.assertEqual(Status.FAILED, manager.steps[4].status) - self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Asset administration shell ' - 'AssetAdministrationShell[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell)] ' - 'must exist in given asset administrationshell list ()\n - ERROR: Given asset administration ' - 'shell list must not have extra asset administration shells (value={AssetAdministrationShell' - '[Identifier(IRI=https://acplt.org/Test_AssetAdministrationShell123)]})', + self.assertEqual('FAILED: Check if data in files are equal\n - ERROR: Attribute id_short of ' + 'AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell] must be == ' + 'TestAssetAdministrationShell (value=\'TestAssetAdministrationShell123\')', manager.format_step(4, verbose_level=1)) diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index fd1ad9510..7b79457bc 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -7,7 +7,7 @@ import unittest from basyx.aas.examples.data import example_aas, example_aas_mandatory_attributes, example_aas_missing_attributes, \ - example_concept_description, example_submodel_template + example_submodel_template from basyx.aas.examples.data._helper import AASDataChecker from basyx.aas import model @@ -23,11 +23,6 @@ def test_example_bill_of_material_submodel(self): submodel = example_aas.create_example_bill_of_material_submodel() example_aas.check_example_bill_of_material_submodel(checker, submodel) - def test_example_asset(self): - checker = AASDataChecker(raise_immediately=True) - asset = example_aas.create_example_asset() - example_aas.check_example_asset(checker, asset) - def test_example_concept_description(self): checker = AASDataChecker(raise_immediately=True) concept_description = example_aas.create_example_concept_description() @@ -35,8 +30,7 @@ def test_example_concept_description(self): def test_example_asset_administration_shell(self): checker = AASDataChecker(raise_immediately=True) - concept_dictionary = example_aas.create_example_concept_dictionary() - shell = example_aas.create_example_asset_administration_shell(concept_dictionary) + shell = example_aas.create_example_asset_administration_shell() example_aas.check_example_asset_administration_shell(checker, shell) def test_example_submodel(self): @@ -49,67 +43,50 @@ def test_full_example(self): obj_store = model.DictObjectStore() with self.assertRaises(AssertionError) as cm: example_aas.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Asset[Identifier(IRI=https://acplt.org/Test_Asset)]")) + self.assertIn("AssetAdministrationShell[https://acplt.org/Test_AssetAdministrationShell]", + str(cm.exception)) obj_store = example_aas.create_full_example() example_aas.check_full_example(checker, obj_store) - failed_asset = model.Asset(kind=model.AssetKind.INSTANCE, - identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - obj_store.add(failed_asset) - with self.assertRaises(AssertionError) as cm: - example_aas.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Asset[Identifier(CUSTOM=test)]")) - obj_store.discard(failed_asset) - failed_shell = model.AssetAdministrationShell( - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='test', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier('test', model.IdentifierType.CUSTOM) + asset_information=model.AssetInformation(global_asset_id='test'), + id_='test' ) obj_store.add(failed_shell) with self.assertRaises(AssertionError) as cm: example_aas.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("AssetAdministrationShell[Identifier(CUSTOM=test)]")) + self.assertIn("AssetAdministrationShell[test]", str(cm.exception)) obj_store.discard(failed_shell) - failed_submodel = model.Submodel(identification=model.Identifier('test', model.IdentifierType.CUSTOM)) + failed_submodel = model.Submodel(id_='test') obj_store.add(failed_submodel) with self.assertRaises(AssertionError) as cm: example_aas.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Submodel[Identifier(CUSTOM=test)]")) + self.assertIn("Submodel[test]", str(cm.exception)) obj_store.discard(failed_submodel) - failed_cd = model.ConceptDescription(identification=model.Identifier('test', model.IdentifierType.CUSTOM)) + failed_cd = model.ConceptDescription(id_='test') obj_store.add(failed_cd) with self.assertRaises(AssertionError) as cm: example_aas.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("ConceptDescription[Identifier(CUSTOM=test)]")) + self.assertIn("ConceptDescription[test]", str(cm.exception)) obj_store.discard(failed_cd) class DummyIdentifiable(model.Identifiable): - def __init__(self, identification: model.Identifier): + def __init__(self, id_: model.Identifier): super().__init__() - self.identification = identification - failed_identifiable = DummyIdentifiable(identification=model.Identifier('test', model.IdentifierType.CUSTOM)) + self.id = id_ + failed_identifiable = DummyIdentifiable(id_='test') obj_store.add(failed_identifiable) with self.assertRaises(KeyError) as cm: example_aas.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Check for DummyIdentifiable[Identifier(CUSTOM=test)] not " - "implemented")) + self.assertIn("Check for DummyIdentifiable[test] not implemented", str(cm.exception)) obj_store.discard(failed_identifiable) example_aas.check_full_example(checker, obj_store) class ExampleAASMandatoryTest(unittest.TestCase): - def test_example_asset(self): - checker = AASDataChecker(raise_immediately=True) - asset = example_aas_mandatory_attributes.create_example_asset() - example_aas_mandatory_attributes.check_example_asset(checker, asset) - def test_example_submodel(self): checker = AASDataChecker(raise_immediately=True) submodel = example_aas_mandatory_attributes.create_example_submodel() @@ -127,8 +104,7 @@ def test_example_concept_description(self): def test_example_asset_administration_shell(self): checker = AASDataChecker(raise_immediately=True) - concept_dictionary = example_aas_mandatory_attributes.create_example_concept_dictionary() - shell = example_aas_mandatory_attributes.create_example_asset_administration_shell(concept_dictionary) + shell = example_aas_mandatory_attributes.create_example_asset_administration_shell() example_aas_mandatory_attributes.check_example_asset_administration_shell(checker, shell) def test_full_example(self): @@ -136,24 +112,17 @@ def test_full_example(self): obj_store = example_aas_mandatory_attributes.create_full_example() example_aas_mandatory_attributes.check_full_example(checker, obj_store) - failed_asset = model.Asset(kind=model.AssetKind.INSTANCE, - identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - obj_store.add(failed_asset) + failed_submodel = model.Submodel(id_='test') + obj_store.add(failed_submodel) with self.assertRaises(AssertionError) as cm: example_aas_mandatory_attributes.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Asset Asset[Identifier(CUSTOM=test)] must exist in given " - "asset list")) - self.assertNotEqual(-1, str(cm.exception).find("Asset[Identifier(CUSTOM=test)]")) - obj_store.discard(failed_asset) + self.assertIn("Given submodel list must not have extra submodels", str(cm.exception)) + self.assertIn("Submodel[test]", str(cm.exception)) + obj_store.discard(failed_submodel) example_aas_mandatory_attributes.check_full_example(checker, obj_store) class ExampleAASMissingTest(unittest.TestCase): - def test_example_asset(self): - checker = AASDataChecker(raise_immediately=True) - asset = example_aas_missing_attributes.create_example_asset() - example_aas_missing_attributes.check_example_asset(checker, asset) - def test_example_submodel(self): checker = AASDataChecker(raise_immediately=True) submodel = example_aas_missing_attributes.create_example_submodel() @@ -166,8 +135,7 @@ def test_example_concept_description(self): def test_example_asset_administration_shell(self): checker = AASDataChecker(raise_immediately=True) - concept_dictionary = example_aas_missing_attributes.create_example_concept_dictionary() - shell = example_aas_missing_attributes.create_example_asset_administration_shell(concept_dictionary) + shell = example_aas_missing_attributes.create_example_asset_administration_shell() example_aas_missing_attributes.check_example_asset_administration_shell(checker, shell) def test_full_example(self): @@ -175,39 +143,16 @@ def test_full_example(self): obj_store = example_aas_missing_attributes.create_full_example() example_aas_missing_attributes.check_full_example(checker, obj_store) - failed_asset = model.Asset(kind=model.AssetKind.INSTANCE, - identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - obj_store.add(failed_asset) + failed_submodel = model.Submodel(id_='test') + obj_store.add(failed_submodel) with self.assertRaises(AssertionError) as cm: example_aas_missing_attributes.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Asset[Identifier(CUSTOM=test)]")) - obj_store.discard(failed_asset) + self.assertIn("Given submodel list must not have extra submodels", str(cm.exception)) + self.assertIn("Submodel[test]", str(cm.exception)) + obj_store.discard(failed_submodel) example_aas_missing_attributes.check_full_example(checker, obj_store) -class ExampleConceptDescriptionTest(unittest.TestCase): - def test_iec61360_concept_description(self): - checker = AASDataChecker(raise_immediately=True) - concept_description = example_concept_description.create_iec61360_concept_description() - example_concept_description.check_example_iec61360_concept_description(checker, concept_description) - - def test_full_example(self): - checker = AASDataChecker(raise_immediately=True) - obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore() - obj_store.add(example_concept_description.create_iec61360_concept_description()) - example_concept_description.check_full_example(checker, obj_store) - - failed_asset = model.Asset(kind=model.AssetKind.INSTANCE, - identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - obj_store.add(failed_asset) - with self.assertRaises(AssertionError) as cm: - example_concept_description.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Asset[Identifier(CUSTOM=test)]")) - obj_store.discard(failed_asset) - - example_concept_description.check_full_example(checker, obj_store) - - class ExampleSubmodelTemplate(unittest.TestCase): def test_example_submodel_template(self): checker = AASDataChecker(raise_immediately=True) @@ -220,12 +165,12 @@ def test_full_example(self): obj_store.add(example_submodel_template.create_example_submodel_template()) example_submodel_template.check_full_example(checker, obj_store) - failed_asset = model.Asset(kind=model.AssetKind.INSTANCE, - identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - obj_store.add(failed_asset) + failed_submodel = model.Submodel(id_='test') + obj_store.add(failed_submodel) with self.assertRaises(AssertionError) as cm: example_submodel_template.check_full_example(checker, obj_store) - self.assertNotEqual(-1, str(cm.exception).find("Asset[Identifier(CUSTOM=test)]")) - obj_store.discard(failed_asset) + self.assertIn("Given submodel list must not have extra submodels", str(cm.exception)) + self.assertIn("Submodel[test]", str(cm.exception)) + obj_store.discard(failed_submodel) example_submodel_template.check_full_example(checker, obj_store) diff --git a/test/examples/test_helpers.py b/test/examples/test_helpers.py index c427e2f58..8fe4b7ae8 100644 --- a/test/examples/test_helpers.py +++ b/test/examples/test_helpers.py @@ -8,7 +8,6 @@ from basyx.aas.examples.data._helper import DataChecker, AASDataChecker from basyx.aas import model -from basyx.aas.model.concept import IEC61360DataType class DataCheckerTest(unittest.TestCase): @@ -59,31 +58,152 @@ def test_qualifiable_checker(self): ) checker = AASDataChecker(raise_immediately=False) + checker.check_property_equal(property, property_expected) self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - self.assertEqual(9, sum(1 for _ in checker.successful_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: Property[Prop1] must contain 1 Constraints (count=0)", + self.assertEqual(14, sum(1 for _ in checker.successful_checks)) + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute qualifier of Property[Prop1] must contain 1 Qualifiers (count=0)", + repr(next(checker_iterator))) + self.assertEqual("FAIL: Qualifier(type=test) must exist ()", repr(next(checker_iterator))) + + def test_submodel_element_list_checker(self): + + # value + range1 = model.Range(None, model.datatypes.Int, 42, 142857) + range2 = model.Range(None, model.datatypes.Int, 42, 1337) + list_ = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.Range, + value_type_list_element=model.datatypes.Int, + order_relevant=True, + value=(range1, range2) + ) + + range1_expected = model.Range(None, model.datatypes.Int, 42, 142857) + range2_expected = model.Range(None, model.datatypes.Int, 42, 1337) + list_expected = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.Range, + value_type_list_element=model.datatypes.Int, + order_relevant=True, + value=(range2_expected, range1_expected) + ) + + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(2, sum(1 for _ in checker.failed_checks)) + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute max of Range[test_list[0]] must be == 1337 (value=142857)", + repr(next(checker_iterator))) + self.assertEqual("FAIL: Attribute max of Range[test_list[1]] must be == 142857 (value=1337)", + repr(next(checker_iterator))) + + # order_relevant + # Don't set protected attributes like this in production code! + list_._order_relevant = False + checker = AASDataChecker(raise_immediately=False) + with self.assertRaises(NotImplementedError) as cm: + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual("A SubmodelElementList with order_relevant=False cannot be compared!", str(cm.exception)) + self.assertEqual(1, sum(1 for _ in checker.failed_checks)) + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute order_relevant of SubmodelElementList[test_list] must be == True " + "(value=False)", repr(next(checker_iterator))) + + # value_type_list_element + list_ = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.Range, + value_type_list_element=model.datatypes.Int, + ) + list_expected = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.Range, + value_type_list_element=model.datatypes.String, + ) + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(1, sum(1 for _ in checker.failed_checks)) + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute value_type_list_element of SubmodelElementList[test_list] must be == str " + "(value='Int')", repr(next(checker_iterator))) + + # Don't set protected attributes like this in production code! + list_._value_type_list_element = model.datatypes.String + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(0, sum(1 for _ in checker.failed_checks)) + + # type_value_list_element + list_ = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.Range, + value_type_list_element=model.datatypes.Int, + ) + list_expected = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.Property, + value_type_list_element=model.datatypes.Int, + ) + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(1, sum(1 for _ in checker.failed_checks)) + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute type_value_list_element of SubmodelElementList[test_list] must be == " + "Property (value='Range')", + repr(next(checker_iterator))) + + # Don't set protected attributes like this in production code! + list_._type_value_list_element = model.Property + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(0, sum(1 for _ in checker.failed_checks)) + + # semantic_id_list_element + list_ = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.MultiLanguageProperty, + semantic_id_list_element=model.ExternalReference( + (model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:invalid"),)) + ) + list_expected = model.SubmodelElementList( + id_short='test_list', + type_value_list_element=model.MultiLanguageProperty, + semantic_id_list_element=model.ExternalReference( + (model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:test"),)) + ) + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(1, sum(1 for _ in checker.failed_checks)) + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute semantic_id_list_element of SubmodelElementList[test_list] must be == " + "ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=urn:x-test:test),)) " + "(value=ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=urn:x-test:invalid),)))", repr(next(checker_iterator))) - self.assertEqual("FAIL: ConstraintQualifier(type=test) must exist ()", repr(next(checker_iterator))) + # Don't set protected attributes like this in production code! + list_._semantic_id_list_element = model.ExternalReference( + (model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:test"),)) + checker = AASDataChecker(raise_immediately=False) + checker.check_submodel_element_list_equal(list_, list_expected) + self.assertEqual(0, sum(1 for _ in checker.failed_checks)) - def test_submodel_element_collection_ordered_checker(self): + def test_submodel_element_collection_checker(self): property = model.Property( id_short='Prop1', value_type=model.datatypes.String, value='test' ) - range = model.Range( + range_ = model.Range( id_short='Range1', value_type=model.datatypes.Int, min=100, max=200 ) - collection = model.SubmodelElementCollectionOrdered( + collection = model.SubmodelElementCollection( id_short='Collection', - value=(property, range) + value=(range_,) ) - property_expected = model.Property( id_short='Prop1', value_type=model.datatypes.String, @@ -95,103 +215,69 @@ def test_submodel_element_collection_ordered_checker(self): min=100, max=200 ) - collection_expected = model.SubmodelElementCollectionOrdered( + collection_expected = model.SubmodelElementCollection( id_short='Collection', - value=(range_expected, property_expected) + value=(property_expected, range_expected) ) checker = AASDataChecker(raise_immediately=False) - checker.check_submodel_collection_equal(collection, collection_expected) + checker.check_submodel_element_collection_equal(collection, collection_expected) self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: Property[Collection / Prop1] must be of class Range (class='Property')", + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute value of SubmodelElementCollection[Collection] must contain 2 " + "SubmodelElements (count=1)", repr(next(checker_iterator))) - self.assertEqual("FAIL: Range[Collection / Range1] must be of class Property (class='Range')", + self.assertEqual("FAIL: Submodel Element Property[Collection / Prop1] must exist ()", repr(next(checker_iterator))) - def test_submodel_element_collection_unordered_checker(self): - collection = model.SubmodelElementCollectionUnordered( - id_short='Collection', - value=() - ) - property_expected = model.Property( - id_short='Prop1', - value_type=model.datatypes.String, - value='test' - ) - collection_expected = model.SubmodelElementCollectionUnordered( - id_short='Collection', - value=(property_expected,) - ) - + collection.add_referable(property) checker = AASDataChecker(raise_immediately=False) - checker.check_submodel_collection_equal(collection, collection_expected) - self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: SubmodelElementCollectionUnordered[Collection] must contain 1 SubmodelElements " - "(count=0)", - repr(next(checker_iterator))) - self.assertEqual("FAIL: Submodel ElementProperty[Collection / Prop1] must exist ()", - repr(next(checker_iterator))) + self.assertEqual(0, sum(1 for _ in checker.failed_checks)) def test_not_implemented(self): class DummySubmodelElement(model.SubmodelElement): - def __init__(self, id_short: str): + def __init__(self, id_short: model.NameType): super().__init__(id_short) dummy_submodel_element = DummySubmodelElement('test') - submodel_collection = model.SubmodelElementCollectionUnordered('test') + submodel_collection = model.SubmodelElementCollection('test') submodel_collection.value.add(dummy_submodel_element) checker = AASDataChecker(raise_immediately=True) with self.assertRaises(AttributeError) as cm: - checker.check_submodel_collection_equal(submodel_collection, submodel_collection) + checker.check_submodel_element_collection_equal(submodel_collection, submodel_collection) self.assertEqual( 'Submodel Element class not implemented', str(cm.exception) ) - class DummySubmodelElementCollection(model.SubmodelElementCollection): - def __init__(self, id_short: str): - super().__init__(id_short) - - @property - def ordered(self): - return True - - dummy_submodel_element_collection = DummySubmodelElementCollection('test') - submodel = model.Submodel(identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - submodel.submodel_element.add(dummy_submodel_element_collection) - checker = AASDataChecker(raise_immediately=True) - with self.assertRaises(AttributeError) as cm: - checker.check_submodel_equal(submodel, submodel) - self.assertEqual( - 'Submodel Element collection class not implemented', - str(cm.exception) - ) - def test_annotated_relationship_element(self): rel1 = model.AnnotatedRelationshipElement(id_short='test', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), + first=model.ModelReference(( + model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key( + type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + second=model.ModelReference(( + model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), ) rel2 = model.AnnotatedRelationshipElement(id_short='test', - first=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), - second=model.AASReference((model.Key(type_=model.KeyElements.PROPERTY, - local=True, - value='ExampleProperty', - id_type=model.KeyType.IDSHORT),), - model.Property), + first=model.ModelReference(( + model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), + second=model.ModelReference(( + model.Key(type_=model.KeyTypes.SUBMODEL, + value='http://acplt.org/Test_Submodel'), + model.Key(type_=model.KeyTypes.PROPERTY, + value='ExampleProperty'),), + model.Property), annotation={ model.Property(id_short="ExampleAnnotatedProperty", value_type=model.datatypes.String, @@ -201,160 +287,72 @@ def test_annotated_relationship_element(self): checker = AASDataChecker(raise_immediately=False) checker.check_annotated_relationship_element_equal(rel1, rel2) self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: AnnotatedRelationshipElement[test] must contain 1 DataElements " + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute annotation of AnnotatedRelationshipElement[test] must contain 1 DataElements " "(count=0)", repr(next(checker_iterator))) self.assertEqual("FAIL: Annotation Property[test / ExampleAnnotatedProperty] must exist ()", repr(next(checker_iterator))) def test_submodel_checker(self): - submodel = model.Submodel(identification=model.Identifier('test', model.IdentifierType.CUSTOM)) + submodel = model.Submodel(id_='test') property_expected = model.Property( id_short='Prop1', value_type=model.datatypes.String, value='test' ) - submodel_expected = model.Submodel(identification=model.Identifier('test', model.IdentifierType.CUSTOM), + submodel_expected = model.Submodel(id_='test', submodel_element=(property_expected,) ) checker = AASDataChecker(raise_immediately=False) checker.check_submodel_equal(submodel, submodel_expected) self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: Submodel[Identifier(CUSTOM=test)] must contain 1 SubmodelElements (count=0)", + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute submodel_element of Submodel[test] must contain 1 " + "SubmodelElements (count=0)", repr(next(checker_iterator))) - self.assertEqual("FAIL: Submodel ElementProperty[Identifier(CUSTOM=test) / Prop1] must exist ()", + self.assertEqual("FAIL: Submodel Element Property[test / Prop1] must exist ()", repr(next(checker_iterator))) def test_asset_administration_shell_checker(self): - shell = model.AssetAdministrationShell(asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='test', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier('test', model.IdentifierType.CUSTOM)) + shell = model.AssetAdministrationShell(asset_information=model.AssetInformation( + global_asset_id='test'), + id_='test') shell_expected = model.AssetAdministrationShell( - asset=model.AASReference((model.Key(type_=model.KeyElements.ASSET, - local=False, - value='test', - id_type=model.KeyType.IRI),), - model.Asset), - identification=model.Identifier('test', model.IdentifierType.CUSTOM), - submodel={model.AASReference((model.Key(type_=model.KeyElements.SUBMODEL, - local=False, - value='test', - id_type=model.KeyType.IRI),), - model.Submodel)}, - concept_dictionary=(model.ConceptDictionary(id_short='test'),), - view=(model.View(id_short='test2'),) + asset_information=model.AssetInformation( + global_asset_id='test'), + id_='test', + submodel={model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, + value='test'),), + model.Submodel)} ) checker = AASDataChecker(raise_immediately=False) checker.check_asset_administration_shell_equal(shell, shell_expected) - self.assertEqual(6, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: AssetAdministrationShell[Identifier(CUSTOM=test)] must contain 1 AASReferences " - "(count=0)", - repr(next(checker_iterator))) - self.assertEqual("FAIL: AssetAdministrationShell[Identifier(CUSTOM=test)] must contain 1 ConceptDictionarys " - "(count=0)", - repr(next(checker_iterator))) - self.assertEqual("FAIL: AssetAdministrationShell[Identifier(CUSTOM=test)] must contain 1 Views " - "(count=0)", - repr(next(checker_iterator))) - - self.assertEqual("FAIL: Submodel Reference AASReference(type=Submodel, key=(Key(local=False, id_type=IRI, " - "value=test),)) must exist ()", - repr(next(checker_iterator))) - self.assertEqual("FAIL: Concept Dictionary ConceptDictionary[Identifier(CUSTOM=test) / test] must exist ()", - repr(next(checker_iterator))) - self.assertEqual("FAIL: View View[Identifier(CUSTOM=test) / test2] must exist ()", - repr(next(checker_iterator))) - - def test_concept_dictionary_checker(self): - cd = model.ConceptDictionary(id_short='test') - cd_expected = model.ConceptDictionary(id_short='test', - concept_description={model.AASReference((model.Key( - type_=model.KeyElements.CONCEPT_DESCRIPTION, - local=False, - value='test', - id_type=model.KeyType.IRI),), - model.ConceptDescription)} - ) - checker = AASDataChecker(raise_immediately=False) - checker.check_concept_dictionary_equal(cd, cd_expected) - self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: ConceptDictionary[test] must contain 1 AASReferences (count=0)", - repr(next(checker_iterator))) - self.assertEqual("FAIL: Concept Description Reference AASReference(type=ConceptDescription, " - "key=(Key(local=False, id_type=IRI, value=test),)) must exist ()", - repr(next(checker_iterator))) - - def test_view_checker(self): - view = model.View(id_short='test') - view_expected = model.View(id_short='test', - contained_element={model.AASReference((model.Key( - type_=model.KeyElements.PROPERTY, - local=False, - value='test', - id_type=model.KeyType.IRI),), - model.Property)}) - checker = AASDataChecker(raise_immediately=False) - checker.check_view_equal(view, view_expected) self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: View[test] must contain 1 AASReferences (count=0)", + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute submodel of AssetAdministrationShell[test] must contain 1 " + "ModelReferences (count=0)", repr(next(checker_iterator))) - self.assertEqual("FAIL: View Reference AASReference(type=Property, key=(Key(local=False, id_type=IRI, " - "value=test),)) must exist ()", + self.assertEqual("FAIL: Submodel Reference ModelReference(key=(Key(type=SUBMODEL," + " value=test),)) must exist ()", repr(next(checker_iterator))) def test_concept_description_checker(self): - cd = model.ConceptDescription(identification=model.Identifier('test', model.IdentifierType.CUSTOM)) - cd_expected = model.ConceptDescription(identification=model.Identifier('test', model.IdentifierType.CUSTOM), - is_case_of={model.Reference((model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='test', - id_type=model.KeyType.IRI),))} + cd = model.ConceptDescription(id_='test') + cd_expected = model.ConceptDescription(id_='test', + is_case_of={ + model.ExternalReference((model.Key( + type_=model.KeyTypes.GLOBAL_REFERENCE, + value='test'),))} ) checker = AASDataChecker(raise_immediately=False) checker.check_concept_description_equal(cd, cd_expected) self.assertEqual(2, sum(1 for _ in checker.failed_checks)) - checker_iterator = iter(checker.failed_checks) - self.assertEqual("FAIL: ConceptDescription[Identifier(CUSTOM=test)] must contain 1 References (count=0)", + checker_iterator = checker.failed_checks + self.assertEqual("FAIL: Attribute is_case_of of ConceptDescription[test] must contain " + "1 References (count=0)", repr(next(checker_iterator))) - self.assertEqual("FAIL: Concept Description Reference Reference(key=(Key(local=False, id_type=IRI, " - "value=test),)) must exist ()", + self.assertEqual("FAIL: Concept Description Reference ExternalReference(key=(Key(" + "type=GLOBAL_REFERENCE, value=test),)) must exist ()", repr(next(checker_iterator))) - iec = model.IEC61360ConceptDescription( - identification=model.Identifier('test', model.IdentifierType.CUSTOM), - preferred_name={'de': 'Test Specification', 'en-us': "TestSpecification"}, - data_type=IEC61360DataType.REAL_MEASURE, - value_list={model.ValueReferencePair(value_type=model.datatypes.String, - value='test', - value_id=model.Reference((model.Key( - type_=model.KeyElements.GLOBAL_REFERENCE, - local=False, - value='test', - id_type=model.KeyType.IRI),)))} - ) - iec_expected = model.IEC61360ConceptDescription( - identification=model.Identifier('test', model.IdentifierType.CUSTOM), - preferred_name={'de': 'Test Specification', 'en-us': "TestSpecification"}, - data_type=IEC61360DataType.REAL_MEASURE - ) - - checker.raise_immediately = True - with self.assertRaises(AssertionError) as cm: - checker.check_concept_description_equal(iec, iec_expected) - self.assertEqual("('Check failed: ValueList must contain 0 ValueReferencePairs', {'value': 1})", - str(cm.exception)) - - with self.assertRaises(AssertionError) as cm: - checker.check_concept_description_equal(iec_expected, iec) - self.assertEqual("('Check failed: ValueList must contain 1 ValueReferencePairs', {'value': " - "{ValueReferencePair(value_type=, value=test, " - "value_id=Reference(key=(Key(local=False, id_type=IRI, value=test),)))}})", str(cm.exception)) diff --git a/test/model/test_aas.py b/test/model/test_aas.py new file mode 100644 index 000000000..27ce13b4d --- /dev/null +++ b/test/model/test_aas.py @@ -0,0 +1,86 @@ +# Copyright (c) 2023 the Eclipse BaSyx Authors +# +# This program and the accompanying materials are made available under the terms of the MIT License, available in +# the LICENSE file of this project. +# +# SPDX-License-Identifier: MIT + +import unittest + +from basyx.aas import model + + +class AssetInformationTest(unittest.TestCase): + def test_aasd_131_init(self) -> None: + with self.assertRaises(model.AASConstraintViolation) as cm: + model.AssetInformation(model.AssetKind.INSTANCE) + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) + model.AssetInformation(model.AssetKind.INSTANCE, global_asset_id="https://acplt.org/TestAsset") + model.AssetInformation(model.AssetKind.INSTANCE, specific_asset_id=(model.SpecificAssetId("test", "test"),)) + model.AssetInformation(model.AssetKind.INSTANCE, global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + + def test_aasd_131_set(self) -> None: + asset_information = model.AssetInformation(model.AssetKind.INSTANCE, + global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + asset_information.global_asset_id = None + with self.assertRaises(model.AASConstraintViolation) as cm: + asset_information.specific_asset_id = model.ConstrainedList(()) + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) + + asset_information = model.AssetInformation(model.AssetKind.INSTANCE, + global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + asset_information.specific_asset_id = model.ConstrainedList(()) + with self.assertRaises(model.AASConstraintViolation) as cm: + asset_information.global_asset_id = None + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) + + def test_aasd_131_specific_asset_id_add(self) -> None: + asset_information = model.AssetInformation(model.AssetKind.INSTANCE, + global_asset_id="https://acplt.org/TestAsset") + specific_asset_id1 = model.SpecificAssetId("test", "test") + specific_asset_id2 = model.SpecificAssetId("test", "test") + asset_information.specific_asset_id.append(specific_asset_id1) + asset_information.specific_asset_id.extend((specific_asset_id2,)) + self.assertIs(asset_information.specific_asset_id[0], specific_asset_id1) + self.assertIs(asset_information.specific_asset_id[1], specific_asset_id2) + + def test_aasd_131_specific_asset_id_set(self) -> None: + asset_information = model.AssetInformation(model.AssetKind.INSTANCE, + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + with self.assertRaises(model.AASConstraintViolation) as cm: + asset_information.specific_asset_id[:] = () + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) + specific_asset_id = model.SpecificAssetId("test", "test") + self.assertIsNot(asset_information.specific_asset_id[0], specific_asset_id) + asset_information.specific_asset_id[:] = (specific_asset_id,) + self.assertIs(asset_information.specific_asset_id[0], specific_asset_id) + asset_information.specific_asset_id[0] = model.SpecificAssetId("test", "test") + self.assertIsNot(asset_information.specific_asset_id[0], specific_asset_id) + + def test_aasd_131_specific_asset_id_del(self) -> None: + specific_asset_id = model.SpecificAssetId("test", "test") + asset_information = model.AssetInformation(model.AssetKind.INSTANCE, + specific_asset_id=(model.SpecificAssetId("test1", "test1"), + specific_asset_id)) + with self.assertRaises(model.AASConstraintViolation) as cm: + del asset_information.specific_asset_id[:] + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + asset_information.specific_asset_id.clear() + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) + self.assertIsNot(asset_information.specific_asset_id[0], specific_asset_id) + del asset_information.specific_asset_id[0] + self.assertIs(asset_information.specific_asset_id[0], specific_asset_id) + with self.assertRaises(model.AASConstraintViolation) as cm: + del asset_information.specific_asset_id[0] + self.assertEqual("An AssetInformation has to have a globalAssetId or a specificAssetId (Constraint AASd-131)", + str(cm.exception)) diff --git a/test/model/test_base.py b/test/model/test_base.py index bdec16d20..44ac6861d 100644 --- a/test/model/test_base.py +++ b/test/model/test_base.py @@ -7,7 +7,8 @@ import unittest from unittest import mock -from typing import Optional, List +from typing import Callable, Dict, Iterable, List, Optional, Type, TypeVar +from collections import OrderedDict from basyx.aas import model from basyx.aas.backend import backends @@ -17,49 +18,33 @@ class KeyTest(unittest.TestCase): def test_get_identifier(self): - key1 = model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel1", model.KeyType.IRI) - key2 = model.Key(model.KeyElements.PROPERTY, True, "prop1", model.KeyType.IDSHORT) - self.assertEqual("urn:x-test:submodel1", key1.get_identifier().id) - self.assertEqual(model.IdentifierType.IRI, key1.get_identifier().id_type) + key1 = model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel1") + key2 = model.Key(model.KeyTypes.PROPERTY, "prop1") + self.assertEqual("urn:x-test:submodel1", key1.get_identifier()) self.assertIsNone(key2.get_identifier()) def test_string_representation(self): - key1 = model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel1", model.KeyType.IRI) - self.assertEqual("IRI=urn:x-test:submodel1", key1.__str__()) + key1 = model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel1") + self.assertEqual("urn:x-test:submodel1", key1.__str__()) def test_equality(self): - key1 = model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel1", model.KeyType.IRI) - ident = model.Identifier('test', model.IdentifierType.CUSTOM) + key1 = model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel1") + ident = 'test' self.assertEqual(key1.__eq__(ident), NotImplemented) - -class IdentifierTest(unittest.TestCase): - def test_equality_hashing(self): - id1 = model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI) - id2 = model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI) - id3 = model.Identifier("urn:x-test:aas1", model.IdentifierType.CUSTOM) - self.assertEqual(id1, id2) - self.assertNotEqual(id1, id3) - - ids = set() - ids.add(id1) - self.assertIn(id1, ids) - self.assertIn(id2, ids) - self.assertNotIn(id3, ids) - - key1 = model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel1", model.KeyType.IRI) - self.assertEqual(id1.__eq__(key1), NotImplemented) - - def test_string_repr(self): - id1 = model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI) - self.assertIn("urn:x-test:aas1", repr(id1)) - self.assertIn("IRI", repr(id1)) - - def test_set_identifier(self): - id1 = model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI) - with self.assertRaises(AttributeError) as cm: - id1.id = 'test' - self.assertEqual('Identifier are immutable', str(cm.exception)) + def test_from_referable(self): + mlp1 = model.MultiLanguageProperty(None) + mlp2 = model.MultiLanguageProperty(None) + se_list = model.SubmodelElementList("list", model.MultiLanguageProperty, [mlp1, mlp2]) + self.assertEqual(model.Key(model.KeyTypes.MULTI_LANGUAGE_PROPERTY, "0"), model.Key.from_referable(mlp1)) + self.assertEqual(model.Key(model.KeyTypes.MULTI_LANGUAGE_PROPERTY, "1"), model.Key.from_referable(mlp2)) + del se_list.value[0] + self.assertEqual(model.Key(model.KeyTypes.MULTI_LANGUAGE_PROPERTY, "0"), model.Key.from_referable(mlp2)) + with self.assertRaises(ValueError) as cm: + model.Key.from_referable(mlp1) + self.assertEqual("Can't create Key for MultiLanguageProperty without an id_short!", str(cm.exception)) + mlp1.id_short = "mlp1" + self.assertEqual(model.Key(model.KeyTypes.MULTI_LANGUAGE_PROPERTY, "mlp1"), model.Key.from_referable(mlp1)) class ExampleReferable(model.Referable): @@ -67,7 +52,7 @@ def __init__(self): super().__init__() -class ExampleRefereableWithNamespace(model.Referable, model.Namespace): +class ExampleRefereableWithNamespace(model.Referable, model.UniqueIdShortNamespace): def __init__(self): super().__init__() @@ -103,7 +88,8 @@ def generate_example_referable_tree() -> model.Referable: :return: example_referable """ - def generate_example_referable_with_namespace(id_short: str, + + def generate_example_referable_with_namespace(id_short: model.NameType, child: Optional[model.Referable] = None) -> model.Referable: """ Generates an example referable with a namespace. @@ -115,7 +101,8 @@ def generate_example_referable_with_namespace(id_short: str, referable = ExampleRefereableWithNamespace() referable.id_short = id_short if child: - namespace_set = model.NamespaceSet(parent=referable, items=[child]) + namespace_set = model.NamespaceSet(parent=referable, attribute_names=[("id_short", True)], + items=[child]) return referable example_grandchild = generate_example_referable_with_namespace("exampleGrandchild") @@ -133,32 +120,28 @@ def generate_example_referable_with_namespace(id_short: str, class ReferableTest(unittest.TestCase): def test_id_short_constraint_aasd_002(self): test_object = ExampleReferable() - test_object.id_short = "" - self.assertEqual("", test_object.id_short) + test_object.id_short = "Test" + self.assertEqual("Test", test_object.id_short) test_object.id_short = "asdASd123_" self.assertEqual("asdASd123_", test_object.id_short) test_object.id_short = "AAs12_" self.assertEqual("AAs12_", test_object.id_short) - with self.assertRaises(ValueError) as cm: + with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "98sdsfdAS" - self.assertEqual("The id_short must start with a letter", str(cm.exception)) - with self.assertRaises(ValueError) as cm: + self.assertEqual("The id_short must start with a letter (Constraint AASd-002)", str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "_sdsfdAS" - self.assertEqual("The id_short must start with a letter", str(cm.exception)) - with self.assertRaises(ValueError) as cm: + self.assertEqual("The id_short must start with a letter (Constraint AASd-002)", str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "asdlujSAD8348@S" - self.assertEqual("The id_short must contain only letters, digits and underscore", str(cm.exception)) - with self.assertRaises(ValueError) as cm: - test_object.id_short = None - self.assertEqual("The id_short for not identifiable elements is mandatory", str(cm.exception)) - with self.assertRaises(ValueError) as cm: + self.assertEqual( + "The id_short must contain only letters, digits and underscore (Constraint AASd-002)", + str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "abc\n" - self.assertEqual("The id_short must contain only letters, digits and underscore", str(cm.exception)) - - def test_id_short_constraint_aasd_001(self): - test_object = ExampleIdentifiable() - test_object.id_short = None - self.assertEqual(None, test_object.id_short) + self.assertEqual( + "The id_short must contain only letters, digits and underscore (Constraint AASd-002)", + str(cm.exception)) def test_representation(self): class DummyClass: @@ -167,6 +150,7 @@ def __init__(self, value: model.Referable): ref = ExampleReferable() test_object = DummyClass(ref) + ref.id_short = "NotNone" ref.parent = test_object with self.assertRaises(AttributeError) as cm: ref.__repr__() @@ -281,7 +265,7 @@ def test_update_from(self): self.assertEqual("NewRelElCat", example_relel.category) # References to Referable objects shall remain stable self.assertIs(example_relel, example_submodel.get_referable('ExampleRelationshipElement')) - self.assertIs(example_relel, example_submodel.submodel_element.get('ExampleRelationshipElement')) + self.assertIs(example_relel, example_submodel.submodel_element.get("id_short", 'ExampleRelationshipElement')) # Check Namespace & parent consistency self.assertIs(example_submodel.namespace_element_sets[0], example_submodel.submodel_element) self.assertIs(example_relel.parent, example_submodel) @@ -297,40 +281,140 @@ def test_update_from(self): # Sources of embedded objects should always be updated self.assertEqual("scheme:NewRelElSource", example_relel.source) + def test_update_commit_qualifier_extension_semantic_id(self): + submodel = model.Submodel("https://acplt.org/Test_Submodel") + submodel.update() + qualifier = model.Qualifier("test", model.datatypes.String) + extension = model.Extension("test") + collection = model.SubmodelElementCollection("test") + property = model.MultiLanguageProperty("test") + + collection.add_referable(property) + submodel.add_qualifier(qualifier) + submodel.add_extension(extension) + submodel.add_referable(collection) + submodel.commit() + + self.assertEqual(next(iter(submodel.qualifier)), qualifier) + self.assertEqual(next(iter(submodel.extension)), extension) + self.assertEqual(next(iter(submodel.submodel_element)), collection) + self.assertEqual(next(iter(collection.value)), property) + + submodel.get_qualifier_by_type("test") + submodel.get_extension_by_name("test") + collection_ = submodel.get_referable("test") + self.assertIsInstance(collection_, model.UniqueIdShortNamespace) + assert isinstance(collection_, model.UniqueIdShortNamespace) + collection_.get_referable("test") + + submodel.remove_qualifier_by_type("test") + submodel.remove_extension_by_name("test") + submodel.remove_referable("test") + collection_.remove_referable("test") + + with self.assertRaises(StopIteration): + next(iter(submodel.qualifier)) + with self.assertRaises(StopIteration): + next(iter(submodel.extension)) + with self.assertRaises(StopIteration): + next(iter(submodel.submodel_element)) + with self.assertRaises(StopIteration): + next(iter(collection.value)) + submodel.commit() + + +class ExampleNamespaceReferable(model.UniqueIdShortNamespace, model.UniqueSemanticIdNamespace): + def __init__(self, values=()): + super().__init__() + self.set1 = model.NamespaceSet(self, [("id_short", False), ("semantic_id", True)]) + self.set2 = model.NamespaceSet(self, [("id_short", False)], values) + self.set3 = model.NamespaceSet(self, [("name", True)]) + self.set4 = model.NamespaceSet(self, [("type", True)]) -class ExampleNamespace(model.Namespace): + +class ExampleNamespaceQualifier(model.Qualifiable): def __init__(self, values=()): super().__init__() - self.set1 = model.NamespaceSet(self, values) - self.set2 = model.NamespaceSet(self) + self.set1 = model.NamespaceSet(self, [("type", False)], values) class ModelNamespaceTest(unittest.TestCase): - _namespace_class = ExampleNamespace + _namespace_class = ExampleNamespaceReferable + _namespace_class_qualifier = ExampleNamespaceQualifier def setUp(self): - self.prop1 = model.Property("Prop1", model.datatypes.Int) - self.prop2 = model.Property("Prop2", model.datatypes.Int) - self.prop1alt = model.Property("Prop1", model.datatypes.Int) + self.propSemanticID = model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Test1'),)) + self.propSemanticID2 = model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Test2'),)) + self.propSemanticID3 = model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, + value='http://acplt.org/Test3'),)) + self.prop1 = model.Property("Prop1", model.datatypes.Int, semantic_id=self.propSemanticID) + self.prop2 = model.Property("Prop2", model.datatypes.Int, semantic_id=self.propSemanticID) + self.prop3 = model.Property("Prop2", model.datatypes.Int, semantic_id=self.propSemanticID2) + self.prop4 = model.Property("Prop3", model.datatypes.Int, semantic_id=self.propSemanticID) + self.prop5 = model.Property("Prop3", model.datatypes.Int, semantic_id=self.propSemanticID2) + self.prop6 = model.Property("Prop4", model.datatypes.Int, semantic_id=self.propSemanticID2) + self.prop7 = model.Property("Prop2", model.datatypes.Int, semantic_id=self.propSemanticID3) + self.prop8 = model.Property("ProP2", model.datatypes.Int, semantic_id=self.propSemanticID3) + self.prop1alt = model.Property("Prop1", model.datatypes.Int, semantic_id=self.propSemanticID) + self.qualifier1 = model.Qualifier("type1", model.datatypes.Int, 1, semantic_id=self.propSemanticID) + self.qualifier2 = model.Qualifier("type2", model.datatypes.Int, 1, semantic_id=self.propSemanticID2) + self.qualifier1alt = model.Qualifier("type1", model.datatypes.Int, 1, semantic_id=self.propSemanticID) + self.extension1 = model.Extension("Ext1", model.datatypes.Int, 1, semantic_id=self.propSemanticID) + self.extension2 = model.Extension("Ext2", model.datatypes.Int, 1, semantic_id=self.propSemanticID2) self.namespace = self._namespace_class() + self.namespace3 = self._namespace_class_qualifier() def test_NamespaceSet(self) -> None: self.namespace.set1.add(self.prop1) - self.namespace.set1.add(self.prop2) - self.assertEqual(2, len(self.namespace.set1)) - self.assertIs(self.prop1, self.namespace.set1.get("Prop1")) + self.assertEqual(1, len(self.namespace.set1)) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set1.add(self.prop2) + self.assertEqual( + "Object with attribute (name='semantic_id', value='ExternalReference(key=(Key(" + "type=GLOBAL_REFERENCE, value=http://acplt.org/Test1),))') is already present in this set of objects " + "(Constraint AASd-000)", + str(cm.exception)) + self.namespace.set2.add(self.prop5) + self.namespace.set2.add(self.prop6) + self.assertEqual(2, len(self.namespace.set2)) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set2.add(self.prop1) + self.assertEqual("Object with attribute (name='id_short', value='Prop1') is already present in another " + "set in the same namespace (Constraint AASd-022)", + str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set2.add(self.prop4) + self.assertEqual( + "Object with attribute (name='semantic_id', value='" + "ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=http://acplt.org/Test1),))')" + " is already present in another set in the same namespace (Constraint AASd-000)", + str(cm.exception)) + + self.assertIs(self.prop1, self.namespace.set1.get("id_short", "Prop1")) self.assertIn(self.prop1, self.namespace.set1) self.assertNotIn(self.prop1alt, self.namespace.set1) self.assertIs(self.namespace, self.prop1.parent) - with self.assertRaises(KeyError) as cm: + self.assertIs(self.prop5, self.namespace.set2.get("id_short", "Prop3")) + + with self.assertRaises(model.AASConstraintViolation) as cm: self.namespace.set1.add(self.prop1alt) - self.assertEqual('"Referable with id_short \'Prop1\' is already present in this set of objects"', + self.assertEqual("Object with attribute (name='id_short', value='Prop1') is already present in this set of" + " objects (Constraint AASd-022)", str(cm.exception)) - with self.assertRaises(KeyError) as cm: - self.namespace.set2.add(self.prop2) - self.assertEqual('"Referable with id_short \'Prop2\' is already present in another set in the same namespace"', + self.namespace.set1.add(self.prop3) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set1.add(self.prop7) + self.assertEqual("Object with attribute (name='id_short', value='Prop2') is already present in this set " + "of objects (Constraint AASd-022)", + str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set1.add(self.prop8) + self.assertEqual("Object with attribute (name='id_short', value='ProP2') is already present in this set " + "of objects (Constraint AASd-022)", str(cm.exception)) namespace2 = self._namespace_class() @@ -338,94 +422,262 @@ def test_NamespaceSet(self) -> None: namespace2.set1.add(self.prop1) self.assertIn('has already a parent', str(cm2.exception)) + self.assertEqual(2, len(self.namespace.set1)) self.namespace.set1.remove(self.prop1) self.assertEqual(1, len(self.namespace.set1)) self.assertIsNone(self.prop1.parent) - self.namespace.set2.add(self.prop1alt) + self.namespace.set1.add(self.prop1) + self.assertEqual(2, len(self.namespace.set1)) + self.namespace.set1.remove_by_id("id_short", self.prop1.id_short) + self.assertEqual(1, len(self.namespace.set1)) + self.assertIsNone(self.prop1.parent) - self.assertIs(self.prop2, self.namespace.set1.pop()) - self.assertEqual(0, len(self.namespace.set1)) + self.assertEqual(2, len(self.namespace.set2)) + self.assertIs(self.prop6, self.namespace.set2.pop()) + self.assertEqual(1, len(self.namespace.set2)) + self.namespace.set2.add(self.prop1alt) self.namespace.set2.clear() self.assertIsNone(self.prop1alt.parent) self.assertEqual(0, len(self.namespace.set2)) + self.assertEqual(1, len(self.namespace.set1)) self.namespace.set1.add(self.prop1) + self.assertEqual(2, len(self.namespace.set1)) self.namespace.set1.discard(self.prop1) - self.assertEqual(0, len(self.namespace.set1)) + self.assertEqual(1, len(self.namespace.set1)) self.assertIsNone(self.prop1.parent) self.namespace.set1.discard(self.prop1) + self.namespace3.set1.add(self.qualifier1) + self.assertEqual(1, len(self.namespace3.set1)) + self.namespace3.set1.add(self.qualifier2) + self.assertEqual(2, len(self.namespace3.set1)) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace3.set1.add(self.qualifier1alt) + self.assertEqual("Object with attribute (name='type', value='type1') is already present in this set " + "of objects (Constraint AASd-021)", + str(cm.exception)) + + def test_namespaceset_hooks(self) -> None: + T = TypeVar("T", bound=model.Referable) + nss_types: List[Type[model.NamespaceSet]] = [model.NamespaceSet, model.OrderedNamespaceSet] + for nss_type in nss_types: + new_item = None + old_item = None + existing_items = [] + + class DummyNamespace(model.UniqueIdShortNamespace): + def __init__(self, items: Iterable[T], item_add_hook: Optional[Callable[[T, Iterable[T]], None]] = None, + item_id_set_hook: Optional[Callable[[T], None]] = None, + item_id_del_hook: Optional[Callable[[T], None]] = None): + super().__init__() + self.set1 = nss_type(self, [('id_short', True)], items, item_add_hook=item_add_hook, + item_id_set_hook=item_id_set_hook, + item_id_del_hook=item_id_del_hook) + + def add_hook(new: T, existing: Iterable[T]) -> None: + nonlocal new_item, existing_items + new_item = new + # Create a new list to prevent an error when checking the assertions: + # RuntimeError: dictionary changed size during iteration + existing_items = list(existing) + + def id_set_hook(new: T) -> None: + if new.id_short is not None: + new.id_short += "new" + + def id_del_hook(old: T) -> None: + nonlocal old_item + old_item = old + if old.id_short is not None: + # remove "new" suffix + old.id_short = old.id_short[:-3] + + cap = model.Capability("test_cap") + dummy_ns = DummyNamespace({cap}, item_add_hook=add_hook, item_id_set_hook=id_set_hook, + item_id_del_hook=id_del_hook) + self.assertEqual(cap.id_short, "test_capnew") + self.assertIs(new_item, cap) + self.assertEqual(len(existing_items), 0) + + mlp = model.MultiLanguageProperty("test_mlp") + dummy_ns.add_referable(mlp) + self.assertEqual(mlp.id_short, "test_mlpnew") + self.assertIs(new_item, mlp) + self.assertEqual(len(existing_items), 1) + self.assertIn(cap, existing_items) + + prop = model.Property("test_prop", model.datatypes.Int) + dummy_ns.set1.add(prop) + self.assertEqual(prop.id_short, "test_propnew") + self.assertIs(new_item, prop) + self.assertEqual(len(existing_items), 2) + self.assertIn(cap, existing_items) + self.assertIn(mlp, existing_items) + + dummy_ns.remove_referable("test_capnew") + self.assertIs(old_item, cap) + self.assertEqual(cap.id_short, "test_cap") + + dummy_ns.set1.remove(prop) + self.assertIs(old_item, prop) + self.assertEqual(prop.id_short, "test_prop") + + dummy_ns.set1.remove_by_id("id_short", "test_mlpnew") + self.assertIs(old_item, mlp) + self.assertEqual(mlp.id_short, "test_mlp") + + self.assertEqual(len(list(dummy_ns)), 0) + + # test atomicity + add_hook_counter: int = 0 + + def add_hook_constraint(_new: T, _existing: Iterable[T]) -> None: + nonlocal add_hook_counter + add_hook_counter += 1 + if add_hook_counter > 1: + raise ValueError + + self.assertEqual(cap.id_short, "test_cap") + self.assertEqual(mlp.id_short, "test_mlp") + with self.assertRaises(ValueError): + DummyNamespace([cap, mlp], item_add_hook=add_hook_constraint, item_id_set_hook=id_set_hook, + item_id_del_hook=id_del_hook) + self.assertEqual(cap.id_short, "test_cap") + self.assertIsNone(cap.parent) + self.assertEqual(mlp.id_short, "test_mlp") + self.assertIsNone(mlp.parent) + + dummy_ns = DummyNamespace((), item_add_hook=add_hook_constraint, item_id_set_hook=id_set_hook, + item_id_del_hook=id_del_hook) + add_hook_counter = 0 + dummy_ns.add_referable(cap) + self.assertIs(cap.parent, dummy_ns) + + with self.assertRaises(ValueError): + dummy_ns.set1.add(prop) + self.assertEqual(prop.id_short, "test_prop") + self.assertIsNone(prop.parent) + def test_Namespace(self) -> None: - with self.assertRaises(KeyError) as cm: - namespace_test = ExampleNamespace([self.prop1, self.prop2, self.prop1alt]) - self.assertEqual('"Referable with id_short \'Prop1\' is already present in this set of objects"', + with self.assertRaises(model.AASConstraintViolation) as cm: + namespace_test = ExampleNamespaceReferable([self.prop1, self.prop2, self.prop1alt]) + self.assertEqual("Object with attribute (name='id_short', value='Prop1') is already present in this set " + "of objects (Constraint AASd-022)", str(cm.exception)) self.assertIsNone(self.prop1.parent) namespace = self._namespace_class([self.prop1, self.prop2]) self.assertIs(self.prop2, namespace.get_referable("Prop2")) - with self.assertRaises(KeyError) as cm: + with self.assertRaises(KeyError) as cm2: namespace.get_referable("Prop3") - self.assertEqual("'Referable with id_short Prop3 not found in this namespace'", str(cm.exception)) + self.assertEqual("'Referable with id_short Prop3 not found in this namespace'", + str(cm2.exception)) namespace.remove_referable("Prop2") - with self.assertRaises(KeyError) as cm2: + with self.assertRaises(KeyError) as cm3: namespace.get_referable("Prop2") - self.assertEqual("'Referable with id_short Prop2 not found in this namespace'", str(cm2.exception)) + self.assertEqual("'Referable with id_short Prop2 not found in this namespace'", str(cm3.exception)) - with self.assertRaises(KeyError) as cm3: + with self.assertRaises(KeyError) as cm4: namespace.remove_referable("Prop2") - self.assertEqual("'Referable with id_short Prop2 not found in this namespace'", str(cm3.exception)) + self.assertEqual("'Referable with id_short Prop2 not found in this namespace'", str(cm4.exception)) def test_renaming(self) -> None: - self.namespace.set1.add(self.prop1) - self.namespace.set1.add(self.prop2) + self.namespace.set2.add(self.prop1) + self.namespace.set2.add(self.prop2) + self.assertIs(self.prop1, self.namespace.get_referable("Prop1")) + self.assertIs(self.prop2, self.namespace.get_referable("Prop2")) self.prop1.id_short = "Prop3" self.assertEqual("Prop3", self.prop1.id_short) - self.assertIs(self.prop1, self.namespace.get_referable('Prop3')) - with self.assertRaises(KeyError): + self.assertEqual(2, len(self.namespace.set2)) + self.assertIs(self.prop1, self.namespace.get_referable("Prop3")) + with self.assertRaises(KeyError) as cm: self.namespace.get_referable('Prop1') + self.assertEqual("'Referable with id_short Prop1 not found in this namespace'", + str(cm.exception)) + self.assertIs(self.prop2, self.namespace.get_referable("Prop2")) + with self.assertRaises(model.AASConstraintViolation) as cm2: + self.prop1.id_short = "Prop2" + self.assertIn("already present", str(cm2.exception)) + self.namespace.set3.add(self.extension1) + self.namespace.set3.add(self.extension2) with self.assertRaises(KeyError) as cm: - self.prop1.id_short = "Prop2" + self.extension1.name = "Ext2" self.assertIn("already present", str(cm.exception)) + self.extension1.name = "Ext3" + self.assertEqual(self.extension1.name, "Ext3") + + self.namespace.set4.add(self.qualifier1) + self.namespace.set4.add(self.qualifier2) + with self.assertRaises(KeyError) as cm: + self.qualifier1.type = "type2" + self.assertIn("already present", str(cm.exception)) + self.qualifier1.type = "type3" + self.assertEqual(self.qualifier1.type, "type3") def test_Namespaceset_update_from(self) -> None: # Prop1 is getting its value updated by namespace2.set1 # Prop2 is getting deleted since it does not exist in namespace2.set1 # Prop3 is getting added, since it does not exist in namespace1.set1 yet namespace1 = self._namespace_class() - prop1 = model.Property("Prop1", model.datatypes.Int, 1) - prop2 = model.Property("Prop2", model.datatypes.Int, 0) - namespace1.set1.add(prop1) - namespace1.set1.add(prop2) + prop1 = model.Property("Prop1", model.datatypes.Int, 1, semantic_id=self.propSemanticID) + prop2 = model.Property("Prop2", model.datatypes.Int, 0, semantic_id=self.propSemanticID2) + namespace1.set2.add(prop1) + namespace1.set2.add(prop2) namespace2 = self._namespace_class() - namespace2.set1.add(model.Property("Prop1", model.datatypes.Int, 0)) - namespace2.set1.add(model.Property("Prop3", model.datatypes.Int, 2)) - namespace1.set1.update_nss_from(namespace2.set1) + namespace2.set2.add(model.Property("Prop1", model.datatypes.Int, 0, semantic_id=self.propSemanticID)) + namespace2.set2.add(model.Property("Prop3", model.datatypes.Int, 2, semantic_id=self.propSemanticID2)) + namespace1.set2.update_nss_from(namespace2.set2) # Check that Prop1 got updated correctly self.assertIs(namespace1.get_referable("Prop1"), prop1) self.assertEqual(prop1.value, 0) self.assertIs(namespace1.get_referable("Prop1").parent, namespace1) # Check that Prop3 got added correctly - prop3_new = namespace1.set1.get_referable("Prop3") + prop3_new = namespace1.set2.get_object_by_attribute("id_short", "Prop3") self.assertIs(prop3_new.parent, namespace1) assert isinstance(prop3_new, model.Property) self.assertEqual(prop3_new.value, 2) # Check that Prop2 got removed correctly - self.assertNotIn("Prop2", namespace1.set1) + self.assertFalse(namespace1.set2.contains_id("id_short", "Prop2")) with self.assertRaises(KeyError): namespace1.get_referable("Prop2") self.assertIsNone(prop2.parent) - -class ExampleOrderedNamespace(model.Namespace): + def test_qualifiable_id_short_namespace(self) -> None: + prop1 = model.Property("Prop1", model.datatypes.Int, 1) + qualifier1 = model.Qualifier("Qualifier1", model.datatypes.Int, 2) + submodel_element_collection = model.SubmodelElementCollection("test_SMC", [prop1], + qualifier=[qualifier1]) + self.assertIs(submodel_element_collection.get_referable("Prop1"), prop1) + self.assertIs(submodel_element_collection.get_qualifier_by_type("Qualifier1"), qualifier1) + + def test_aasd_117(self) -> None: + property = model.Property(None, model.datatypes.Int, semantic_id=self.propSemanticID) + se_collection = model.SubmodelElementCollection("foo") + with self.assertRaises(model.AASConstraintViolation) as cm: + se_collection.add_referable(property) + self.assertEqual("Property has attribute id_short=None, which is not allowed within a " + "SubmodelElementCollection! (Constraint AASd-117)", str(cm.exception)) + property.id_short = "property" + se_collection.add_referable(property) + with self.assertRaises(model.AASConstraintViolation) as cm: + property.id_short = None + self.assertEqual("id_short of Property[foo / property] cannot be unset, since it is already contained in " + "SubmodelElementCollection[foo] (Constraint AASd-117)", str(cm.exception)) + property.id_short = "bar" + + +class ExampleOrderedNamespace(model.UniqueIdShortNamespace, model.UniqueSemanticIdNamespace): def __init__(self, values=()): super().__init__() - self.set1 = model.OrderedNamespaceSet(self, values) - self.set2 = model.OrderedNamespaceSet(self) + self.set1 = model.OrderedNamespaceSet(self, [("id_short", False), ("semantic_id", True)]) + self.set2 = model.OrderedNamespaceSet(self, [("id_short", False)], values) + self.set3 = model.NamespaceSet(self, [("name", True)]) + self.set4 = model.NamespaceSet(self, [("type", True)]) class ModelOrderedNamespaceTest(ModelNamespaceTest): @@ -434,230 +686,338 @@ class ModelOrderedNamespaceTest(ModelNamespaceTest): def test_OrderedNamespace(self) -> None: # Tests from ModelNamespaceTest are inherited, but with ExampleOrderedNamespace instead of ExampleNamespace # So, we only need to test order-related things here - self.namespace.set1.add(self.prop1) - self.namespace.set1.insert(0, self.prop2) - with self.assertRaises(KeyError) as cm: - self.namespace.set2.insert(0, self.prop1alt) - self.assertEqual('"Referable with id_short \'Prop1\' is already present in another set in the same namespace"', + self.namespace.set2.add(self.prop1) + self.assertEqual(1, len(self.namespace.set2)) + self.namespace.set2.insert(0, self.prop2) + self.assertEqual(2, len(self.namespace.set2)) + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set1.insert(0, self.prop1alt) + self.assertEqual('Object with attribute (name=\'id_short\', value=\'Prop1\') is already present in another ' + 'set in the same namespace (Constraint AASd-022)', str(cm.exception)) - self.assertEqual((self.prop2, self.prop1), tuple(self.namespace.set1)) - self.assertEqual(self.prop1, self.namespace.set1[1]) + self.assertEqual((self.prop2, self.prop1), tuple(self.namespace.set2)) + self.assertEqual(self.prop1, self.namespace.set2[1]) - with self.assertRaises(KeyError) as cm: - self.namespace.set1[1] = self.prop2 - self.assertEqual('"Referable with id_short \'Prop2\' is already present in this set of objects"', + with self.assertRaises(model.AASConstraintViolation) as cm: + self.namespace.set2[1] = self.prop2 + self.assertEqual('Object with attribute (name=\'id_short\', value=\'Prop2\') is already present in this ' + 'set of objects (Constraint AASd-022)', str(cm.exception)) - prop3 = model.Property("Prop3", model.datatypes.Int) - self.namespace.set1[1] = prop3 - self.assertEqual(2, len(self.namespace.set1)) + prop3 = model.Property("Prop3", model.datatypes.Int, semantic_id=self.propSemanticID3) + self.assertEqual(2, len(self.namespace.set2)) + self.namespace.set2[1] = prop3 + self.assertEqual(2, len(self.namespace.set2)) self.assertIsNone(self.prop1.parent) self.assertIs(self.namespace, prop3.parent) - self.assertEqual((self.prop2, prop3), tuple(self.namespace.set1)) + self.assertEqual((self.prop2, prop3), tuple(self.namespace.set2)) - del self.namespace.set1[0] + del self.namespace.set2[0] self.assertIsNone(self.prop2.parent) - self.assertEqual(1, len(self.namespace.set1)) + self.assertEqual(1, len(self.namespace.set2)) namespace2 = ExampleOrderedNamespace() - namespace2.set1.add(self.prop1) - namespace2.set1.get_referable('Prop1') - namespace2.set1.remove('Prop1') - with self.assertRaises(KeyError) as cm: - namespace2.set1.get_referable('Prop1') - self.assertEqual("'Prop1'", str(cm.exception)) + namespace2.set2.add(self.prop1) + namespace2.set2.add(self.prop5) + self.assertEqual(2, len(namespace2.set2)) + self.assertIs(self.prop1, namespace2.set2.get("id_short", "Prop1")) + namespace2.set2.remove(("id_short", "Prop1")) + self.assertEqual(1, len(namespace2.set2)) + with self.assertRaises(KeyError) as cm2: + namespace2.get_referable("Prop1") + self.assertEqual("'Referable with id_short Prop1 not found in this namespace'", + str(cm2.exception)) + +class ExternalReferenceTest(unittest.TestCase): + def test_constraints(self): + with self.assertRaises(ValueError) as cm: + model.ExternalReference(tuple()) + self.assertEqual("A reference must have at least one key!", str(cm.exception)) + + # AASd-122 + keys = (model.Key(model.KeyTypes.PROPERTY, "urn:x-test:x"),) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ExternalReference(keys) + self.assertEqual("The type of the first key of an ExternalReference must be a GenericGloballyIdentifiable: " + f"{keys[0]!r} (Constraint AASd-122)", str(cm.exception)) + model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:x"),)) + + # AASd-124 + keys = (model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:x"), + model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"),) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ExternalReference(keys) + self.assertEqual("The type of the last key of an ExternalReference must be a GenericGloballyIdentifiable or a" + f" GenericFragmentKey: {keys[-1]!r} (Constraint AASd-124)", str(cm.exception)) + keys += (model.Key(model.KeyTypes.FRAGMENT_REFERENCE, "urn:x-test:x"),) + model.ExternalReference(keys) + + +class ModelReferenceTest(unittest.TestCase): + def test_constraints(self): + with self.assertRaises(ValueError) as cm: + model.ExternalReference(tuple()) + self.assertEqual("A reference must have at least one key!", str(cm.exception)) + + # AASd-123 + keys = (model.Key(model.KeyTypes.PROPERTY, "urn:x-test:x"),) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ModelReference(keys, model.Property) + self.assertEqual(f"The type of the first key of a ModelReference must be an AasIdentifiable: {keys[0]!r}" + " (Constraint AASd-123)", str(cm.exception)) + keys = (model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"),) + keys + model.ModelReference(keys, model.Property) + + # AASd-125 + keys = (model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.ASSET_ADMINISTRATION_SHELL, "urn:x-test:x"), + model.Key(model.KeyTypes.CONCEPT_DESCRIPTION, "urn:x-test:x")) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ModelReference(keys, model.ConceptDescription) + self.assertEqual("The type of all keys following the first of a ModelReference " + f"must be one of FragmentKeyElements: {keys[1]!r} (Constraint AASd-125)", str(cm.exception)) + keys = (keys[0], model.Key(model.KeyTypes.FILE, "urn:x-test:x"), keys[2]) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ModelReference(keys, model.ConceptDescription) + self.assertEqual("The type of all keys following the first of a ModelReference " + f"must be one of FragmentKeyElements: {keys[2]!r} (Constraint AASd-125)", str(cm.exception)) + keys = tuple(keys[:2]) + (model.Key(model.KeyTypes.FRAGMENT_REFERENCE, "urn:x-test:x"),) + model.ModelReference(keys, model.ConceptDescription) + + # AASd-126 + keys = (model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.FILE, "urn:x-test:x"), + model.Key(model.KeyTypes.FRAGMENT_REFERENCE, "urn:x-test:x"), + model.Key(model.KeyTypes.PROPERTY, "urn:x-test:x")) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ModelReference(keys, model.Property) + self.assertEqual(f"Key {keys[2]!r} is a GenericFragmentKey, but the last key of the chain is not: {keys[-1]!r}" + " (Constraint AASd-126)", str(cm.exception)) + keys = tuple(keys[:3]) + model.ModelReference(keys, model.File) + + # AASd-127 + keys = (model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.PROPERTY, "urn:x-test:x"), + model.Key(model.KeyTypes.FRAGMENT_REFERENCE, "urn:x-test:x")) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ModelReference(keys, model.Property) + self.assertEqual(f"{keys[-1]!r} is not preceeded by a key of type File or Blob, but {keys[1]!r}" + f" (Constraint AASd-127)", str(cm.exception)) + keys = (keys[0], model.Key(model.KeyTypes.BLOB, "urn:x-test:x"), keys[2]) + model.ModelReference(keys, model.Blob) + + # AASd-128 + keys = (model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_LIST, "urn:x-test:x")) + for invalid_key_value in ("string", "-5", "5.5", "5,5", "+5"): + invalid_key = model.Key(model.KeyTypes.PROPERTY, invalid_key_value) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.ModelReference(keys + (invalid_key,), model.Property) + self.assertEqual(f"Key {keys[1]!r} references a SubmodelElementList, but the value of the succeeding key " + f"({invalid_key!r}) is not a non-negative integer: {invalid_key.value} " + "(Constraint AASd-128)", + str(cm.exception)) + keys = keys[:1] + (model.Key(model.KeyTypes.PROPERTY, "5"),) + model.ModelReference(keys, model.Property) -class AASReferenceTest(unittest.TestCase): def test_set_reference(self): - ref = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI),), - model.Submodel) + ref = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"),), model.Submodel) with self.assertRaises(AttributeError) as cm: ref.type = model.Property self.assertEqual('Reference is immutable', str(cm.exception)) with self.assertRaises(AttributeError) as cm: - ref.key = model.Key(model.KeyElements.PROPERTY, False, "urn:x-test:x", model.KeyType.IRI) + ref.key = model.Key(model.KeyTypes.PROPERTY, "urn:x-test:x") self.assertEqual('Reference is immutable', str(cm.exception)) with self.assertRaises(AttributeError) as cm: ref.key = () self.assertEqual('Reference is immutable', str(cm.exception)) + with self.assertRaises(AttributeError) as cm: + ref.referred_semantic_id = model.ExternalReference( + (model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:x"),)) + self.assertEqual('Reference is immutable', str(cm.exception)) def test_equality(self): - ref = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI),), - model.Submodel) - ident = model.Identifier('test', model.IdentifierType.CUSTOM) - self.assertEqual(ref.__eq__(ident), NotImplemented) - ref_2 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI), - model.Key(model.KeyElements.PROPERTY, False, "test", model.KeyType.IRI)), + ref = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"),), model.Submodel) - self.assertFalse(ref == ref_2) + ident = 'test' + self.assertEqual(ref.__eq__(ident), NotImplemented) + ref_2 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.PROPERTY, "test")), + model.Submodel) + self.assertNotEqual(ref, ref_2) + ref_3 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.PROPERTY, "test")), + model.Submodel) + self.assertEqual(ref_2, ref_3) + referred_semantic_id = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:x"),)) + object.__setattr__(ref_2, 'referred_semantic_id', referred_semantic_id) + self.assertNotEqual(ref_2, ref_3) + object.__setattr__(ref_3, 'referred_semantic_id', referred_semantic_id) + self.assertEqual(ref_2, ref_3) def test_reference_typing(self) -> None: - dummy_submodel = model.Submodel(model.Identifier("urn:x-test:x", model.IdentifierType.IRI)) + dummy_submodel = model.Submodel("urn:x-test:x") class DummyObjectProvider(model.AbstractObjectProvider): def get_identifiable(self, identifier: Identifier) -> Identifiable: return dummy_submodel - x = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI),), - model.Submodel) + x = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"),), model.Submodel) submodel: model.Submodel = x.resolve(DummyObjectProvider()) self.assertIs(submodel, submodel) def test_resolve(self) -> None: prop = model.Property("prop", model.datatypes.Int) - collection = model.SubmodelElementCollectionUnordered("collection", {prop}) - prop.parent = collection - submodel = model.Submodel(model.Identifier("urn:x-test:submodel", model.IdentifierType.IRI), {collection}) - collection.parent = submodel + collection = model.SubmodelElementCollection(None, {prop}) + list_ = model.SubmodelElementList("list", model.SubmodelElementCollection, {collection}) + submodel = model.Submodel("urn:x-test:submodel", {list_}) class DummyObjectProvider(model.AbstractObjectProvider): def get_identifiable(self, identifier: Identifier) -> Identifiable: - if identifier == submodel.identification: + if identifier == submodel.id: return submodel else: raise KeyError() - ref1 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel", - model.KeyType.IRI), - model.Key(model.KeyElements.SUBMODEL_ELEMENT_COLLECTION, False, "collection", - model.KeyType.IDSHORT), - model.Key(model.KeyElements.PROPERTY, False, "prop", model.KeyType.IDSHORT)), - model.Property) - self.assertIs(prop, ref1.resolve(DummyObjectProvider())) - - ref2 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel", - model.KeyType.IRI), - model.Key(model.KeyElements.SUBMODEL_ELEMENT_COLLECTION, False, "collection", - model.KeyType.IDSHORT), - model.Key(model.KeyElements.PROPERTY, False, "prop", model.KeyType.IDSHORT), - model.Key(model.KeyElements.PROPERTY, False, "prop", model.KeyType.IDSHORT)), - model.Property) - with self.assertRaises(TypeError) as cm: + ref1 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_LIST, "lst"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION, "99"), + model.Key(model.KeyTypes.PROPERTY, "prop")), + model.Property) + with self.assertRaises(KeyError) as cm: + ref1.resolve(DummyObjectProvider()) + self.assertEqual("'Could not resolve id_short lst at urn:x-test:submodel'", str(cm.exception)) + + ref2 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_LIST, "list"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION, "99"), + model.Key(model.KeyTypes.PROPERTY, "prop")), + model.Property) + with self.assertRaises(KeyError) as cm_2: ref2.resolve(DummyObjectProvider()) - self.assertEqual("Object retrieved at Identifier(IRI=urn:x-test:submodel) / collection / prop is not a " - "Namespace", str(cm.exception)) + self.assertEqual("'Could not resolve index 99 at urn:x-test:submodel / list'", str(cm_2.exception)) + + ref3 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_LIST, "list"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION, "0"), + model.Key(model.KeyTypes.PROPERTY, "prop")), + model.Property) + self.assertIs(prop, ref3.resolve(DummyObjectProvider())) + + ref4 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_LIST, "list"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION, "0"), + model.Key(model.KeyTypes.PROPERTY, "prop"), + model.Key(model.KeyTypes.PROPERTY, "prop")), + model.Property) + with self.assertRaises(TypeError) as cm_3: + ref4.resolve(DummyObjectProvider()) + self.assertEqual("Object retrieved at urn:x-test:submodel / list[0] / prop is not a Namespace", + str(cm_3.exception)) - with self.assertRaises(AttributeError) as cm_2: + with self.assertRaises(AttributeError) as cm_4: ref1.key[2].value = "prop1" - self.assertEqual("Reference is immutable", str(cm_2.exception)) + self.assertEqual("Reference is immutable", str(cm_4.exception)) - ref3 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:sub", model.KeyType.IRI),), - model.Property) + ref5 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:sub"),), model.Property) # Oh no, yet another typo! - with self.assertRaises(KeyError) as cm_3: - ref3.resolve(DummyObjectProvider()) - self.assertEqual("'Could not resolve global reference key Identifier(IRI=urn:x-test:sub)'", str(cm_3.exception)) - - ref4 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel", - model.KeyType.IRI),), - model.Property) - # Okay, typo is fixed, but the type is not what we expect. However, we should get the the submodel via the + with self.assertRaises(KeyError) as cm_5: + ref5.resolve(DummyObjectProvider()) + self.assertEqual("'Could not resolve identifier urn:x-test:sub'", str(cm_5.exception)) + + ref6 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel"),), model.Property) + # Okay, typo is fixed, but the type is not what we expect. However, we should get the submodel via the # exception's value attribute - with self.assertRaises(model.UnexpectedTypeError) as cm_4: - ref4.resolve(DummyObjectProvider()) - self.assertIs(submodel, cm_4.exception.value) + with self.assertRaises(model.UnexpectedTypeError) as cm_6: + ref6.resolve(DummyObjectProvider()) + self.assertIs(submodel, cm_6.exception.value) - with self.assertRaises(ValueError) as cm_5: - ref5 = model.AASReference((), model.Submodel) - self.assertEqual('A reference must have at least one key!', str(cm_5.exception)) + with self.assertRaises(ValueError) as cm_7: + ref7 = model.ModelReference((), model.Submodel) + self.assertEqual('A reference must have at least one key!', str(cm_7.exception)) - ref6 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:submodel", - model.KeyType.IRI), - model.Key(model.KeyElements.SUBMODEL_ELEMENT_COLLECTION, False, "collection", - model.KeyType.IDSHORT), - model.Key(model.KeyElements.PROPERTY, False, "prop_false", - model.KeyType.IDSHORT)), model.Property) + ref8 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:submodel"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_LIST, "list"), + model.Key(model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION, "0"), + model.Key(model.KeyTypes.PROPERTY, "prop_false")), model.Property) - with self.assertRaises(KeyError) as cm_6: - ref6.resolve(DummyObjectProvider()) - self.assertEqual("'Could not resolve id_short prop_false at Identifier(IRI=urn:x-test:submodel) / collection'", - str(cm_6.exception)) + with self.assertRaises(KeyError) as cm_8: + ref8.resolve(DummyObjectProvider()) + self.assertEqual("'Could not resolve id_short prop_false at urn:x-test:submodel / list[0]'", + str(cm_8.exception)) + + with self.assertRaises(ValueError) as cm_9: + ref9 = model.ModelReference((), model.Submodel) + self.assertEqual('A reference must have at least one key!', str(cm_9.exception)) def test_get_identifier(self) -> None: - ref = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI),), - model.Submodel) - self.assertEqual(model.Identifier("urn:x-test:x", model.IdentifierType.IRI), ref.get_identifier()) - - ref2 = model.AASReference((model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI), - model.Key(model.KeyElements.PROPERTY, False, "myProperty", model.KeyType.IDSHORT),), - model.Submodel) - self.assertEqual(model.Identifier("urn:x-test:x", model.IdentifierType.IRI), ref.get_identifier()) - - # People will do strange things ... - ref3 = model.AASReference((model.Key(model.KeyElements.ASSET_ADMINISTRATION_SHELL, False, "urn:x-test-aas:x", - model.KeyType.IRI), - model.Key(model.KeyElements.SUBMODEL, False, "urn:x-test:x", model.KeyType.IRI),), - model.Submodel) - self.assertEqual(model.Identifier("urn:x-test:x", model.IdentifierType.IRI), ref2.get_identifier()) - - ref4 = model.AASReference((model.Key(model.KeyElements.PROPERTY, False, "myProperty", model.KeyType.IDSHORT),), - model.Property) - with self.assertRaises(ValueError): - ref4.get_identifier() + ref = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"),), model.Submodel) + self.assertEqual("urn:x-test:x", ref.get_identifier()) + + ref2 = model.ModelReference((model.Key(model.KeyTypes.SUBMODEL, "urn:x-test:x"), + model.Key(model.KeyTypes.PROPERTY, "myProperty"),), model.Submodel) + self.assertEqual("urn:x-test:x", ref2.get_identifier()) def test_from_referable(self) -> None: prop = model.Property("prop", model.datatypes.Int) - collection = model.SubmodelElementCollectionUnordered("collection", {prop}) + collection = model.SubmodelElementCollection("collection", {prop}) prop.parent = collection - submodel = model.Submodel(model.Identifier("urn:x-test:submodel", model.IdentifierType.IRI), {collection}) + submodel = model.Submodel("urn:x-test:submodel", {collection}) collection.parent = submodel # Test normal usage for Identifiable and Referable objects - ref1 = model.AASReference.from_referable(submodel) + ref1 = model.ModelReference.from_referable(submodel) self.assertEqual(1, len(ref1.key)) self.assertIs(ref1.type, model.Submodel) self.assertEqual("urn:x-test:submodel", ref1.key[0].value) - self.assertEqual(model.KeyType.IRI, ref1.key[0].id_type) - self.assertEqual(model.KeyElements.SUBMODEL, ref1.key[0].type) + self.assertEqual(model.KeyTypes.SUBMODEL, ref1.key[0].type) - ref2 = model.AASReference.from_referable(prop) + ref2 = model.ModelReference.from_referable(prop) self.assertEqual(3, len(ref2.key)) self.assertIs(ref2.type, model.Property) self.assertEqual("urn:x-test:submodel", ref2.key[0].value) - self.assertEqual(model.KeyType.IRI, ref2.key[0].id_type) self.assertEqual("prop", ref2.key[2].value) - self.assertEqual(model.KeyType.IDSHORT, ref2.key[2].id_type) - self.assertEqual(model.KeyElements.PROPERTY, ref2.key[2].type) + self.assertEqual(model.KeyTypes.PROPERTY, ref2.key[2].type) # Test exception for element without identifiable ancestor submodel.submodel_element.remove(collection) with self.assertRaises(ValueError) as cm: - ref3 = model.AASReference.from_referable(prop) + ref3 = model.ModelReference.from_referable(prop) self.assertEqual("The given Referable object is not embedded within an Identifiable object", str(cm.exception)) # Test creating a reference to a custom Referable class class DummyThing(model.Referable): - def __init__(self, id_short: str): + def __init__(self, id_short: model.NameType): super().__init__() self.id_short = id_short - class DummyIdentifyableNamespace(model.Identifiable, model.Namespace): - def __init__(self, identification: model.Identifier): - super().__init__() - self.identification = identification - self.things: model.NamespaceSet = model.NamespaceSet(self) + class DummyIdentifyableNamespace(model.Submodel, model.UniqueIdShortNamespace): + def __init__(self, id_: model.Identifier): + super().__init__(id_) + self.things: model.NamespaceSet = model.NamespaceSet(self, [("id_short", True)]) thing = DummyThing("thing") - identifable_thing = DummyIdentifyableNamespace(model.Identifier("urn:x-test:thing", model.IdentifierType.IRI)) + identifable_thing = DummyIdentifyableNamespace("urn:x-test:thing") identifable_thing.things.add(thing) - ref4 = model.AASReference.from_referable(thing) + ref4 = model.ModelReference.from_referable(thing) self.assertIs(ref4.type, model.Referable) class AdministrativeInformationTest(unittest.TestCase): def test_setting_version_revision(self) -> None: - with self.assertRaises(ValueError) as cm: - obj = model.AdministrativeInformation(revision='0.9') + with self.assertRaises(model.AASConstraintViolation) as cm: + obj = model.AdministrativeInformation(revision='9') self.assertEqual("A revision requires a version. This means, if there is no version there is no " - "revision neither.", str(cm.exception)) + "revision neither. Please set version first. (Constraint AASd-005)", str(cm.exception)) def test_setting_revision(self) -> None: obj = model.AdministrativeInformation() - with self.assertRaises(ValueError) as cm: - obj.revision = '0.3' + with self.assertRaises(model.AASConstraintViolation) as cm: + obj.revision = '3' self.assertEqual("A revision requires a version. This means, if there is no version there is no revision " - "neither. Please set version first.", str(cm.exception)) + "neither. Please set version first. (Constraint AASd-005)", str(cm.exception)) class QualifierTest(unittest.TestCase): @@ -668,13 +1028,269 @@ def test_set_value(self): self.assertIsNone(qualifier.value) +class ExtensionTest(unittest.TestCase): + def test_set_value(self): + extension = model.Extension('test', model.datatypes.Int, 2) + self.assertEqual(extension.value, 2) + extension.value = None + self.assertIsNone(extension.value) + extension2 = model.Extension('test') + with self.assertRaises(ValueError) as cm: + extension2.value = 2 + self.assertEqual("ValueType must be set, if value is not None", str(cm.exception)) + + class ValueReferencePairTest(unittest.TestCase): def test_set_value(self): - pair = model.ValueReferencePair(model.datatypes.Int, 2, model.Reference((model.Key( - model.KeyElements.GLOBAL_REFERENCE, False, 'test', model.KeyType.CUSTOM),))) - self.assertEqual(pair.value, 2) - with self.assertRaises(AttributeError) as cm: - pair.value = None - self.assertEqual('Value can not be None', str(cm.exception)) - pair.value = 3 - self.assertEqual(pair.value, 3) + pair = model.ValueReferencePair( + value="2", + value_id=model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, 'test'),))) + self.assertEqual(pair.value, "2") + pair.value = "3" + self.assertEqual(pair.value, "3") + + +class HasSemanticsTest(unittest.TestCase): + def test_supplemental_semantic_id_constraint(self) -> None: + extension = model.Extension(name='test') + key: model.Key = model.Key(model.KeyTypes.GLOBAL_REFERENCE, "global_reference") + ref_sem_id: model.Reference = model.ExternalReference((key,)) + ref1: model.Reference = model.ExternalReference((key,)) + + with self.assertRaises(model.AASConstraintViolation) as cm: + extension.supplemental_semantic_id.append(ref1) + self.assertEqual(cm.exception.constraint_id, 118) + self.assertEqual('A semantic_id must be defined before adding a supplemental_semantic_id! ' + '(Constraint AASd-118)', str(cm.exception)) + extension.semantic_id = ref_sem_id + extension.supplemental_semantic_id.append(ref1) + + with self.assertRaises(model.AASConstraintViolation) as cm: + extension.semantic_id = None + self.assertEqual(cm.exception.constraint_id, 118) + self.assertEqual('semantic_id can not be removed while there is at least one supplemental_semantic_id: ' + '[ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=global_reference),))] ' + '(Constraint AASd-118)', str(cm.exception)) + extension.supplemental_semantic_id.clear() + extension.semantic_id = None + + +class ConstrainedListTest(unittest.TestCase): + def test_length(self) -> None: + c_list: model.ConstrainedList[int] = model.ConstrainedList([1, 2]) + self.assertEqual(len(c_list), 2) + c_list.append(1) + self.assertEqual(len(c_list), 3) + c_list.clear() + self.assertEqual(len(c_list), 0) + + def test_contains(self) -> None: + c_list: model.ConstrainedList[int] = model.ConstrainedList([1, 2]) + self.assertIn(1, c_list) + self.assertNotIn(3, c_list) + c_list.append(3) + self.assertIn(3, c_list) + + def test_hooks(self) -> None: + new: Optional[int] = None + old_items: List[int] = [] + new_items: List[int] = [] + existing_items: List[int] = [] + + def add_hook(itm: int, list_: List[int]) -> None: + nonlocal new, existing_items + new = itm + # Copy list, otherwise we just store a reference to the same lists and the tests are meaningless. + existing_items = list_.copy() + + def set_hook(old: List[int], new: List[int], list_: List[int]) -> None: + nonlocal old_items, new_items, existing_items + # Copy list, otherwise we just store a reference to the same lists and the tests are meaningless. + old_items = old.copy() + new_items = new.copy() + existing_items = list_.copy() + + def del_hook(itm: int, list_: List[int]) -> None: + nonlocal new, existing_items + new = itm + # Copy list, otherwise we just store a reference to the same lists and the tests are meaningless. + existing_items = list_.copy() + + self.assertIsNone(new) + self.assertEqual(len(existing_items), 0) + + c_list: model.ConstrainedList[int] = model.ConstrainedList([1, 2, 3], item_add_hook=add_hook, + item_set_hook=set_hook, + item_del_hook=del_hook) + check_list: List[int] = [1, 2, 3] + + self.assertEqual(new, 3) + self.assertEqual(existing_items, [1, 2]) + self.assertEqual(c_list, check_list) + + # add hook test + c_list.append(4) + self.assertEqual(new, 4) + self.assertEqual(existing_items, [1, 2, 3]) + check_list.append(4) + self.assertEqual(c_list, check_list) + + c_list.extend([10, 11]) + self.assertEqual(new, 11) + self.assertEqual(existing_items, [1, 2, 3, 4, 10]) + check_list.extend([10, 11]) + self.assertEqual(c_list, check_list) + + c_list.insert(2, 20) + self.assertEqual(new, 20) + self.assertEqual(existing_items, [1, 2, 3, 4, 10, 11]) + check_list.insert(2, 20) + self.assertEqual(c_list, check_list) + + # set hook test + c_list[2] = 40 + self.assertEqual(old_items, [20]) + self.assertEqual(new_items, [40]) + self.assertEqual(existing_items, [1, 2, 20, 3, 4, 10, 11]) + check_list[2] = 40 + self.assertEqual(c_list, check_list) + + c_list[2:4] = [2, 3] + self.assertEqual(old_items, [40, 3]) + self.assertEqual(new_items, [2, 3]) + self.assertEqual(existing_items, [1, 2, 40, 3, 4, 10, 11]) + check_list[2:4] = [2, 3] + self.assertEqual(c_list, check_list) + + c_list[:] = [] + self.assertEqual(old_items, [1, 2, 2, 3, 4, 10, 11]) + self.assertEqual(new_items, []) + self.assertEqual(existing_items, [1, 2, 2, 3, 4, 10, 11]) + check_list[:] = [] + self.assertEqual(c_list, check_list) + + c_list[:] = [1, 2, 20, 3, 4, 10, 11] + self.assertEqual(old_items, []) + self.assertEqual(new_items, [1, 2, 20, 3, 4, 10, 11]) + self.assertEqual(existing_items, []) + check_list[:] = [1, 2, 20, 3, 4, 10, 11] + self.assertEqual(c_list, check_list) + + # del hook test + c_list.remove(20) + self.assertEqual(new, 20) + self.assertEqual(existing_items, [1, 2, 20, 3, 4, 10, 11]) + check_list.remove(20) + self.assertEqual(c_list, check_list) + + with self.assertRaises(ValueError): + c_list.remove(20) + + c_list.pop() + self.assertEqual(new, 11) + self.assertEqual(existing_items, [1, 2, 3, 4, 10, 11]) + check_list.pop() + self.assertEqual(c_list, check_list) + + def test_atomicity(self) -> None: + def hook(itm: int, _list: List[int]) -> None: + if itm > 2: + raise ValueError + + c_list: model.ConstrainedList[int] = model.ConstrainedList([], item_add_hook=hook) + with self.assertRaises(ValueError): + c_list = model.ConstrainedList([1, 2, 3], item_add_hook=hook) + self.assertEqual(c_list, []) + with self.assertRaises(ValueError): + c_list.extend([1, 2, 3]) + self.assertEqual(c_list, []) + c_list.extend([1, 2]) + self.assertEqual(c_list, [1, 2]) + + c_list = model.ConstrainedList([1, 2, 3], item_del_hook=hook) + with self.assertRaises(ValueError): + del c_list[0:3] + self.assertEqual(c_list, [1, 2, 3]) + with self.assertRaises(ValueError): + c_list.clear() + # the default clear() implementation seems to repeatedly delete the last item until the list is empty + # in this case, the last item is 3, which cannot be deleted because it is > 2, thus leaving it unclear whether + # clear() really is atomic. to work around this, the list is reversed, making 1 the last item, and attempting + # to clear again. + c_list.reverse() + with self.assertRaises(ValueError): + c_list.clear() + self.assertEqual(c_list, [3, 2, 1]) + c_list.reverse() + del c_list[0:2] + self.assertEqual(c_list, [3]) + + +class LangStringSetTest(unittest.TestCase): + def test_language_tag_constraints(self) -> None: + with self.assertRaises(ValueError) as cm: + model.LangStringSet({"foo": "bar"}) + self.assertEqual("The language code of the language tag must consist of exactly two lower-case letters! " + "Given language tag and language code: 'foo', 'foo'", str(cm.exception)) + + lss = model.LangStringSet({"fo-OO": "bar"}) + with self.assertRaises(ValueError) as cm: + lss["foo"] = "bar" + self.assertEqual("The language code of the language tag must consist of exactly two lower-case letters! " + "Given language tag and language code: 'foo', 'foo'", str(cm.exception)) + self.assertNotIn("foo", lss) + self.assertNotIn("fo", lss) + lss["fo"] = "bar" + self.assertIn("fo", lss) + + def test_empty(self) -> None: + lss = model.LangStringSet({"fo": "bar", "fo-OO": "baz"}) + with self.assertRaises(KeyError) as cm: + lss.clear() + self.assertEqual("A LangStringSet must not be empty!", cm.exception.args[0]) + self.assertEqual(lss, model.LangStringSet({"fo": "bar", "fo-OO": "baz"})) + del lss["fo"] + self.assertNotEqual(lss, model.LangStringSet({"fo": "bar", "fo-OO": "baz"})) + self.assertEqual(lss, model.LangStringSet({"fo-OO": "baz"})) + with self.assertRaises(KeyError) as cm: + del lss["fo-OO"] + self.assertEqual("A LangStringSet must not be empty!", cm.exception.args[0]) + self.assertEqual(lss, model.LangStringSet({"fo-OO": "baz"})) + + def test_text_constraints(self) -> None: + with self.assertRaises(ValueError) as cm: + model.MultiLanguageNameType({"fo": "o" * 65}) + self.assertEqual("The text for the language tag 'fo' is invalid: MultiLanguageNameType has a maximum length of " + "64! (length: 65)", str(cm.exception)) + mlnt = model.MultiLanguageNameType({"fo": "o" * 64}) + with self.assertRaises(ValueError) as cm: + mlnt["fo"] = "" + self.assertEqual("The text for the language tag 'fo' is invalid: MultiLanguageNameType has a minimum length of " + "1! (length: 0)", str(cm.exception)) + self.assertEqual(mlnt["fo"], "o" * 64) + mlnt["fo"] = "o" + self.assertEqual(mlnt["fo"], "o") + + def test_repr(self) -> None: + lss = model.LangStringSet({"fo": "bar"}) + self.assertEqual("LangStringSet(fo=\"bar\")", repr(lss)) + self.assertEqual(repr(lss), str(lss)) + mltt = model.MultiLanguageTextType({"fo": "bar"}) + self.assertEqual("MultiLanguageTextType(fo=\"bar\")", repr(mltt)) + self.assertEqual(repr(mltt), str(mltt)) + + def test_len(self) -> None: + lss = model.LangStringSet({"fo": "bar"}) + self.assertEqual(1, len(lss)) + lss["aa"] = "baz" + self.assertEqual(2, len(lss)) + + def test_iter(self) -> None: + lss = model.LangStringSet({"fo": "bar", "aa": "baz"}) + count: int = 0 + items: Dict[str, str] = {} + for ltag, text in lss.items(): + count += 1 + items[ltag] = text + self.assertEqual(count, 2) + self.assertEqual(items, {"fo": "bar", "aa": "baz"}) diff --git a/test/model/test_concept.py b/test/model/test_concept.py deleted file mode 100644 index 2efee6df6..000000000 --- a/test/model/test_concept.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors -# -# This program and the accompanying materials are made available under the terms of the MIT License, available in -# the LICENSE file of this project. -# -# SPDX-License-Identifier: MIT - -import unittest - -from basyx.aas import model - - -class IEC61360ConceptDescriptionTest(unittest.TestCase): - def test_set_value(self): - cp = model.IEC61360ConceptDescription(model.Identifier('test', model.IdentifierType.CUSTOM), - {'de': 'test'}, - model.concept.IEC61360DataType.STRING, - value_format=model.datatypes.Int, - value=2) - self.assertEqual(cp.value, 2) - cp.value = None - self.assertIsNone(cp.value) diff --git a/test/model/test_datatypes.py b/test/model/test_datatypes.py index 44946838c..bfdedb1c2 100644 --- a/test/model/test_datatypes.py +++ b/test/model/test_datatypes.py @@ -18,6 +18,9 @@ def test_parse_int(self) -> None: self.assertEqual(5, model.datatypes.from_xsd("5", model.datatypes.Integer)) self.assertEqual(6, model.datatypes.from_xsd("6", model.datatypes.Byte)) self.assertEqual(7, model.datatypes.from_xsd("7", model.datatypes.NonNegativeInteger)) + self.assertEqual(8, model.datatypes.from_xsd("8", model.datatypes.Long)) + self.assertEqual(9, model.datatypes.from_xsd("9", model.datatypes.Int)) + self.assertEqual(10, model.datatypes.from_xsd("10", model.datatypes.Short)) def test_serialize_int(self) -> None: self.assertEqual("5", model.datatypes.xsd_repr(model.datatypes.Integer(5))) @@ -40,6 +43,12 @@ def test_range_error(self) -> None: with self.assertRaises(ValueError) as cm: model.datatypes.PositiveInteger(0) self.assertEqual("0 is out of the allowed range for type PositiveInteger", str(cm.exception)) + with self.assertRaises(ValueError) as cm: + model.datatypes.Int(2147483648) + self.assertEqual("2147483648 is out of the allowed range for type Int", str(cm.exception)) + with self.assertRaises(ValueError) as cm: + model.datatypes.Long(2**63) + self.assertEqual(str(2**63)+" is out of the allowed range for type Long", str(cm.exception)) def test_trivial_cast(self) -> None: val = model.datatypes.trivial_cast(5, model.datatypes.UnsignedByte) diff --git a/test/model/test_provider.py b/test/model/test_provider.py index bb62a4e12..55586ffc8 100644 --- a/test/model/test_provider.py +++ b/test/model/test_provider.py @@ -12,14 +12,12 @@ class ProvidersTest(unittest.TestCase): def setUp(self) -> None: - self.aas1 = model.AssetAdministrationShell(model.AASReference((model.Key( - model.KeyElements.ASSET, True, "urn:x-test:asset", model.KeyType.IRI),), model.Asset), - model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI)) - self.aas2 = model.AssetAdministrationShell(model.AASReference((model.Key( - model.KeyElements.ASSET, True, "urn:x-test:asset", model.KeyType.IRI),), model.Asset), - model.Identifier("urn:x-test:aas2", model.IdentifierType.IRI)) - self.submodel1 = model.Submodel(model.Identifier("urn:x-test:submodel1", model.IdentifierType.IRI)) - self.submodel2 = model.Submodel(model.Identifier("urn:x-test:submodel2", model.IdentifierType.IRI)) + self.aas1 = model.AssetAdministrationShell( + model.AssetInformation(global_asset_id="http://acplt.org/TestAsset1/"), "urn:x-test:aas1") + self.aas2 = model.AssetAdministrationShell( + model.AssetInformation(global_asset_id="http://acplt.org/TestAsset2/"), "urn:x-test:aas2") + self.submodel1 = model.Submodel("urn:x-test:submodel1") + self.submodel2 = model.Submodel("urn:x-test:submodel2") def test_store_retrieve(self) -> None: object_store: model.DictObjectStore[model.AssetAdministrationShell] = model.DictObjectStore() @@ -28,24 +26,23 @@ def test_store_retrieve(self) -> None: self.assertIn(self.aas1, object_store) property = model.Property('test', model.datatypes.String) self.assertFalse(property in object_store) - aas3 = model.AssetAdministrationShell(model.AASReference((model.Key( - model.KeyElements.SUBMODEL, True, "urn:x-test:submodel", model.KeyType.IRI),), model.Asset), - model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI)) + aas3 = model.AssetAdministrationShell(model.AssetInformation(global_asset_id="http://acplt.org/TestAsset/"), + "urn:x-test:aas1") with self.assertRaises(KeyError) as cm: object_store.add(aas3) - self.assertEqual("'Identifiable object with same identification Identifier(IRI=urn:x-test:aas1) is already " + self.assertEqual("'Identifiable object with same id urn:x-test:aas1 is already " "stored in this store'", str(cm.exception)) self.assertEqual(2, len(object_store)) self.assertIs(self.aas1, - object_store.get_identifiable(model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI))) + object_store.get_identifiable("urn:x-test:aas1")) self.assertIs(self.aas1, - object_store.get(model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI))) + object_store.get("urn:x-test:aas1")) object_store.discard(self.aas1) object_store.discard(self.aas1) with self.assertRaises(KeyError) as cm: - object_store.get_identifiable(model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI)) - self.assertIsNone(object_store.get(model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI))) - self.assertEqual("Identifier(IRI=urn:x-test:aas1)", str(cm.exception)) + object_store.get_identifiable("urn:x-test:aas1") + self.assertIsNone(object_store.get("urn:x-test:aas1")) + self.assertEqual("'urn:x-test:aas1'", str(cm.exception)) self.assertIs(self.aas2, object_store.pop()) self.assertEqual(0, len(object_store)) @@ -67,10 +64,8 @@ def test_provider_multiplexer(self) -> None: submodel_object_store.add(self.submodel2) multiplexer = model.ObjectProviderMultiplexer([aas_object_store, submodel_object_store]) - self.assertIs(self.aas1, - multiplexer.get_identifiable(model.Identifier("urn:x-test:aas1", model.IdentifierType.IRI))) - self.assertIs(self.submodel1, - multiplexer.get_identifiable(model.Identifier("urn:x-test:submodel1", model.IdentifierType.IRI))) + self.assertIs(self.aas1, multiplexer.get_identifiable("urn:x-test:aas1")) + self.assertIs(self.submodel1, multiplexer.get_identifiable("urn:x-test:submodel1")) with self.assertRaises(KeyError) as cm: - multiplexer.get_identifiable(model.Identifier("urn:x-test:submodel3", model.IdentifierType.IRI)) + multiplexer.get_identifiable("urn:x-test:submodel3") self.assertEqual("'Identifier could not be found in any of the 2 consulted registries.'", str(cm.exception)) diff --git a/test/model/test_string_constraints.py b/test/model/test_string_constraints.py new file mode 100644 index 000000000..5adb15523 --- /dev/null +++ b/test/model/test_string_constraints.py @@ -0,0 +1,101 @@ +# Copyright (c) 2023 the Eclipse BaSyx Authors +# +# This program and the accompanying materials are made available under the terms of the MIT License, available in +# the LICENSE file of this project. +# +# SPDX-License-Identifier: MIT + +import unittest + +from basyx.aas import model +from basyx.aas.model import _string_constraints + + +class StringConstraintsTest(unittest.TestCase): + def test_identifier(self) -> None: + identifier: model.Identifier = "" + with self.assertRaises(ValueError) as cm: + _string_constraints.check_identifier(identifier) + self.assertEqual("Identifier has a minimum length of 1! (length: 0)", cm.exception.args[0]) + identifier = "a" * 2001 + with self.assertRaises(ValueError) as cm: + _string_constraints.check_identifier(identifier) + self.assertEqual("Identifier has a maximum length of 2000! (length: 2001)", cm.exception.args[0]) + identifier = "a" * 2000 + _string_constraints.check_identifier(identifier) + + def test_version_type(self) -> None: + version: model.VersionType = "" + with self.assertRaises(ValueError) as cm: + _string_constraints.check_version_type(version) + self.assertEqual("VersionType has a minimum length of 1! (length: 0)", cm.exception.args[0]) + version = "1" * 5 + with self.assertRaises(ValueError) as cm: + _string_constraints.check_version_type(version) + self.assertEqual("VersionType has a maximum length of 4! (length: 5)", cm.exception.args[0]) + version = "0" * 4 + with self.assertRaises(ValueError) as cm: + _string_constraints.check_version_type(version) + self.assertEqual("VersionType must match the pattern '([0-9]|[1-9][0-9]*)'! (value: '0000')", + cm.exception.args[0]) + version = "0" + _string_constraints.check_version_type(version) + + def test_aasd_130(self) -> None: + name: model.NameType = "\0" + with self.assertRaises(ValueError) as cm: + _string_constraints.check_name_type(name) + self.assertEqual(r"Every string must match the pattern '[\t\n\r -\ud7ff\ue000-\ufffd\U00010000-\U0010ffff]*'! " + r"(value: '\x00')", cm.exception.args[0]) + name = "\ud800" + with self.assertRaises(ValueError) as cm: + _string_constraints.check_name_type(name) + self.assertEqual(r"Every string must match the pattern '[\t\n\r -\ud7ff\ue000-\ufffd\U00010000-\U0010ffff]*'! " + r"(value: '\ud800')", cm.exception.args[0]) + name = "\ufffe" + with self.assertRaises(ValueError) as cm: + _string_constraints.check_name_type(name) + self.assertEqual(r"Every string must match the pattern '[\t\n\r -\ud7ff\ue000-\ufffd\U00010000-\U0010ffff]*'! " + r"(value: '\ufffe')", cm.exception.args[0]) + name = "this\ris\na\tvalid täst\uffdd\U0010ab12" + _string_constraints.check_name_type(name) + + +class StringConstraintsDecoratorTest(unittest.TestCase): + @_string_constraints.constrain_path_type("some_attr") + class DummyClass: + def __init__(self, path: model.PathType): + self.some_attr: model.PathType = path + + def test_path_type_decoration(self) -> None: + with self.assertRaises(ValueError) as cm: + self.DummyClass("") + self.assertEqual("PathType has a minimum length of 1! (length: 0)", cm.exception.args[0]) + dc = self.DummyClass("a") + with self.assertRaises(ValueError) as cm: + dc.some_attr = "a" * 2001 + self.assertEqual("PathType has a maximum length of 2000! (length: 2001)", cm.exception.args[0]) + self.assertEqual(dc.some_attr, "a") + + def test_ignore_none_values(self) -> None: + # None values should be ignored as some decorated attributes are optional. As shown in the following, + # such assignments are caught by the typechecker anyway. + dc = self.DummyClass(None) # type: ignore + self.assertIsNone(dc.some_attr) + dc.some_attr = None # type: ignore + + def test_attribute_name_conflict(self) -> None: + # We don't want to overwrite existing attributes in case of a name conflict + with self.assertRaises(AttributeError) as cm: + @_string_constraints.constrain_revision_type("foo") + class DummyClass: + foo = property() + self.assertEqual("DummyClass already has an attribute named 'foo'", cm.exception.args[0]) + + with self.assertRaises(AttributeError) as cm: + @_string_constraints.constrain_label_type("bar") + class DummyClass2: + @property + def bar(self): + return "baz" + self.assertEqual("DummyClass2 already has an attribute named 'bar'", cm.exception.args[0]) diff --git a/test/model/test_submodel.py b/test/model/test_submodel.py index b8a989c0f..74c12328d 100644 --- a/test/model/test_submodel.py +++ b/test/model/test_submodel.py @@ -6,16 +6,139 @@ # SPDX-License-Identifier: MIT import unittest +import dateutil.tz from basyx.aas import model class EntityTest(unittest.TestCase): + def test_aasd_014_init_self_managed(self) -> None: + with self.assertRaises(model.AASConstraintViolation) as cm: + model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY) + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, global_asset_id="https://acplt.org/TestAsset") + model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) - def test_set_entity(self): - with self.assertRaises(ValueError) as cm: - obj = model.Entity(id_short='Test', entity_type=model.EntityType.SELF_MANAGED_ENTITY, statement=()) - self.assertEqual('A self-managed entity has to have an asset-reference', str(cm.exception)) + def test_aasd_014_init_co_managed(self) -> None: + model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY, + global_asset_id="https://acplt.org/TestAsset") + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY, + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY, + global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + + def test_aasd_014_set_self_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, + global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + entity.global_asset_id = None + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id = model.ConstrainedList(()) + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + + entity = model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, + global_asset_id="https://acplt.org/TestAsset", + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + entity.specific_asset_id = model.ConstrainedList(()) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.global_asset_id = None + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + + def test_aasd_014_set_co_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.global_asset_id = "https://acplt.org/TestAsset" + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id = model.ConstrainedList((model.SpecificAssetId("test", "test"),)) + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + + def test_aasd_014_specific_asset_id_add_self_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, + global_asset_id="https://acplt.org/TestAsset") + specific_asset_id1 = model.SpecificAssetId("test", "test") + specific_asset_id2 = model.SpecificAssetId("test", "test") + entity.specific_asset_id.append(specific_asset_id1) + entity.specific_asset_id.extend((specific_asset_id2,)) + self.assertIs(entity.specific_asset_id[0], specific_asset_id1) + self.assertIs(entity.specific_asset_id[1], specific_asset_id2) + + def test_aasd_014_specific_asset_id_add_co_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id.append(model.SpecificAssetId("test", "test")) + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id.extend((model.SpecificAssetId("test", "test"),)) + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + + def test_assd_014_specific_asset_id_set_self_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, + specific_asset_id=(model.SpecificAssetId("test", "test"),)) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id[:] = () + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + specific_asset_id = model.SpecificAssetId("test", "test") + self.assertIsNot(entity.specific_asset_id[0], specific_asset_id) + entity.specific_asset_id[:] = (specific_asset_id,) + self.assertIs(entity.specific_asset_id[0], specific_asset_id) + entity.specific_asset_id[0] = model.SpecificAssetId("test", "test") + self.assertIsNot(entity.specific_asset_id[0], specific_asset_id) + + def test_assd_014_specific_asset_id_set_co_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id[:] = (model.SpecificAssetId("test", "test"),) + self.assertEqual("A co-managed entity has to have neither a globalAssetId nor a specificAssetId " + "(Constraint AASd-014)", str(cm.exception)) + entity.specific_asset_id[:] = () + + def test_aasd_014_specific_asset_id_del_self_managed(self) -> None: + specific_asset_id = model.SpecificAssetId("test", "test") + entity = model.Entity("TestEntity", model.EntityType.SELF_MANAGED_ENTITY, + specific_asset_id=(model.SpecificAssetId("test", "test"), + specific_asset_id)) + with self.assertRaises(model.AASConstraintViolation) as cm: + del entity.specific_asset_id[:] + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + with self.assertRaises(model.AASConstraintViolation) as cm: + entity.specific_asset_id.clear() + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + self.assertIsNot(entity.specific_asset_id[0], specific_asset_id) + del entity.specific_asset_id[0] + self.assertIs(entity.specific_asset_id[0], specific_asset_id) + with self.assertRaises(model.AASConstraintViolation) as cm: + del entity.specific_asset_id[0] + self.assertEqual("A self-managed entity has to have a globalAssetId or a specificAssetId (Constraint AASd-014)", + str(cm.exception)) + + def test_aasd_014_specific_asset_id_del_co_managed(self) -> None: + entity = model.Entity("TestEntity", model.EntityType.CO_MANAGED_ENTITY) + del entity.specific_asset_id[:] class PropertyTest(unittest.TestCase): @@ -35,3 +158,170 @@ def test_set_min_max(self): self.assertIsNone(range.min) range.max = None self.assertIsNone(range.max) + + +class SubmodelElementListTest(unittest.TestCase): + def test_constraints(self): + # AASd-107 + mlp = model.MultiLanguageProperty(None, semantic_id=model.ExternalReference( + (model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:invalid"),) + )) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.SubmodelElementList("test_list", model.MultiLanguageProperty, {mlp}, + semantic_id_list_element=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:test"),))) + self.assertEqual("If semantic_id_list_element=ExternalReference(key=(Key(type=GLOBAL_REFERENCE, " + "value=urn:x-test:test),)) is specified all first level children must have " + "the same semantic_id, got MultiLanguageProperty with " + "semantic_id=ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=urn:x-test:invalid),)) " + "(Constraint AASd-107)", str(cm.exception)) + sel = model.SubmodelElementList("test_list", model.MultiLanguageProperty, {mlp}, + semantic_id_list_element=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:invalid"),))) + sel.value.clear() + model.SubmodelElementList("test_list", model.MultiLanguageProperty, {mlp}, semantic_id_list_element=None) + mlp = model.MultiLanguageProperty(None) + model.SubmodelElementList("test_list", model.MultiLanguageProperty, {mlp}, + semantic_id_list_element=model.ExternalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:invalid"),))) + + # AASd-108 + are = model.AnnotatedRelationshipElement( + None, + model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:test-first"),)), + model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:test-second"),)) + ) + # This tests checks if subclasses of the required type are rejected in a SubmodelElementList. + # Thus, a requirement is that AnnotatedRelationshipElement is a subclass of RelationshipElement: + self.assertIsInstance(are, model.RelationshipElement) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.SubmodelElementList("test_list", model.RelationshipElement, {are}) + self.assertEqual("All first level elements must be of the type specified in " + "type_value_list_element=RelationshipElement, got AnnotatedRelationshipElement " + "(Constraint AASd-108)", str(cm.exception)) + model.SubmodelElementList("test_list", model.AnnotatedRelationshipElement, {are}) + + # AASd-109 + # Pass an item to the constructor to assert that this constraint is checked before items are added. + prop = model.Property(None, model.datatypes.Int, 0) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.SubmodelElementList("test_list", model.Property, [prop]) + self.assertEqual("type_value_list_element=Property, but value_type_list_element is not set! " + "(Constraint AASd-109)", str(cm.exception)) + model.SubmodelElementList("test_list", model.Property, [prop], value_type_list_element=model.datatypes.Int) + + prop = model.Property(None, model.datatypes.String) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.SubmodelElementList("test_list", model.Property, {prop}, value_type_list_element=model.datatypes.Int) + self.assertEqual("All first level elements must have the value_type specified by value_type_list_element=Int, " + "got Property with value_type=str (Constraint AASd-109)", str(cm.exception)) + model.SubmodelElementList("test_list", model.Property, {prop}, value_type_list_element=model.datatypes.String) + + # AASd-114 + semantic_id1 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:test"),)) + semantic_id2 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "urn:x-test:different"),)) + mlp1 = model.MultiLanguageProperty(None, semantic_id=semantic_id1) + mlp2 = model.MultiLanguageProperty(None, semantic_id=semantic_id2) + with self.assertRaises(model.AASConstraintViolation) as cm: + model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp1, mlp2]) + self.assertEqual("Element to be added MultiLanguageProperty has semantic_id " + "ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=urn:x-test:different),)), " + "while already contained element MultiLanguageProperty[test_list[0]] has semantic_id " + "ExternalReference(key=(Key(type=GLOBAL_REFERENCE, value=urn:x-test:test),)), " + "which aren't equal. (Constraint AASd-114)", str(cm.exception)) + mlp2.semantic_id = semantic_id1 + model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp1, mlp2]) + + # AASd-120 + mlp = model.MultiLanguageProperty("mlp") + with self.assertRaises(model.AASConstraintViolation) as cm: + model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp]) + self.assertEqual("Objects with an id_short may not be added to a SubmodelElementList, got " + "MultiLanguageProperty[mlp] with id_short=mlp (Constraint AASd-120)", str(cm.exception)) + mlp.id_short = None + model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp]) + with self.assertRaises(model.AASConstraintViolation) as cm: + mlp.id_short = "mlp" + self.assertEqual("id_short of MultiLanguageProperty[test_list[0]] cannot be set, because it is " + "contained in a SubmodelElementList[test_list] (Constraint AASd-120)", str(cm.exception)) + + def test_aasd_108_add_set(self): + prop = model.Property(None, model.datatypes.Int) + mlp1 = model.MultiLanguageProperty(None) + mlp2 = model.MultiLanguageProperty(None) + list_ = model.SubmodelElementList("test_list", model.MultiLanguageProperty) + with self.assertRaises(model.AASConstraintViolation) as cm: + list_.add_referable(prop) + self.assertEqual("All first level elements must be of the type specified in type_value_list_element=" + "MultiLanguageProperty, got Property (Constraint AASd-108)", str(cm.exception)) + list_.add_referable(mlp1) + + with self.assertRaises(model.AASConstraintViolation) as cm: + list_.value.add(prop) + self.assertEqual("All first level elements must be of the type specified in type_value_list_element=" + "MultiLanguageProperty, got Property (Constraint AASd-108)", str(cm.exception)) + list_.value.add(mlp2) + + with self.assertRaises(model.AASConstraintViolation) as cm: + list_.value[0] = prop + self.assertEqual("All first level elements must be of the type specified in type_value_list_element=" + "MultiLanguageProperty, got Property (Constraint AASd-108)", str(cm.exception)) + del list_.value[1] + list_.value[0] = mlp2 + + with self.assertRaises(model.AASConstraintViolation) as cm: + list_.value = [mlp1, prop] + self.assertEqual("All first level elements must be of the type specified in type_value_list_element=" + "MultiLanguageProperty, got Property (Constraint AASd-108)", str(cm.exception)) + list_.value = [mlp1, mlp2] + + def test_immutable_attributes(self): + list_ = model.SubmodelElementList("test_list", model.File) + with self.assertRaises(AttributeError): + list_.type_value_list_element = model.MultiLanguageProperty + with self.assertRaises(AttributeError): + list_.order_relevant = False + with self.assertRaises(AttributeError): + list_.semantic_id_list_element = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "t"),)) + with self.assertRaises(AttributeError): + list_.value_type_list_element = model.datatypes.Int + + +class BasicEventElementTest(unittest.TestCase): + def test_constraints(self): + with self.assertRaises(ValueError) as cm: + model.BasicEventElement("test_basic_event_element", + model.ModelReference((model.Key(model.KeyTypes.ASSET_ADMINISTRATION_SHELL, + "urn:x-test:AssetAdministrationShell"),), + model.AssetAdministrationShell), + model.Direction.INPUT, + model.StateOfEvent.ON, + max_interval=model.datatypes.Duration(minutes=10)) + self.assertEqual("max_interval is not applicable if direction = input!", str(cm.exception)) + bee = model.BasicEventElement("test_basic_event_element", + model.ModelReference((model.Key(model.KeyTypes.ASSET_ADMINISTRATION_SHELL, + "urn:x-test:AssetAdministrationShell"),), + model.AssetAdministrationShell), + model.Direction.OUTPUT, + model.StateOfEvent.ON, + max_interval=model.datatypes.Duration(minutes=10)) + with self.assertRaises(ValueError) as cm: + bee.direction = model.Direction.INPUT + self.assertEqual("max_interval is not applicable if direction = input!", str(cm.exception)) + + bee.max_interval = None + bee.direction = model.Direction.INPUT + + timestamp_tzinfo = model.datatypes.DateTime(2022, 11, 13, 23, 45, 30, 123456, + dateutil.tz.gettz("Europe/Berlin")) + with self.assertRaises(ValueError) as cm: + bee.last_update = timestamp_tzinfo + self.assertEqual("last_update must be specified in UTC!", str(cm.exception)) + + timestamp = model.datatypes.DateTime(2022, 11, 13, 23, 45, 30, 123456) + with self.assertRaises(ValueError) as cm: + bee.last_update = timestamp + self.assertEqual("last_update must be specified in UTC!", str(cm.exception)) + + timestamp_tzinfo_utc = model.datatypes.DateTime(2022, 11, 13, 23, 45, 30, 123456, dateutil.tz.UTC) + bee.last_update = timestamp_tzinfo_utc diff --git a/test/test_config.default.ini b/test/test_config.default.ini index e76c0ff24..c09b44a00 100644 --- a/test/test_config.default.ini +++ b/test/test_config.default.ini @@ -4,7 +4,7 @@ # to that file to override the defaults defined here. [couchdb] -url = http://localhost:5984 +url = http://127.0.0.1:5984 database = aas_test user = aas_test password = aas_test diff --git a/test/util/test_identification.py b/test/util/test_identification.py index 185eda39c..418423dea 100644 --- a/test/util/test_identification.py +++ b/test/util/test_identification.py @@ -15,7 +15,7 @@ class IdentifierGeneratorTest(unittest.TestCase): def test_generate_uuid_identifier(self): generator = UUIDGenerator() identification = generator.generate_id() - self.assertRegex(identification.id, + self.assertRegex(identification, r"urn:uuid:[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}") ids = set() for i in range(100): @@ -38,20 +38,20 @@ def test_generate_iri_identifier(self): self.assertEqual("http://acplt.org/AAS/", generator.namespace) identification = generator.generate_id() - self.assertEqual(identification.id, "http://acplt.org/AAS/0000") + self.assertEqual(identification, "http://acplt.org/AAS/0000") provider.add(model.Submodel(identification)) for i in range(10): identification = generator.generate_id() self.assertNotIn(identification, provider) provider.add(model.Submodel(identification)) - self.assertEqual(identification.id, "http://acplt.org/AAS/0010") + self.assertEqual(identification, "http://acplt.org/AAS/0010") identification = generator.generate_id("Spülmaschine") - self.assertEqual(identification.id, "http://acplt.org/AAS/Spülmaschine") + self.assertEqual(identification, "http://acplt.org/AAS/Spülmaschine") provider.add(model.Submodel(identification)) for i in range(10): identification = generator.generate_id("Spülmaschine") self.assertNotIn(identification, provider) - self.assertNotEqual(identification.id, "http://acplt.org/AAS/Spülmaschine") + self.assertNotEqual(identification, "http://acplt.org/AAS/Spülmaschine")