diff --git a/aas_core3/jsonization.py b/aas_core3/jsonization.py index be6b9631..c62ff3b8 100644 --- a/aas_core3/jsonization.py +++ b/aas_core3/jsonization.py @@ -1066,6 +1066,9 @@ def asset_administration_shell_from_jsonable( exception.path._prepend(PropertySegment(jsonable_value, key)) raise exception + if setter.id_short is None: + raise DeserializationException("The required property 'idShort' is missing") + if setter.id is None: raise DeserializationException("The required property 'id' is missing") @@ -1075,11 +1078,11 @@ def asset_administration_shell_from_jsonable( ) return aas_types.AssetAdministrationShell( + setter.id_short, setter.id, setter.asset_information, setter.extensions, setter.category, - setter.id_short, setter.display_name, setter.description, setter.administration, @@ -1652,14 +1655,17 @@ def submodel_from_jsonable(jsonable: Jsonable) -> aas_types.Submodel: exception.path._prepend(PropertySegment(jsonable_value, key)) raise exception + if setter.id_short is None: + raise DeserializationException("The required property 'idShort' is missing") + if setter.id is None: raise DeserializationException("The required property 'id' is missing") return aas_types.Submodel( + setter.id_short, setter.id, setter.extensions, setter.category, - setter.id_short, setter.display_name, setter.description, setter.administration, @@ -5993,14 +5999,17 @@ def concept_description_from_jsonable( exception.path._prepend(PropertySegment(jsonable_value, key)) raise exception + if setter.id_short is None: + raise DeserializationException("The required property 'idShort' is missing") + if setter.id is None: raise DeserializationException("The required property 'id' is missing") return aas_types.ConceptDescription( + setter.id_short, setter.id, setter.extensions, setter.category, - setter.id_short, setter.display_name, setter.description, setter.administration, @@ -8116,8 +8125,7 @@ def transform_asset_administration_shell( if that.category is not None: jsonable["category"] = that.category - if that.id_short is not None: - jsonable["idShort"] = that.id_short + jsonable["idShort"] = that.id_short if that.display_name is not None: jsonable["displayName"] = [ @@ -8220,8 +8228,7 @@ def transform_submodel(self, that: aas_types.Submodel) -> MutableJsonable: if that.category is not None: jsonable["category"] = that.category - if that.id_short is not None: - jsonable["idShort"] = that.id_short + jsonable["idShort"] = that.id_short if that.display_name is not None: jsonable["displayName"] = [ @@ -9049,8 +9056,7 @@ def transform_concept_description( if that.category is not None: jsonable["category"] = that.category - if that.id_short is not None: - jsonable["idShort"] = that.id_short + jsonable["idShort"] = that.id_short if that.display_name is not None: jsonable["displayName"] = [ diff --git a/aas_core3/types.py b/aas_core3/types.py index 1b5aac5c..cd9ff0a9 100644 --- a/aas_core3/types.py +++ b/aas_core3/types.py @@ -397,6 +397,37 @@ def __init__( class Identifiable(Referable): """An element that has a globally unique identifier.""" + #: In case of identifiables this attribute is a short name of the element. + #: In case of referable this ID is an identifying string of the element within + #: its name space. + #: + #: .. note:: + #: + #: In case the element is a property and the property has a semantic definition + #: (:py:attr:`HasSemantics.semantic_id`) conformant to IEC61360 + #: the :py:attr:`id_short` is typically identical to the short name in English. + #: + #: :py:attr:`id_short` is strengthened to required in this class, + #: see :ref:`Constraint AASd-117 `. + id_short: str + + # region Strengthening of id_short + @property # type: ignore + def id_short(self) -> str: + # pylint: disable=missing-function-docstring + return self._id_short + + @id_short.setter + def id_short(self, new_id_short: Optional[str]) -> None: + if new_id_short is None: + raise ValueError( + "Unexpected None id_short assigned to an instance of Identifiable" + ) + + self._id_short = new_id_short + + # endregion + #: Administrative information of an identifiable element. #: #: .. note:: @@ -410,10 +441,10 @@ class Identifiable(Referable): def __init__( self, + id_short: str, id: str, extensions: Optional[List["Extension"]] = None, category: Optional[str] = None, - id_short: Optional[str] = None, display_name: Optional[List["LangStringNameType"]] = None, description: Optional[List["LangStringTextType"]] = None, administration: Optional["AdministrativeInformation"] = None, @@ -424,6 +455,9 @@ def __init__( ) self.id = id self.administration = administration + # region Strengthening + self._id_short = id_short + # endregion class ModellingKind(enum.Enum): @@ -931,11 +965,11 @@ def transform_with_context( def __init__( self, + id_short: str, id: str, asset_information: "AssetInformation", extensions: Optional[List["Extension"]] = None, category: Optional[str] = None, - id_short: Optional[str] = None, display_name: Optional[List["LangStringNameType"]] = None, description: Optional[List["LangStringTextType"]] = None, administration: Optional["AdministrativeInformation"] = None, @@ -948,10 +982,10 @@ def __init__( """Initialize with the given values.""" Identifiable.__init__( self, + id_short, id, extensions, category, - id_short, display_name, description, administration, @@ -960,6 +994,9 @@ def __init__( self.derived_from = derived_from self.asset_information = asset_information self.submodels = submodels + # region Strengthening + self._id_short = id_short + # endregion class AssetInformation(Class): @@ -1448,10 +1485,10 @@ def transform_with_context( def __init__( self, + id_short: str, id: str, extensions: Optional[List["Extension"]] = None, category: Optional[str] = None, - id_short: Optional[str] = None, display_name: Optional[List["LangStringNameType"]] = None, description: Optional[List["LangStringTextType"]] = None, administration: Optional["AdministrativeInformation"] = None, @@ -1467,10 +1504,10 @@ def __init__( """Initialize with the given values.""" Identifiable.__init__( self, + id_short, id, extensions, category, - id_short, display_name, description, administration, @@ -1480,6 +1517,9 @@ def __init__( Qualifiable.__init__(self, qualifiers) HasDataSpecification.__init__(self, embedded_data_specifications) self.submodel_elements = submodel_elements + # region Strengthening + self._id_short = id_short + # endregion class SubmodelElement(Referable, HasSemantics, Qualifiable, HasDataSpecification): @@ -4499,10 +4539,10 @@ def transform_with_context( def __init__( self, + id_short: str, id: str, extensions: Optional[List["Extension"]] = None, category: Optional[str] = None, - id_short: Optional[str] = None, display_name: Optional[List["LangStringNameType"]] = None, description: Optional[List["LangStringTextType"]] = None, administration: Optional["AdministrativeInformation"] = None, @@ -4514,16 +4554,19 @@ def __init__( """Initialize with the given values.""" Identifiable.__init__( self, + id_short, id, extensions, category, - id_short, display_name, description, administration, ) HasDataSpecification.__init__(self, embedded_data_specifications) self.is_case_of = is_case_of + # region Strengthening + self._id_short = id_short + # endregion class ReferenceTypes(enum.Enum): diff --git a/aas_core3/verification.py b/aas_core3/verification.py index 4a9aee5e..fb257897 100644 --- a/aas_core3/verification.py +++ b/aas_core3/verification.py @@ -2103,13 +2103,6 @@ def transform_asset_administration_shell( ): yield Error("Display name specifies no duplicate languages.") - if not (that.id_short is not None): - yield Error( - "Constraint AASd-117: ID-short of Referables not being " - + "a direct child of a Submodel element list shall be " - + "specified." - ) - if not ( not (that.embedded_data_specifications is not None) or (len(that.embedded_data_specifications) >= 1) @@ -2156,10 +2149,9 @@ def transform_asset_administration_shell( error.path._prepend(PropertySegment(that, "category")) yield error - if that.id_short is not None: - for error in verify_id_short_type(that.id_short): - error.path._prepend(PropertySegment(that, "id_short")) - yield error + for error in verify_id_short_type(that.id_short): + error.path._prepend(PropertySegment(that, "id_short")) + yield error if that.display_name is not None: for i, another_item in enumerate(that.display_name): @@ -2400,13 +2392,6 @@ def transform_submodel(self, that: aas_types.Submodel) -> Iterator[Error]: ): yield Error("Display name specifies no duplicate languages.") - if not (that.id_short is not None): - yield Error( - "Constraint AASd-117: ID-short of Referables not being " - + "a direct child of a Submodel element list shall be " - + "specified." - ) - if not ( not (that.supplemental_semantic_ids is not None) or (len(that.supplemental_semantic_ids) >= 1) @@ -2536,10 +2521,9 @@ def transform_submodel(self, that: aas_types.Submodel) -> Iterator[Error]: error.path._prepend(PropertySegment(that, "category")) yield error - if that.id_short is not None: - for error in verify_id_short_type(that.id_short): - error.path._prepend(PropertySegment(that, "id_short")) - yield error + for error in verify_id_short_type(that.id_short): + error.path._prepend(PropertySegment(that, "id_short")) + yield error if that.display_name is not None: for i, another_item in enumerate(that.display_name): @@ -2684,13 +2668,6 @@ def transform_relationship_element( + "at least one item." ) - if not (that.id_short is not None): - yield Error( - "Constraint AASd-117: ID-short of Referables not being " - + "a direct child of a Submodel element list shall be " - + "specified." - ) - if that.extensions is not None: for i, an_item in enumerate(that.extensions): for error in self.transform(an_item): @@ -4237,13 +4214,6 @@ def transform_annotated_relationship_element( + "at least one item." ) - if not (that.id_short is not None): - yield Error( - "Constraint AASd-117: ID-short of Referables not being " - + "a direct child of a Submodel element list shall be " - + "specified." - ) - if not (not (that.annotations is not None) or (len(that.annotations) >= 1)): yield Error( "Annotations must be either not set or have at least one " + "item." @@ -4693,13 +4663,6 @@ def transform_basic_event_element( + "at least one item." ) - if not (that.id_short is not None): - yield Error( - "Constraint AASd-117: ID-short of Referables not being " - + "a direct child of a Submodel element list shall be " - + "specified." - ) - if not ( not (that.direction == aas_types.Direction.INPUT) or (that.max_interval is None) @@ -5202,13 +5165,6 @@ def transform_concept_description( ): yield Error("Display name specifies no duplicate languages.") - if not (that.id_short is not None): - yield Error( - "Constraint AASd-117: ID-short of Referables not being " - + "a direct child of a Submodel element list shall be " - + "specified." - ) - if not ( not (that.embedded_data_specifications is not None) or (len(that.embedded_data_specifications) >= 1) @@ -5332,10 +5288,9 @@ def transform_concept_description( error.path._prepend(PropertySegment(that, "category")) yield error - if that.id_short is not None: - for error in verify_id_short_type(that.id_short): - error.path._prepend(PropertySegment(that, "id_short")) - yield error + for error in verify_id_short_type(that.id_short): + error.path._prepend(PropertySegment(that, "id_short")) + yield error if that.display_name is not None: for i, another_item in enumerate(that.display_name): diff --git a/aas_core3/xmlization.py b/aas_core3/xmlization.py index 7c82f544..51eac694 100644 --- a/aas_core3/xmlization.py +++ b/aas_core3/xmlization.py @@ -10900,6 +10900,9 @@ def _read_asset_administration_shell_as_sequence( exception.path._prepend(ElementSegment(next_element)) raise + if reader_and_setter.id_short is None: + raise DeserializationException("The required property 'idShort' is missing") + if reader_and_setter.id is None: raise DeserializationException("The required property 'id' is missing") @@ -10909,11 +10912,11 @@ def _read_asset_administration_shell_as_sequence( ) return aas_types.AssetAdministrationShell( + reader_and_setter.id_short, reader_and_setter.id, reader_and_setter.asset_information, reader_and_setter.extensions, reader_and_setter.category, - reader_and_setter.id_short, reader_and_setter.display_name, reader_and_setter.description, reader_and_setter.administration, @@ -12017,14 +12020,17 @@ def _read_submodel_as_sequence( exception.path._prepend(ElementSegment(next_element)) raise + if reader_and_setter.id_short is None: + raise DeserializationException("The required property 'idShort' is missing") + if reader_and_setter.id is None: raise DeserializationException("The required property 'id' is missing") return aas_types.Submodel( + reader_and_setter.id_short, reader_and_setter.id, reader_and_setter.extensions, reader_and_setter.category, - reader_and_setter.id_short, reader_and_setter.display_name, reader_and_setter.description, reader_and_setter.administration, @@ -20021,14 +20027,17 @@ def _read_concept_description_as_sequence( exception.path._prepend(ElementSegment(next_element)) raise + if reader_and_setter.id_short is None: + raise DeserializationException("The required property 'idShort' is missing") + if reader_and_setter.id is None: raise DeserializationException("The required property 'id' is missing") return aas_types.ConceptDescription( + reader_and_setter.id_short, reader_and_setter.id, reader_and_setter.extensions, reader_and_setter.category, - reader_and_setter.id_short, reader_and_setter.display_name, reader_and_setter.description, reader_and_setter.administration, @@ -23945,8 +23954,7 @@ def _write_asset_administration_shell_as_sequence( if that.category is not None: self._write_str_property("category", that.category) - if that.id_short is not None: - self._write_str_property("idShort", that.id_short) + self._write_str_property("idShort", that.id_short) if that.display_name is not None: if len(that.display_name) == 0: @@ -24172,8 +24180,7 @@ def _write_submodel_as_sequence(self, that: aas_types.Submodel) -> None: if that.category is not None: self._write_str_property("category", that.category) - if that.id_short is not None: - self._write_str_property("idShort", that.id_short) + self._write_str_property("idShort", that.id_short) if that.display_name is not None: if len(that.display_name) == 0: @@ -25892,8 +25899,7 @@ def _write_concept_description_as_sequence( if that.category is not None: self._write_str_property("category", that.category) - if that.id_short is not None: - self._write_str_property("idShort", that.id_short) + self._write_str_property("idShort", that.id_short) if that.display_name is not None: if len(that.display_name) == 0: diff --git a/docs/source/getting_started/create_get_set.rst b/docs/source/getting_started/create_get_set.rst index 90641c26..da0d5f07 100644 --- a/docs/source/getting_started/create_get_set.rst +++ b/docs/source/getting_started/create_get_set.rst @@ -60,6 +60,7 @@ The submodel will contain two elements, a property and a blob. # Nest the elements in a submodel submodel = aas_types.Submodel( + id_short="someIdShort", id="some-unique-global-identifier", submodel_elements=[ some_element, @@ -72,7 +73,7 @@ The submodel will contain two elements, a property and a blob. submodels=[submodel] ) - # You can access the propreties from the children as well. + # You can access the properties from the children as well. environment.submodels[0].submodel_elements[1].value = b'\xC0\x01\xCA\xFE' # Now you can do something with the environment... diff --git a/docs/source/getting_started/iterate_and_transform.rst b/docs/source/getting_started/iterate_and_transform.rst index 299f56aa..1958453b 100644 --- a/docs/source/getting_started/iterate_and_transform.rst +++ b/docs/source/getting_started/iterate_and_transform.rst @@ -37,6 +37,7 @@ Here is a short example how you can get all the properties from an environment w environment = aas_types.Environment( submodels=[ aas_types.Submodel( + id_short="someIdShort", id="some-unique-global-identifier", submodel_elements=[ aas_types.Property( @@ -114,6 +115,7 @@ Let us re-write the above example related to :py:meth:`~aas_core3.types.Class.de environment = aas_types.Environment( submodels=[ aas_types.Submodel( + id_short="someIdShort", id="some-unique-global-identifier", submodel_elements=[ aas_types.Property( diff --git a/docs/source/getting_started/jsonize.rst b/docs/source/getting_started/jsonize.rst index 6f2baa32..f5645e52 100644 --- a/docs/source/getting_started/jsonize.rst +++ b/docs/source/getting_started/jsonize.rst @@ -22,6 +22,7 @@ Here is a snippet that converts the environment first into a JSON-able mapping, environment = aas_types.Environment( submodels=[ aas_types.Submodel( + id_short="someIdShort", id="some-unique-global-identifier", submodel_elements=[ aas_types.Property( @@ -47,6 +48,7 @@ Expected output: { "submodels": [ { + "idShort": "someIdShort", "id": "some-unique-global-identifier", "submodelElements": [ { @@ -80,6 +82,7 @@ Here is an example snippet: { "submodels": [ { + "idShort": "someIdShort", "id": "some-unique-global-identifier", "submodelElements": [ { diff --git a/docs/source/getting_started/verify.rst b/docs/source/getting_started/verify.rst index 63340b95..632442b0 100644 --- a/docs/source/getting_started/verify.rst +++ b/docs/source/getting_started/verify.rst @@ -19,8 +19,8 @@ Here is a short example snippet: environment = aas_types.Environment( submodels=[ aas_types.Submodel( + id_short="someIdShort", id="some-unique-global-identifier", - id_short="someIdentifier", submodel_elements=[ aas_types.Property( # The ID-shorts must be proper variable names, diff --git a/docs/source/getting_started/xmlize.rst b/docs/source/getting_started/xmlize.rst index c78c8056..4bbecab5 100644 --- a/docs/source/getting_started/xmlize.rst +++ b/docs/source/getting_started/xmlize.rst @@ -22,6 +22,7 @@ Here is an example snippet: environment = aas_types.Environment( submodels=[ aas_types.Submodel( + id_short="someIdShort", id="some-unique-global-identifier", submodel_elements=[ aas_types.Property( @@ -43,7 +44,7 @@ Expected output: .. testoutput:: - some-unique-global-identifiersome_propertyxs:int1984 + someIdShortsome-unique-global-identifiersome_propertyxs:int1984 De-serialize @@ -64,7 +65,9 @@ Here is a snippet which parses XML as text and then de-serializes it into an ins text = ( "" + - "some-unique-global-identifier" + + "" + + "someIdShort" + "some-unique-global-identifier" + "someProperty" + "xs:boolean" + "" diff --git a/requirements-dev.txt b/requirements-dev.txt index 368e76ab..9f2397a7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,5 +4,5 @@ pylint==2.15.4 coverage>=6.5.0,<7 pyinstaller>=5<6 twine -aas-core-meta@git+https://github.com/aas-core-works/aas-core-meta@3191ea5#egg=aas-core-meta -aas-core-codegen@git+https://github.com/aas-core-works/aas-core-codegen@9b47d57#egg=aas-core-codegen +aas-core-meta@git+https://github.com/aas-core-works/aas-core-meta@02712de#egg=aas-core-meta +aas-core-codegen@git+https://github.com/aas-core-works/aas-core-codegen@3262e99#egg=aas-core-codegen