Skip to content

Commit

Permalink
Check explicitly for invalid model types
Browse files Browse the repository at this point in the history
We explicitly check during the JSON de-serialization that model types
correspond to the expected model types. We need to be particularly
careful with concrete classes without descendants with a mandatory
``modelType``, as they do not necessarily require a model type for
de-serialization, but the specs mandate it for reasons of backward
compatibility.

The code corresponds to [aas-core-codegen cd92d208], and the test data
corresponds to [aas-core3.0-testgen 9e523511c].

This is related to the issue #32, which discovered the problematic in
the first place.

[aas-core-codegen cd92d208]: aas-core-works/aas-core-codegen@cd92d208
[aas-core3.0-testgen 9e523511c]: aas-core-works/aas-core3.0-testgen@9e523511c
  • Loading branch information
mristin committed Jul 7, 2024
1 parent c07821b commit bc07a2a
Show file tree
Hide file tree
Showing 37 changed files with 453 additions and 17 deletions.
145 changes: 128 additions & 17 deletions aas_core3/jsonization.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,11 +1114,18 @@ def asset_administration_shell_from_jsonable(

setter = _SetterForAssetAdministrationShell()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "AssetAdministrationShell":
raise DeserializationException(
f"Invalid modelType, expected 'AssetAdministrationShell', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_ASSET_ADMINISTRATION_SHELL.get(key)
if setter_method is None:
Expand Down Expand Up @@ -1714,11 +1721,17 @@ def submodel_from_jsonable(jsonable: Jsonable) -> aas_types.Submodel:

setter = _SetterForSubmodel()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Submodel":
raise DeserializationException(
f"Invalid modelType, expected 'Submodel', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_SUBMODEL.get(key)
if setter_method is None:
Expand Down Expand Up @@ -2374,11 +2387,18 @@ def submodel_element_list_from_jsonable(

setter = _SetterForSubmodelElementList()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "SubmodelElementList":
raise DeserializationException(
f"Invalid modelType, expected 'SubmodelElementList', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_SUBMODEL_ELEMENT_LIST.get(key)
if setter_method is None:
Expand Down Expand Up @@ -2646,11 +2666,18 @@ def submodel_element_collection_from_jsonable(

setter = _SetterForSubmodelElementCollection()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "SubmodelElementCollection":
raise DeserializationException(
f"Invalid modelType, expected 'SubmodelElementCollection', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_SUBMODEL_ELEMENT_COLLECTION.get(key)
if setter_method is None:
Expand Down Expand Up @@ -2941,11 +2968,17 @@ def property_from_jsonable(jsonable: Jsonable) -> aas_types.Property:

setter = _SetterForProperty()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Property":
raise DeserializationException(
f"Invalid modelType, expected 'Property', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_PROPERTY.get(key)
if setter_method is None:
Expand Down Expand Up @@ -3218,11 +3251,18 @@ def multi_language_property_from_jsonable(

setter = _SetterForMultiLanguageProperty()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "MultiLanguageProperty":
raise DeserializationException(
f"Invalid modelType, expected 'MultiLanguageProperty', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_MULTI_LANGUAGE_PROPERTY.get(key)
if setter_method is None:
Expand Down Expand Up @@ -3482,11 +3522,17 @@ def range_from_jsonable(jsonable: Jsonable) -> aas_types.Range:

setter = _SetterForRange()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Range":
raise DeserializationException(
f"Invalid modelType, expected 'Range', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_RANGE.get(key)
if setter_method is None:
Expand Down Expand Up @@ -3732,11 +3778,18 @@ def reference_element_from_jsonable(jsonable: Jsonable) -> aas_types.ReferenceEl

setter = _SetterForReferenceElement()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "ReferenceElement":
raise DeserializationException(
f"Invalid modelType, expected 'ReferenceElement', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_REFERENCE_ELEMENT.get(key)
if setter_method is None:
Expand Down Expand Up @@ -3986,11 +4039,17 @@ def blob_from_jsonable(jsonable: Jsonable) -> aas_types.Blob:

setter = _SetterForBlob()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Blob":
raise DeserializationException(
f"Invalid modelType, expected 'Blob', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_BLOB.get(key)
if setter_method is None:
Expand Down Expand Up @@ -4244,11 +4303,17 @@ def file_from_jsonable(jsonable: Jsonable) -> aas_types.File:

setter = _SetterForFile()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "File":
raise DeserializationException(
f"Invalid modelType, expected 'File', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_FILE.get(key)
if setter_method is None:
Expand Down Expand Up @@ -4529,11 +4594,18 @@ def annotated_relationship_element_from_jsonable(

setter = _SetterForAnnotatedRelationshipElement()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "AnnotatedRelationshipElement":
raise DeserializationException(
f"Invalid modelType, expected 'AnnotatedRelationshipElement', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_ANNOTATED_RELATIONSHIP_ELEMENT.get(key)
if setter_method is None:
Expand Down Expand Up @@ -4841,11 +4913,17 @@ def entity_from_jsonable(jsonable: Jsonable) -> aas_types.Entity:

setter = _SetterForEntity()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Entity":
raise DeserializationException(
f"Invalid modelType, expected 'Entity', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_ENTITY.get(key)
if setter_method is None:
Expand Down Expand Up @@ -5386,11 +5464,18 @@ def basic_event_element_from_jsonable(

setter = _SetterForBasicEventElement()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "BasicEventElement":
raise DeserializationException(
f"Invalid modelType, expected 'BasicEventElement', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_BASIC_EVENT_ELEMENT.get(key)
if setter_method is None:
Expand Down Expand Up @@ -5713,11 +5798,17 @@ def operation_from_jsonable(jsonable: Jsonable) -> aas_types.Operation:

setter = _SetterForOperation()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Operation":
raise DeserializationException(
f"Invalid modelType, expected 'Operation', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_OPERATION.get(key)
if setter_method is None:
Expand Down Expand Up @@ -6002,11 +6093,17 @@ def capability_from_jsonable(jsonable: Jsonable) -> aas_types.Capability:

setter = _SetterForCapability()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "Capability":
raise DeserializationException(
f"Invalid modelType, expected 'Capability', " f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_CAPABILITY.get(key)
if setter_method is None:
Expand Down Expand Up @@ -6223,11 +6320,18 @@ def concept_description_from_jsonable(

setter = _SetterForConceptDescription()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "ConceptDescription":
raise DeserializationException(
f"Invalid modelType, expected 'ConceptDescription', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_CONCEPT_DESCRIPTION.get(key)
if setter_method is None:
Expand Down Expand Up @@ -7495,11 +7599,18 @@ def data_specification_iec_61360_from_jsonable(

setter = _SetterForDataSpecificationIEC61360()

if "modelType" not in jsonable:
model_type = jsonable.get("modelType", None)
if model_type is None:
raise DeserializationException(
"Expected the property modelType, but found none"
)

if model_type != "DataSpecificationIec61360":
raise DeserializationException(
f"Invalid modelType, expected 'DataSpecificationIec61360', "
f"but got: {model_type!r}"
)

for key, jsonable_value in jsonable.items():
setter_method = _SETTER_MAP_FOR_DATA_SPECIFICATION_IEC_61360.get(key)
if setter_method is None:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"submodels": [
{
"id": "something_48c66017",
"modelType": "Submodel",
"submodelElements": [
{
"first": {
"keys": [
{
"type": "GlobalReference",
"value": "urn:another-company01:f390f801"
}
],
"type": "ExternalReference"
},
"idShort": "something3fdd3eb4",
"modelType": "aCompletelyInvalidModelType",
"second": {
"keys": [
{
"type": "GlobalReference",
"value": "urn:an-example05:b7bf2725"
}
],
"type": "ExternalReference"
}
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
submodels[0].submodelElements[0]: Unexpected model type for SubmodelElement: aCompletelyInvalidModelType
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"assetAdministrationShells": [
{
"assetInformation": {
"assetKind": "NotApplicable",
"globalAssetId": "something_eea66fa1"
},
"id": "something_142922d6",
"modelType": "aCompletelyInvalidModelType"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
assetAdministrationShells[0]: Invalid modelType, expected 'AssetAdministrationShell', but got: 'aCompletelyInvalidModelType'
Loading

0 comments on commit bc07a2a

Please sign in to comment.