Model API
core
Identifiable (BaseModel)
Base class for all identifiable classes that have an identifier, that allows to identify these objects.
If no id is set, the id function of the python object is used. Otherwise, a uuid is generated.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id |
str |
Global id of the object. |
required |
Source code in aas_middleware\model\core.py
class Identifiable(BaseModel):
"""
Base class for all identifiable classes that have an identifier, that allows to identify these objects.
If no id is set, the id function of the python object is used. Otherwise, a uuid is generated.
Args:
id (str): Global id of the object.
"""
id: IdString
@model_validator(mode="before")
@classmethod
def check_id_and_id_short(cls, data: Any) -> Any:
potential_id = get_id(data)
assert potential_id, "Either id or id_short must be set"
return {"id": potential_id}
data_model
DataModel (BaseModel)
The data model is a container that allows to store all models of a data model and provides methods to access them easily by their id or type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
**data |
Dict[str, Any] |
The data to load into the data model (used by pydantic). |
{} |
Attributes:
Name | Type | Description |
---|---|---|
_models_key_id |
Dict[str, Identifiable] |
The dictionary of models with their id as key. |
_top_level_models |
Dict[str, List[str]] |
The dictionary of top level models with their type as key. |
_models_key_type |
Dict[str, List[str]] |
The dictionary of models with their type as key. |
_reference_info_dict_for_referencing |
Dict[str, Dict[str, ReferenceInfo]] |
The dictionary of reference infos with keys from the referencing model to the referenced model. |
_reference_info_dict_for_referenced |
Dict[str, Dict[str, ReferenceInfo]] |
The dictionary of reference infos with keys from the referenced model to the referencing model. |
Source code in aas_middleware\model\data_model.py
class DataModel(BaseModel):
"""
The data model is a container that allows to store all models of a data model and provides methods to access them easily by their id or type.
Args:
**data (Dict[str, Any]): The data to load into the data model (used by pydantic).
Attributes:
_models_key_id (Dict[str, Identifiable]): The dictionary of models with their id as key.
_top_level_models (Dict[str, List[str]]): The dictionary of top level models with their type as key.
_models_key_type (Dict[str, List[str]]): The dictionary of models with their type as key.
_reference_info_dict_for_referencing (Dict[str, Dict[str, ReferenceInfo]]): The dictionary of reference infos with keys from the referencing model to the referenced model.
_reference_info_dict_for_referenced (Dict[str, Dict[str, ReferenceInfo]]): The dictionary of reference infos with keys from the referenced model to the referencing model.
"""
_key_ids_models: Dict[str, Identifiable] = {}
_top_level_models: Dict[str, List[str]] = {}
_models_key_type: Dict[str, List[str]] = {}
_reference_infos: Set[ReferenceInfo] = set()
_reference_info_dict_for_referencing: Dict[str, Dict[str, ReferenceInfo]] = {}
_reference_info_dict_for_referenced: Dict[str, Dict[str, ReferenceInfo]] = {}
_schemas: Dict[str, Type[Any]] = {}
_top_level_schemas: Set[str] = set()
_schema_reference_infos: Set[ReferenceInfo] = set()
_schema_reference_info_for_referencing: Dict[str, Dict[str, ReferenceInfo]] = {}
_schema_reference_info_for_referenced: Dict[str, Dict[str, ReferenceInfo]] = {}
def __init__(self, **data: Dict[str, Any]):
super().__init__(**data)
try:
Identifiable.model_validate(self)
self.add_model(self)
except ValidationError:
for attribute_value in get_value_attributes(self).values():
if is_identifiable_container(attribute_value):
self.add(*attribute_value)
else:
self.add(attribute_value)
@classmethod
def from_models(
cls, *models: Tuple[Identifiable], **data: Dict[str, Any]
) -> DataModel:
"""
Method to create a data model from a list of provided models.
Args:
models (Tuple[Identifiable]): The models to load into the data model.
data (Dict[str, Any]): The data to load into the data model.
Returns:
DataModel: The data model with loaded models
"""
data_model = cls(**data)
data_model.add(*models)
return data_model
@classmethod
def from_model_types(cls, *model_types: Tuple[Type[Identifiable]], **data: Dict[str, Any]) -> DataModel:
"""
Method to create a data model a provided list of model types.
Args:
model_types (Tuple[Type[Identifiable]]): The model types to load into the data model.
data (Dict[str, Any]): The data to load into the data model.
Returns:
DataModel: The data model with loaded models
"""
data_model = cls(**data)
for model_type in model_types:
data_model.add_schema(model_type)
return data_model
@property
def model_ids(self) -> Set[str]:
"""
Property to get the ids of all contained models.
Returns:
Set[str]: The set of ids.
"""
return set(str(key) for key in self._key_ids_models.keys())
def get_contained_ids(self) -> Set[str]:
"""
Method to get all ids of contained models.
Returns:
Set[str]: The set of ids.
"""
return self.model_ids
def add(self, *models: Identifiable) -> None:
"""
Method to add models to the data model.
Args:
*models (Tuple[Identifiable]): The models to load into the data model.
"""
for model in models:
self.add_model(model)
def add_schema(self, schema: Type[Identifiable]) -> None:
"""
Method to add a schema of the data model.
Args:
schema (Type[Identifiable]): The schema to load.
"""
all_schemas, schema_reference_infos = ReferenceFinder.find_schema_references(schema)
self._add_contained_schemas(all_schemas)
self._add_top_level_schema(schema)
self._add_schema_references_to_referencing_schemas_dict(schema_reference_infos)
def add_model(self, model: Identifiable) -> None:
"""
Method to load a model of the data model.
Args:
model (Identifiable): The model to load.
"""
# Identifiable.model_validate(model)
model_id = get_id_with_patch(model)
if model_id in self.model_ids:
raise ValueError(f"Model with id {model_id} already loaded.")
self.add_schema(type(model))
all_identifiables, reference_infos = ReferenceFinder.find(model)
self._add_contained_models(model, all_identifiables)
self._add_top_level_model(model)
self._add_references_to_referencing_models_dict(reference_infos)
def check_different_model_with_same_id_contained(self, model: Identifiable) -> bool:
"""
Method to check if a model is already contained in the data model.
Args:
model (Identifiable): The model to check.
Returns:
bool: True if the model is already contained, False otherwise.
"""
model_id = get_id_with_patch(model)
if model_id in self.model_ids:
same_id_model = self.get_model(model_id)
if not same_id_model == model:
return True
return False
def _add_contained_models(
self, top_level_model: Identifiable, contained_models: List[Identifiable]
) -> None:
"""
Method to load all contained models of a model.
Args:
top_level_model (Identifiable): The top level model to load.
contained_models (List[Identifiable]): The contained models to load.
"""
for contained_model in contained_models:
contained_model_id = get_id_with_patch(contained_model)
if contained_model_id in self.model_ids:
same_id_model = self.get_model(contained_model_id)
if not models_are_equal(same_id_model, contained_model):
raise ValueError(
f"Model with id {contained_model_id} already loaded but with different content. Make sure to only load models with unique ids."
)
replace_attribute_with_model(top_level_model, same_id_model)
continue
self._add_model(contained_model)
def _add_contained_schemas(
self, contained_schemas: List[Type[Identifiable]]
) -> None:
"""
Method to load all contained schemas of a schema.
Args:
top_level_schema (Type[Identifiable]): The top level schema to load.
contained_schemas (List[Type[Identifiable]]): The contained schemas to load.
"""
for contained_schema in contained_schemas:
self._schemas[contained_schema.__name__] = contained_schema
def patch_schema_references(self) -> None:
"""
Function tries to patch schema reference infos to represent a more realistic data model.
ReferenceInfos of Type Reference are patched so that another ReferenceInfo is added to every schema that has a class name that contains the reference id.
ReferenceInfos of Type Attribute are patched so that another ReferenceInfo is added to every schema that has a class name that contains the reference id.
"""
reference_infos = patch_references(self._schema_reference_infos, self._schemas.values())
self._schema_reference_infos = reference_infos
self._add_schema_references_to_referencing_schemas_dict(reference_infos)
def _add_references_to_referencing_models_dict(
self, reference_infos: Set[ReferenceInfo]
) -> None:
"""
Method to add information about referencing model ids of the input model.
Args:
model (Identifiable): The model to add the information for.
"""
self._reference_infos = self._reference_infos | reference_infos
for reference_info in reference_infos:
referencing_model_id = reference_info.identifiable_id
referenced_model_id = reference_info.reference_id
if not referencing_model_id in self._reference_info_dict_for_referencing:
self._reference_info_dict_for_referencing[referencing_model_id] = {}
self._reference_info_dict_for_referencing[referencing_model_id][
referenced_model_id
] = reference_info
if not referenced_model_id in self._reference_info_dict_for_referenced:
self._reference_info_dict_for_referenced[referenced_model_id] = {}
self._reference_info_dict_for_referenced[referenced_model_id][
referencing_model_id
] = reference_info
def _add_schema_references_to_referencing_schemas_dict(self, reference_infos: Set[ReferenceInfo]) -> None:
"""
Method to add information about referencing schema ids of the input schema.
Args:
schema (Type[Identifiable]): The schema to add the information for.
"""
self._schema_reference_infos = self._schema_reference_infos | reference_infos
for reference_info in reference_infos:
referencing_schema_id = reference_info.identifiable_id
referenced_schema_id = reference_info.reference_id
if not referencing_schema_id in self._schema_reference_info_for_referencing:
self._schema_reference_info_for_referencing[referencing_schema_id] = {}
self._schema_reference_info_for_referencing[referencing_schema_id][
referenced_schema_id
] = reference_info
if not referenced_schema_id in self._schema_reference_info_for_referenced:
self._schema_reference_info_for_referenced[referenced_schema_id] = {}
self._schema_reference_info_for_referenced[referenced_schema_id][
referencing_schema_id
] = reference_info
def _add_model(self, model: Identifiable) -> None:
"""
Method to add a model to the data model.
Args:
model (Identifiable): The model to add.
"""
model_id = get_id_with_patch(model)
if model_id in self.model_ids:
raise ValueError(f"Model with id {model_id} already loaded.")
self._key_ids_models[model_id] = model
type_name = model.__class__.__name__.split(".")[-1]
if not type_name in self._models_key_type:
self._models_key_type[type_name] = []
self._models_key_type[type_name].append(model_id)
def _add_top_level_model(self, model: Identifiable) -> None:
"""
Method to add a model to the data model.
Args:
model (Identifiable): The model to add.
"""
type_name = model.__class__.__name__.split(".")[-1]
underscore_type_name = convert_camel_case_to_underscrore_str(type_name)
if not underscore_type_name in self._top_level_models:
self._top_level_models[underscore_type_name] = []
self._top_level_models[underscore_type_name].append(get_id_with_patch(model))
def _add_top_level_schema(self, schema: Type[Identifiable]) -> None:
"""
Method to add a schema to the data model.
Args:
schema (Type[Identifiable]): The schema to add.
"""
schema_name = schema.__name__
if not schema_name in self._top_level_schemas:
self._top_level_schemas.add(schema_name)
def from_dict(self, data: NESTED_DICT, types: List[Type]) -> None:
"""
Method to load a data model from a dict.
Args:
data (NESTED_DICT): The dict to load the data model from.
"""
for attribute_name, attribute_value in data.items():
class_name = convert_under_score_to_camel_case_str(attribute_name)
for type_ in types:
if type_.__name__ == class_name:
type_for_attribute_values = type_
break
else:
raise ValueError(f"Type {class_name} not supported.")
for model_dict in attribute_value:
model = type_for_attribute_values(**model_dict)
self.add(model)
def dict(self) -> NESTED_DICT:
"""
Method to get the dict of the data model.
Returns:
NESTED_DICT: The dict of the data model.
"""
nested_dict = {}
for attribute_name, attribute_value in self.get_top_level_models().items():
nested_dict[attribute_name] = [
model.model_dump() for model in attribute_value
]
return nested_dict
def json(self) -> str:
"""
Method to get the json of the data model.
Returns:
str: The json of the data model.
"""
nested_dict = {}
for attribute_name, attribute_value in self.get_top_level_models().items():
# TODO: if a non-BaseModel object is loaded, this breakds down -> adjust this
nested_dict[attribute_name] = [
model.model_dump() for model in attribute_value
]
return json.dumps(nested_dict, indent=4, cls=DateTimeEncoder)
def get_top_level_models(self) -> Dict[str, List[Identifiable]]:
"""
Method to get all models of the data model.
Returns:
Dict[str, List[Identifiable]]: The dictionary of models.
"""
top_level_models = {}
for top_level_model_name, top_level_model_ids in self._top_level_models.items():
top_level_models[top_level_model_name] = [
self.get_model(model_id) for model_id in top_level_model_ids
]
return top_level_models
def get_top_level_types(self) -> List[Type[Identifiable]]:
"""
Method to get all types of the top level models in the data model.
Returns:
List[Type[Identifiable]]: The types of the top level models in the data model
"""
top_level_types = []
for schema_name in self._top_level_schemas:
top_level_types.append(self._schemas[schema_name])
return top_level_types
def get_models_of_type_name(self, model_type_name: str) -> List[Identifiable]:
"""
Method to get all models of a specific type.
Args:
model_type (str): The type of the models to get.
Returns:
List[Identifiable]: The list of models of the type.
"""
if not model_type_name in self._models_key_type:
raise ValueError(f"Model type {model_type_name} not supported.")
return [
self.get_model(model_id)
for model_id in self._models_key_type[model_type_name]
]
def get_models_of_type(self, model_type: Type[T]) -> List[T]:
"""
Method to get all models of a specific type.
Args:
model_type (Type[T]): The type of the models to get.
Returns:
List[T]: The list of models of the type.
"""
type_name = model_type.__name__.split(".")[-1]
return self.get_models_of_type_name(type_name)
def get_contained_models(self) -> List[Identifiable]:
"""
Method to get all models that are contained in the data model.
Returns:
List[Identifiable]: The list of models.
"""
return list(self._key_ids_models.values())
def get_referencing_info(
self, referenced_model: Identifiable
) -> List[ReferenceInfo]:
"""
Method to get all reference infos of a model.
Args:
referenced_model (Identifiable): The model to get the reference infos for.
Returns:
List[ReferenceInfo]: The list of reference infos.
"""
referenced_model_id = get_id_with_patch(referenced_model)
if not referenced_model_id in self._reference_info_dict_for_referenced:
return []
return list(
self._reference_info_dict_for_referenced[referenced_model_id].values()
)
def get_referencing_models(
self, referenced_model: Identifiable
) -> List[Identifiable]:
"""
Method to get all models that reference a specific model directly as an attribute or by its id.
Args:
referenced_model (Identifiable): The model to get the referencing models for.
Returns:
List[Identifiable]: The list of referencing models of the model.
"""
referenced_model_id = get_id_with_patch(referenced_model)
if not referenced_model_id in self._reference_info_dict_for_referenced:
return []
referencing_model_dict = self._reference_info_dict_for_referenced[
referenced_model_id
]
return [self.get_model(model_id) for model_id in referencing_model_dict]
def get_referencing_models_of_type(
self, referenced_model: Identifiable, referencing_model_type: Type[T]
) -> List[T]:
"""
Method to get all models that reference a specific model directly as an attribute or by its id.
Args:
referenced_model (Identifiable): The model to get the referencing models for.
referencing_model_type (Type[T]): The type of the referencing models to get.
Returns:
List[T]: The list of referencing models of the model.
"""
referenced_model_id = get_id_with_patch(referenced_model)
if not referenced_model_id in self._reference_info_dict_for_referenced:
return []
referencing_model_dict = self._reference_info_dict_for_referenced[
referenced_model_id
]
return [
self.get_model(model_id)
for model_id in referencing_model_dict
if isinstance(self.get_model(model_id), referencing_model_type)
]
def get_referenced_info(
self, referencing_model: Identifiable
) -> List[ReferenceInfo]:
"""
Method to get all reference infos of a model.
Args:
referencing_model (Identifiable): The model to get the reference infos for.
Returns:
List[ReferenceInfo]: The list of reference infos.
"""
referencing_model_id = get_id_with_patch(referencing_model)
if not referencing_model_id in self._reference_info_dict_for_referencing:
return []
return list(
self._reference_info_dict_for_referencing[referencing_model_id].values()
)
def get_referenced_models(
self, referencing_model: Identifiable
) -> List[Identifiable]:
"""
Method to get all models that are referenced by a specific model directly as an attribute or by its id.
Args:
referencing_model (Identifiable): The model to get the referenced models for.
Returns:
List[Identifiable]: The list of referenced models of the model.
"""
referencing_model_id = get_id_with_patch(referencing_model)
if not referencing_model_id in self._reference_info_dict_for_referencing:
return []
referenced_model_dict = self._reference_info_dict_for_referencing[
referencing_model_id
]
return [self.get_model(model_id) for model_id in referenced_model_dict if model_id in self.model_ids]
def get_referenced_models_of_type(
self, referencing_model: Identifiable, referenced_model_type: Type[T]
) -> List[T]:
"""
Method to get all models that are referenced by a specific model directly as an attribute or by its id.
Args:
referencing_model (Identifiable): The model to get the referenced models for.
referenced_model_type (Type[T]): The type of the referenced models to get.
Returns:
List[T]: The list of referenced models of the model.
"""
referencing_model_id = get_id_with_patch(referencing_model)
if not referencing_model_id in self._reference_info_dict_for_referencing:
return []
referenced_model_dict = self._reference_info_dict_for_referencing[
referencing_model_id
]
return [
self.get_model(model_id)
for model_id in referenced_model_dict
if isinstance(self.get_model(model_id), referenced_model_type)
]
def get_model(self, model_id: str) -> Identifiable:
"""
Method to get a model by its id.
Args:
model_id (str): The id of the model to get.
Returns:
Identifiable: The model.
"""
if model_id not in self.model_ids:
return None
return self._key_ids_models[model_id]
def contains_model(self, model_id: str) -> bool:
"""
Method to check if a model is contained in the data model.
Args:
model_id (str): The id of the model to check.
Returns:
bool: True if the model is contained, False otherwise.
"""
if self.get_model(model_id) is not None:
return True
return False
model_ids: Set[str]
property
readonly
Property to get the ids of all contained models.
Returns:
Type | Description |
---|---|
Set[str] |
The set of ids. |
add(self, *models)
Method to add models to the data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
*models |
Tuple[Identifiable] |
The models to load into the data model. |
() |
add_model(self, model)
Method to load a model of the data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Identifiable |
The model to load. |
required |
Source code in aas_middleware\model\data_model.py
def add_model(self, model: Identifiable) -> None:
"""
Method to load a model of the data model.
Args:
model (Identifiable): The model to load.
"""
# Identifiable.model_validate(model)
model_id = get_id_with_patch(model)
if model_id in self.model_ids:
raise ValueError(f"Model with id {model_id} already loaded.")
self.add_schema(type(model))
all_identifiables, reference_infos = ReferenceFinder.find(model)
self._add_contained_models(model, all_identifiables)
self._add_top_level_model(model)
self._add_references_to_referencing_models_dict(reference_infos)
add_schema(self, schema)
Method to add a schema of the data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Identifiable] |
The schema to load. |
required |
Source code in aas_middleware\model\data_model.py
def add_schema(self, schema: Type[Identifiable]) -> None:
"""
Method to add a schema of the data model.
Args:
schema (Type[Identifiable]): The schema to load.
"""
all_schemas, schema_reference_infos = ReferenceFinder.find_schema_references(schema)
self._add_contained_schemas(all_schemas)
self._add_top_level_schema(schema)
self._add_schema_references_to_referencing_schemas_dict(schema_reference_infos)
check_different_model_with_same_id_contained(self, model)
Method to check if a model is already contained in the data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Identifiable |
The model to check. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the model is already contained, False otherwise. |
Source code in aas_middleware\model\data_model.py
def check_different_model_with_same_id_contained(self, model: Identifiable) -> bool:
"""
Method to check if a model is already contained in the data model.
Args:
model (Identifiable): The model to check.
Returns:
bool: True if the model is already contained, False otherwise.
"""
model_id = get_id_with_patch(model)
if model_id in self.model_ids:
same_id_model = self.get_model(model_id)
if not same_id_model == model:
return True
return False
contains_model(self, model_id)
Method to check if a model is contained in the data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_id |
str |
The id of the model to check. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the model is contained, False otherwise. |
Source code in aas_middleware\model\data_model.py
dict(self)
Method to get the dict of the data model.
Returns:
Type | Description |
---|---|
NESTED_DICT |
The dict of the data model. |
Source code in aas_middleware\model\data_model.py
def dict(self) -> NESTED_DICT:
"""
Method to get the dict of the data model.
Returns:
NESTED_DICT: The dict of the data model.
"""
nested_dict = {}
for attribute_name, attribute_value in self.get_top_level_models().items():
nested_dict[attribute_name] = [
model.model_dump() for model in attribute_value
]
return nested_dict
from_dict(self, data, types)
Method to load a data model from a dict.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
NESTED_DICT |
The dict to load the data model from. |
required |
Source code in aas_middleware\model\data_model.py
def from_dict(self, data: NESTED_DICT, types: List[Type]) -> None:
"""
Method to load a data model from a dict.
Args:
data (NESTED_DICT): The dict to load the data model from.
"""
for attribute_name, attribute_value in data.items():
class_name = convert_under_score_to_camel_case_str(attribute_name)
for type_ in types:
if type_.__name__ == class_name:
type_for_attribute_values = type_
break
else:
raise ValueError(f"Type {class_name} not supported.")
for model_dict in attribute_value:
model = type_for_attribute_values(**model_dict)
self.add(model)
from_model_types(*model_types, **data)
classmethod
Method to create a data model a provided list of model types.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_types |
Tuple[Type[Identifiable]] |
The model types to load into the data model. |
() |
data |
Dict[str, Any] |
The data to load into the data model. |
{} |
Returns:
Type | Description |
---|---|
DataModel |
The data model with loaded models |
Source code in aas_middleware\model\data_model.py
@classmethod
def from_model_types(cls, *model_types: Tuple[Type[Identifiable]], **data: Dict[str, Any]) -> DataModel:
"""
Method to create a data model a provided list of model types.
Args:
model_types (Tuple[Type[Identifiable]]): The model types to load into the data model.
data (Dict[str, Any]): The data to load into the data model.
Returns:
DataModel: The data model with loaded models
"""
data_model = cls(**data)
for model_type in model_types:
data_model.add_schema(model_type)
return data_model
from_models(*models, **data)
classmethod
Method to create a data model from a list of provided models.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
models |
Tuple[Identifiable] |
The models to load into the data model. |
() |
data |
Dict[str, Any] |
The data to load into the data model. |
{} |
Returns:
Type | Description |
---|---|
DataModel |
The data model with loaded models |
Source code in aas_middleware\model\data_model.py
@classmethod
def from_models(
cls, *models: Tuple[Identifiable], **data: Dict[str, Any]
) -> DataModel:
"""
Method to create a data model from a list of provided models.
Args:
models (Tuple[Identifiable]): The models to load into the data model.
data (Dict[str, Any]): The data to load into the data model.
Returns:
DataModel: The data model with loaded models
"""
data_model = cls(**data)
data_model.add(*models)
return data_model
get_contained_ids(self)
get_contained_models(self)
Method to get all models that are contained in the data model.
Returns:
Type | Description |
---|---|
List[Identifiable] |
The list of models. |
get_model(self, model_id)
Method to get a model by its id.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_id |
str |
The id of the model to get. |
required |
Returns:
Type | Description |
---|---|
Identifiable |
The model. |
Source code in aas_middleware\model\data_model.py
get_models_of_type(self, model_type)
Method to get all models of a specific type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_type |
Type[T] |
The type of the models to get. |
required |
Returns:
Type | Description |
---|---|
List[T] |
The list of models of the type. |
Source code in aas_middleware\model\data_model.py
def get_models_of_type(self, model_type: Type[T]) -> List[T]:
"""
Method to get all models of a specific type.
Args:
model_type (Type[T]): The type of the models to get.
Returns:
List[T]: The list of models of the type.
"""
type_name = model_type.__name__.split(".")[-1]
return self.get_models_of_type_name(type_name)
get_models_of_type_name(self, model_type_name)
Method to get all models of a specific type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_type |
str |
The type of the models to get. |
required |
Returns:
Type | Description |
---|---|
List[Identifiable] |
The list of models of the type. |
Source code in aas_middleware\model\data_model.py
def get_models_of_type_name(self, model_type_name: str) -> List[Identifiable]:
"""
Method to get all models of a specific type.
Args:
model_type (str): The type of the models to get.
Returns:
List[Identifiable]: The list of models of the type.
"""
if not model_type_name in self._models_key_type:
raise ValueError(f"Model type {model_type_name} not supported.")
return [
self.get_model(model_id)
for model_id in self._models_key_type[model_type_name]
]
get_referenced_info(self, referencing_model)
Method to get all reference infos of a model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
referencing_model |
Identifiable |
The model to get the reference infos for. |
required |
Returns:
Type | Description |
---|---|
List[ReferenceInfo] |
The list of reference infos. |
Source code in aas_middleware\model\data_model.py
def get_referenced_info(
self, referencing_model: Identifiable
) -> List[ReferenceInfo]:
"""
Method to get all reference infos of a model.
Args:
referencing_model (Identifiable): The model to get the reference infos for.
Returns:
List[ReferenceInfo]: The list of reference infos.
"""
referencing_model_id = get_id_with_patch(referencing_model)
if not referencing_model_id in self._reference_info_dict_for_referencing:
return []
return list(
self._reference_info_dict_for_referencing[referencing_model_id].values()
)
get_referenced_models(self, referencing_model)
Method to get all models that are referenced by a specific model directly as an attribute or by its id.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
referencing_model |
Identifiable |
The model to get the referenced models for. |
required |
Returns:
Type | Description |
---|---|
List[Identifiable] |
The list of referenced models of the model. |
Source code in aas_middleware\model\data_model.py
def get_referenced_models(
self, referencing_model: Identifiable
) -> List[Identifiable]:
"""
Method to get all models that are referenced by a specific model directly as an attribute or by its id.
Args:
referencing_model (Identifiable): The model to get the referenced models for.
Returns:
List[Identifiable]: The list of referenced models of the model.
"""
referencing_model_id = get_id_with_patch(referencing_model)
if not referencing_model_id in self._reference_info_dict_for_referencing:
return []
referenced_model_dict = self._reference_info_dict_for_referencing[
referencing_model_id
]
return [self.get_model(model_id) for model_id in referenced_model_dict if model_id in self.model_ids]
get_referenced_models_of_type(self, referencing_model, referenced_model_type)
Method to get all models that are referenced by a specific model directly as an attribute or by its id.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
referencing_model |
Identifiable |
The model to get the referenced models for. |
required |
referenced_model_type |
Type[T] |
The type of the referenced models to get. |
required |
Returns:
Type | Description |
---|---|
List[T] |
The list of referenced models of the model. |
Source code in aas_middleware\model\data_model.py
def get_referenced_models_of_type(
self, referencing_model: Identifiable, referenced_model_type: Type[T]
) -> List[T]:
"""
Method to get all models that are referenced by a specific model directly as an attribute or by its id.
Args:
referencing_model (Identifiable): The model to get the referenced models for.
referenced_model_type (Type[T]): The type of the referenced models to get.
Returns:
List[T]: The list of referenced models of the model.
"""
referencing_model_id = get_id_with_patch(referencing_model)
if not referencing_model_id in self._reference_info_dict_for_referencing:
return []
referenced_model_dict = self._reference_info_dict_for_referencing[
referencing_model_id
]
return [
self.get_model(model_id)
for model_id in referenced_model_dict
if isinstance(self.get_model(model_id), referenced_model_type)
]
get_referencing_info(self, referenced_model)
Method to get all reference infos of a model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
referenced_model |
Identifiable |
The model to get the reference infos for. |
required |
Returns:
Type | Description |
---|---|
List[ReferenceInfo] |
The list of reference infos. |
Source code in aas_middleware\model\data_model.py
def get_referencing_info(
self, referenced_model: Identifiable
) -> List[ReferenceInfo]:
"""
Method to get all reference infos of a model.
Args:
referenced_model (Identifiable): The model to get the reference infos for.
Returns:
List[ReferenceInfo]: The list of reference infos.
"""
referenced_model_id = get_id_with_patch(referenced_model)
if not referenced_model_id in self._reference_info_dict_for_referenced:
return []
return list(
self._reference_info_dict_for_referenced[referenced_model_id].values()
)
get_referencing_models(self, referenced_model)
Method to get all models that reference a specific model directly as an attribute or by its id.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
referenced_model |
Identifiable |
The model to get the referencing models for. |
required |
Returns:
Type | Description |
---|---|
List[Identifiable] |
The list of referencing models of the model. |
Source code in aas_middleware\model\data_model.py
def get_referencing_models(
self, referenced_model: Identifiable
) -> List[Identifiable]:
"""
Method to get all models that reference a specific model directly as an attribute or by its id.
Args:
referenced_model (Identifiable): The model to get the referencing models for.
Returns:
List[Identifiable]: The list of referencing models of the model.
"""
referenced_model_id = get_id_with_patch(referenced_model)
if not referenced_model_id in self._reference_info_dict_for_referenced:
return []
referencing_model_dict = self._reference_info_dict_for_referenced[
referenced_model_id
]
return [self.get_model(model_id) for model_id in referencing_model_dict]
get_referencing_models_of_type(self, referenced_model, referencing_model_type)
Method to get all models that reference a specific model directly as an attribute or by its id.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
referenced_model |
Identifiable |
The model to get the referencing models for. |
required |
referencing_model_type |
Type[T] |
The type of the referencing models to get. |
required |
Returns:
Type | Description |
---|---|
List[T] |
The list of referencing models of the model. |
Source code in aas_middleware\model\data_model.py
def get_referencing_models_of_type(
self, referenced_model: Identifiable, referencing_model_type: Type[T]
) -> List[T]:
"""
Method to get all models that reference a specific model directly as an attribute or by its id.
Args:
referenced_model (Identifiable): The model to get the referencing models for.
referencing_model_type (Type[T]): The type of the referencing models to get.
Returns:
List[T]: The list of referencing models of the model.
"""
referenced_model_id = get_id_with_patch(referenced_model)
if not referenced_model_id in self._reference_info_dict_for_referenced:
return []
referencing_model_dict = self._reference_info_dict_for_referenced[
referenced_model_id
]
return [
self.get_model(model_id)
for model_id in referencing_model_dict
if isinstance(self.get_model(model_id), referencing_model_type)
]
get_top_level_models(self)
Method to get all models of the data model.
Returns:
Type | Description |
---|---|
Dict[str, List[Identifiable]] |
The dictionary of models. |
Source code in aas_middleware\model\data_model.py
def get_top_level_models(self) -> Dict[str, List[Identifiable]]:
"""
Method to get all models of the data model.
Returns:
Dict[str, List[Identifiable]]: The dictionary of models.
"""
top_level_models = {}
for top_level_model_name, top_level_model_ids in self._top_level_models.items():
top_level_models[top_level_model_name] = [
self.get_model(model_id) for model_id in top_level_model_ids
]
return top_level_models
get_top_level_types(self)
Method to get all types of the top level models in the data model.
Returns:
Type | Description |
---|---|
List[Type[Identifiable]] |
The types of the top level models in the data model |
Source code in aas_middleware\model\data_model.py
def get_top_level_types(self) -> List[Type[Identifiable]]:
"""
Method to get all types of the top level models in the data model.
Returns:
List[Type[Identifiable]]: The types of the top level models in the data model
"""
top_level_types = []
for schema_name in self._top_level_schemas:
top_level_types.append(self._schemas[schema_name])
return top_level_types
json(self)
Method to get the json of the data model.
Returns:
Type | Description |
---|---|
str |
The json of the data model. |
Source code in aas_middleware\model\data_model.py
def json(self) -> str:
"""
Method to get the json of the data model.
Returns:
str: The json of the data model.
"""
nested_dict = {}
for attribute_name, attribute_value in self.get_top_level_models().items():
# TODO: if a non-BaseModel object is loaded, this breakds down -> adjust this
nested_dict[attribute_name] = [
model.model_dump() for model in attribute_value
]
return json.dumps(nested_dict, indent=4, cls=DateTimeEncoder)
model_post_init(/, self, context)
This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that's what pydantic-core passes when calling it.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
self |
BaseModel |
The BaseModel instance. |
required |
context |
Any |
The context. |
required |
Source code in aas_middleware\model\data_model.py
def init_private_attributes(self: BaseModel, context: Any, /) -> None:
"""This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that's what pydantic-core passes when calling it.
Args:
self: The BaseModel instance.
context: The context.
"""
if getattr(self, '__pydantic_private__', None) is None:
pydantic_private = {}
for name, private_attr in self.__private_attributes__.items():
default = private_attr.get_default()
if default is not PydanticUndefined:
pydantic_private[name] = default
object_setattr(self, '__pydantic_private__', pydantic_private)
patch_schema_references(self)
Function tries to patch schema reference infos to represent a more realistic data model.
ReferenceInfos of Type Reference are patched so that another ReferenceInfo is added to every schema that has a class name that contains the reference id. ReferenceInfos of Type Attribute are patched so that another ReferenceInfo is added to every schema that has a class name that contains the reference id.
Source code in aas_middleware\model\data_model.py
def patch_schema_references(self) -> None:
"""
Function tries to patch schema reference infos to represent a more realistic data model.
ReferenceInfos of Type Reference are patched so that another ReferenceInfo is added to every schema that has a class name that contains the reference id.
ReferenceInfos of Type Attribute are patched so that another ReferenceInfo is added to every schema that has a class name that contains the reference id.
"""
reference_infos = patch_references(self._schema_reference_infos, self._schemas.values())
self._schema_reference_infos = reference_infos
self._add_schema_references_to_referencing_schemas_dict(reference_infos)
DateTimeEncoder (JSONEncoder)
Source code in aas_middleware\model\data_model.py
default(self, o)
Implement this method in a subclass such that it returns
a serializable object for o
, or calls the base implementation
(to raise a TypeError
).
For example, to support arbitrary iterators, you could implement default like this::
def default(self, o):
!!! try
iterable = iter(o)
except TypeError:
pass
!!! else
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
data_model_rebuilder
DataModelRebuilder
Source code in aas_middleware\model\data_model_rebuilder.py
class DataModelRebuilder:
def __init__(self, data_model: DataModel):
"""
Rebuilds a data model with either direct or indirect references.
Args:
data_model (DataModel): The data model to rebuild.
"""
self.data_model = data_model
def rebuild_data_model_with_associations(self) -> DataModel:
"""
Rebuilds all models in the data model with assosiations.
Returns:
DataModel: The rebuilt data model.
"""
raise NotImplementedError
def rebuild_data_model_for_AAS_structure(self) -> DataModel:
"""
Rebuilds the data model for AAS meta model structure by adjusting the associations and references and infering correct AAS types.
Returns:
DataModel: The rebuilt data model.
"""
aas_candidates = []
submodel_candidates = []
top_level_models_list = []
for models in self.data_model.get_top_level_models().values():
top_level_models_list += models
for model in top_level_models_list:
if isinstance(model, aas_model.AAS):
aas_candidates.append(model)
continue
if any(
reference_info.reference_type == ReferenceType.ASSOCIATION
for reference_info in self.data_model.get_referencing_info(model)
):
continue
if not all(
is_identifiable(attribute_value)
for attribute_value in get_value_attributes(model).values()
):
continue
aas_candidates.append(model)
for model in top_level_models_list:
if model in aas_candidates:
continue
submodel_candidates.append(model)
submodel_objects = []
for submodel_candidate in submodel_candidates:
# TODO: remove the need to patch models that are already subclasses of submodel...
patched_submodel_object = get_patched_aas_object(
submodel_candidate, patch_type=aas_model.Submodel
)
submodel_objects.append(patched_submodel_object)
aas_objects = []
for aas_candidate in aas_candidates:
# TODO: remove the need to patch models that are already subclasses of aas...
patched_aas_object = get_patched_aas_object(
aas_candidate, patch_type=aas_model.AAS
)
aas_objects.append(patched_aas_object)
aas_data_model = DataModel.from_models(*aas_objects + submodel_objects)
return aas_data_model
def rebuild_data_model_with_references(self) -> DataModel:
"""
Rebuilds all models in the data model with references.
Returns:
DataModel: The rebuilt data model.
"""
raise NotImplementedError
__init__(self, data_model)
special
Rebuilds a data model with either direct or indirect references.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data_model |
DataModel |
The data model to rebuild. |
required |
rebuild_data_model_for_AAS_structure(self)
Rebuilds the data model for AAS meta model structure by adjusting the associations and references and infering correct AAS types.
Returns:
Type | Description |
---|---|
DataModel |
The rebuilt data model. |
Source code in aas_middleware\model\data_model_rebuilder.py
def rebuild_data_model_for_AAS_structure(self) -> DataModel:
"""
Rebuilds the data model for AAS meta model structure by adjusting the associations and references and infering correct AAS types.
Returns:
DataModel: The rebuilt data model.
"""
aas_candidates = []
submodel_candidates = []
top_level_models_list = []
for models in self.data_model.get_top_level_models().values():
top_level_models_list += models
for model in top_level_models_list:
if isinstance(model, aas_model.AAS):
aas_candidates.append(model)
continue
if any(
reference_info.reference_type == ReferenceType.ASSOCIATION
for reference_info in self.data_model.get_referencing_info(model)
):
continue
if not all(
is_identifiable(attribute_value)
for attribute_value in get_value_attributes(model).values()
):
continue
aas_candidates.append(model)
for model in top_level_models_list:
if model in aas_candidates:
continue
submodel_candidates.append(model)
submodel_objects = []
for submodel_candidate in submodel_candidates:
# TODO: remove the need to patch models that are already subclasses of submodel...
patched_submodel_object = get_patched_aas_object(
submodel_candidate, patch_type=aas_model.Submodel
)
submodel_objects.append(patched_submodel_object)
aas_objects = []
for aas_candidate in aas_candidates:
# TODO: remove the need to patch models that are already subclasses of aas...
patched_aas_object = get_patched_aas_object(
aas_candidate, patch_type=aas_model.AAS
)
aas_objects.append(patched_aas_object)
aas_data_model = DataModel.from_models(*aas_objects + submodel_objects)
return aas_data_model
rebuild_data_model_with_associations(self)
Rebuilds all models in the data model with assosiations.
Returns:
Type | Description |
---|---|
DataModel |
The rebuilt data model. |
rebuild_data_model_with_references(self)
Rebuilds all models in the data model with references.
Returns:
Type | Description |
---|---|
DataModel |
The rebuilt data model. |
get_patched_aas_object(model, patch_type)
Rebuilds an Identifiable object to an AAS object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
object |
The object to rebuild. |
required |
Returns:
Type | Description |
---|---|
aas_model.AAS |
The rebuilt AAS object. |
Source code in aas_middleware\model\data_model_rebuilder.py
def get_patched_aas_object(model: Any, patch_type: Type[T]) -> T:
"""
Rebuilds an Identifiable object to an AAS object.
Args:
model (object): The object to rebuild.
Returns:
aas_model.AAS: The rebuilt AAS object.
"""
model_id = get_id_with_patch(model)
dict_dynamic_model_creation = {}
dict_model_instantiation = {}
dict_model_instantiation["id_short"] = model_id
if not patch_type == aas_model.SubmodelElementCollection:
dict_model_instantiation["id"] = model_id
for attribute_name, attribute_value in get_value_attributes(model).items():
below_patch_type = get_below_patch_type(patch_type)
if is_identifiable(attribute_value):
patched_attribute_value = get_patched_aas_object(
attribute_value, patch_type=below_patch_type
)
elif is_identifiable_container(attribute_value):
patched_attribute_value = []
for element in attribute_value:
patched_element = get_patched_aas_object(
element, patch_type=below_patch_type
)
patched_attribute_value.append(patched_element)
else:
patched_attribute_value = attribute_value
attribute_patch_type = get_patched_type(model, attribute_name, patched_attribute_value)
dict_dynamic_model_creation.update(
{
attribute_name: (
attribute_patch_type,
Field(examples=[patched_attribute_value]),
)
}
)
dict_model_instantiation.update({attribute_name: patched_attribute_value})
new_model_type = create_model(
model.__class__.__name__, **dict_dynamic_model_creation, __base__=patch_type
)
return new_model_type.model_validate(dict_model_instantiation)
formatting
special
aas
special
aas_json_formatter
AasJsonFormatter
Allows to serialize and deserialize Basyx AAS objects (AssetAdministrationShells, Submodels or Containers of both) to a DataModel.
Source code in aas_middleware\model\formatting\aas\aas_json_formatter.py
class AasJsonFormatter:
"""
Allows to serialize and deserialize Basyx AAS objects (AssetAdministrationShells, Submodels or Containers of both) to a DataModel.
"""
def serialize(self, data: DataModel) -> Dict[Literal["assetAdministrationShells", "submodels"], List[str]]:
"""
Serialize a DataModel object to the specific format of the formatter.
Args:
data (DataModel): A data model
Returns:
Objectstore: the basyx object store contain all AAS elements
"""
basyx_dict_obj_store = BasyxFormatter().serialize(data)
return json.loads(basyx.aas.adapter.json.object_store_to_json(basyx_dict_obj_store))
def deserialize(self, data: Dict[Literal["assetAdministrationShells", "submodels"], List[str]]) -> DataModel:
"""
Deserialize the specific format of the formater to a DataModel object.
Args:
data (Any): The specific format of the formatter.
Returns:
DataModel: A data model that holds the objects that were deserialized
"""
object_store = DictObjectStore()
for key, items in data.items():
if key == "assetAdministrationShells":
for aas_item in items:
aas = json.loads(json.dumps(aas_item), cls=basyx.aas.adapter.json.AASFromJsonDecoder)
object_store.add(aas)
elif key == "submodels":
for submodel_item in items:
submodel = json.loads(json.dumps(submodel_item), cls=basyx.aas.adapter.json.AASFromJsonDecoder)
object_store.add(submodel)
return BasyxFormatter().deserialize(object_store)
deserialize(self, data)
Deserialize the specific format of the formater to a DataModel object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Any |
The specific format of the formatter. |
required |
Returns:
Type | Description |
---|---|
DataModel |
A data model that holds the objects that were deserialized |
Source code in aas_middleware\model\formatting\aas\aas_json_formatter.py
def deserialize(self, data: Dict[Literal["assetAdministrationShells", "submodels"], List[str]]) -> DataModel:
"""
Deserialize the specific format of the formater to a DataModel object.
Args:
data (Any): The specific format of the formatter.
Returns:
DataModel: A data model that holds the objects that were deserialized
"""
object_store = DictObjectStore()
for key, items in data.items():
if key == "assetAdministrationShells":
for aas_item in items:
aas = json.loads(json.dumps(aas_item), cls=basyx.aas.adapter.json.AASFromJsonDecoder)
object_store.add(aas)
elif key == "submodels":
for submodel_item in items:
submodel = json.loads(json.dumps(submodel_item), cls=basyx.aas.adapter.json.AASFromJsonDecoder)
object_store.add(submodel)
return BasyxFormatter().deserialize(object_store)
serialize(self, data)
Serialize a DataModel object to the specific format of the formatter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
DataModel |
A data model |
required |
Returns:
Type | Description |
---|---|
Objectstore |
the basyx object store contain all AAS elements |
Source code in aas_middleware\model\formatting\aas\aas_json_formatter.py
def serialize(self, data: DataModel) -> Dict[Literal["assetAdministrationShells", "submodels"], List[str]]:
"""
Serialize a DataModel object to the specific format of the formatter.
Args:
data (DataModel): A data model
Returns:
Objectstore: the basyx object store contain all AAS elements
"""
basyx_dict_obj_store = BasyxFormatter().serialize(data)
return json.loads(basyx.aas.adapter.json.object_store_to_json(basyx_dict_obj_store))
aas_middleware_util
convert_under_score_to_camel_case_str(underscore_str)
Convert a underscore seperated string to a camel case string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
class_name |
str |
The underscore seperated string to convert. |
required |
Returns:
Type | Description |
---|---|
str |
The camel case string. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def convert_under_score_to_camel_case_str(underscore_str: str) -> str:
"""
Convert a underscore seperated string to a camel case string.
Args:
class_name (str): The underscore seperated string to convert.
Returns:
str: The camel case string.
"""
words = underscore_str.split("_")
camel_case_str = "".join(word.title() for word in words)
return camel_case_str
core_model_check(fieldinfo)
Checks if a pydantic model field is a core model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
fieldinfo |
FieldInfo |
Pydantic model field. |
required |
Returns:
Type | Description |
---|---|
bool |
If the model field is a core model. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def core_model_check(fieldinfo: FieldInfo) -> bool:
"""
Checks if a pydantic model field is a core model.
Args:
fieldinfo (FieldInfo): Pydantic model field.
Returns:
bool: If the model field is a core model.
"""
if isinstance(fieldinfo.default, BaseModel):
return True
if typing.get_origin(fieldinfo.annotation) is typing.Union:
args = typing.get_args(fieldinfo.annotation)
if all(issubclass(arg, BaseModel) for arg in args):
return True
else:
if issubclass(fieldinfo.annotation, BaseModel):
return True
get_all_submodel_elements_from_submodel(model)
Function to get all submodel elements from a pydantic submodel
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type[BaseModel] |
The pydantic submodel to get the submodel elements from |
required |
Returns:
Type | Description |
---|---|
List[aas_model.SubmodelElementCollection | list | str | bool | float | int] |
A list of all submodel elements in the pydantic submodel |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def get_all_submodel_elements_from_submodel(
model: Type[aas_model.Submodel],
) -> Dict[
str, Type[aas_model.SubmodelElementCollection | list | str | bool | float | int]
]:
"""
Function to get all submodel elements from a pydantic submodel
Args:
model (Type[BaseModel]): The pydantic submodel to get the submodel elements from
Returns:
List[aas_model.SubmodelElementCollection | list | str | bool | float | int]: A list of all submodel elements in the pydantic submodel
"""
submodel_elements = {}
for field_name, field_info in model.model_fields.items():
if (
field_name != "description"
and field_name != "id_short"
and field_name != "semantic_id"
and field_name != "id"
):
submodel_elements[field_name] = field_info.annotation
return submodel_elements
get_all_submodels_from_object_store(obj_store)
Function to get all basyx submodels from an object store
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj_store |
model.DictObjectStore |
Object store to get submodels from |
required |
Returns:
Type | Description |
---|---|
List[model.Submodel] |
List of basyx submodels |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def get_all_submodels_from_object_store(
obj_store: model.DictObjectStore,
) -> List[model.Submodel]:
"""
Function to get all basyx submodels from an object store
Args:
obj_store (model.DictObjectStore): Object store to get submodels from
Returns:
List[model.Submodel]: List of basyx submodels
"""
submodels = []
for item in obj_store:
if isinstance(item, model.Submodel):
submodels.append(item)
return submodels
get_contained_models_attribute_info(model)
Function to get all submodels from a pydantic model
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type[BaseModel] |
The pydantic model to get the submodels from |
required |
Returns:
Type | Description |
---|---|
List[Tuple[str, Type[aas_model.Submodel]]] |
List of attribute name and value of all submodels in the pydantic model |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def get_contained_models_attribute_info(
model: Type[BaseModel],
) -> List[Tuple[str, Type[aas_model.Submodel]]]:
"""
Function to get all submodels from a pydantic model
Args:
model (Type[BaseModel]): The pydantic model to get the submodels from
Returns:
List[Tuple[str, Type[aas_model.Submodel]]]: List of attribute name and value of all submodels in the pydantic model
"""
submodels = []
for attribute_name, fieldinfo in model.model_fields.items():
if typing.get_args(fieldinfo.annotation) != () and any(issubclass(arg, aas_model.Submodel) for arg in typing.get_args(fieldinfo.annotation)):
submodels.append((attribute_name, fieldinfo.annotation))
elif issubclass(fieldinfo.annotation, aas_model.Submodel):
submodels.append((attribute_name, fieldinfo.annotation))
return submodels
get_field_default_value(fieldinfo)
Function to get the default values of a pydantic model field. If no default is given, the function tries to infer a default cored on the type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
fieldinfo |
FieldInfo |
Pydantic model field. |
required |
Returns:
Type | Description |
---|---|
Any |
Missing default value. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def get_field_default_value(fieldinfo: FieldInfo) -> typing.Any:
"""
Function to get the default values of a pydantic model field. If no default is given, the function tries to infer a default cored on the type.
Args:
fieldinfo (FieldInfo): Pydantic model field.
Returns:
typing.Any: Missing default value.
"""
if fieldinfo.default:
return fieldinfo.default
elif fieldinfo.default_factory:
return fieldinfo.default_factory()
elif fieldinfo.annotation == str:
return "string"
elif fieldinfo.annotation == bool:
return False
elif fieldinfo.annotation == int:
return 1
elif fieldinfo.annotation == float:
return 1.0
elif fieldinfo.annotation == list:
return []
get_pydantic_model_from_dict(dict_values, model_name, all_fields_required=False)
Functions that creates pydantic model from dict.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dict_values |
dict |
Dictionary of values. |
required |
model_name |
str |
Name of the model. |
required |
all_fields_required |
bool |
If all fields should be required (non-Optional) in the model. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
Type[BaseModel] |
Pydantic model. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def get_pydantic_model_from_dict(
dict_values: dict, model_name: str, all_fields_required: bool = False
) -> Type[BaseModel]:
"""
Functions that creates pydantic model from dict.
Args:
dict_values (dict): Dictionary of values.
model_name (str): Name of the model.
all_fields_required (bool, optional): If all fields should be required (non-Optional) in the model. Defaults to False.
Returns:
Type[BaseModel]: Pydantic model.
"""
# TODO: check function below if needed...
pydantic_model = recusrive_model_creation(model_name, dict_values)
pydantic_model = set_example_values(pydantic_model)
if all_fields_required:
for field_name, field_info in pydantic_model.model_fields.items():
field_info.default = None
return pydantic_model
get_pydantic_models_from_instances(instances)
Functions that creates pydantic models from instances.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
instances |
List[BaseModel] |
List of pydantic model instances. |
required |
Returns:
Type | Description |
---|---|
List[Type[BaseModel]] |
List of pydantic models. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def get_pydantic_models_from_instances(
instances: List[BaseModel],
) -> List[Type[BaseModel]]:
"""
Functions that creates pydantic models from instances.
Args:
instances (typing.List[BaseModel]): List of pydantic model instances.
Returns:
List[Type[BaseModel]]: List of pydantic models.
"""
# TODO: update method with pydantic v2 arguments of create_model
models = []
for instance in instances:
model_name = type(instance).__name__
pydantic_model = create_model(model_name, **vars(instance))
pydantic_model = set_example_values(pydantic_model)
pydantic_model = set_required_fields(pydantic_model, instance.__class__)
pydantic_model = set_default_values(pydantic_model, instance.__class__)
models.append(pydantic_model)
return models
recusrive_model_creation(model_name, dict_values, depth=0)
Function that creates a pydantic model from a dict.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_name |
_type_ |
description |
required |
dict_values |
_type_ |
description |
required |
Returns:
Type | Description |
---|---|
_type_ |
description |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def recusrive_model_creation(model_name, dict_values, depth=0):
"""
Function that creates a pydantic model from a dict.
Args:
model_name (_type_): _description_
dict_values (_type_): _description_
Returns:
_type_: _description_
"""
# TODO: check function below if needed
for attribute_name, attribute_values in dict_values.items():
if isinstance(attribute_values, dict):
class_name = convert_under_score_to_camel_case_str(attribute_name)
created_model = recusrive_model_creation(
class_name, attribute_values, depth=depth + 1
)
dict_values[attribute_name] = created_model(**attribute_values)
if depth == 0:
core_class = aas_model.AAS
elif depth == 1:
core_class = aas_model.Submodel
else:
core_class = aas_model.SubmodelElementCollection
return create_model(model_name, **dict_values, __core__=core_class)
save_model_list_with_schema(model_list, path)
Saves a list of pydantic models to a json file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_list |
List[aas_model.AAS] |
List of pydantic models |
required |
path |
str |
Path to the json file |
required |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def save_model_list_with_schema(model_list: typing.List[BaseModel], path: str):
"""
Saves a list of pydantic models to a json file.
Args:
model_list (typing.List[aas_model.AAS]): List of pydantic models
path (str): Path to the json file
"""
save_dict = {
"models": [model.model_dump() for model in model_list],
"schema": [model.model_json_schema() for model in model_list],
}
with open(path, "w", encoding="utf-8") as json_file:
json.dump(save_dict, json_file, indent=4)
set_default_values(model, origin_model)
Sets the default values and default factory of a pydantic model cored on a original model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type[BaseModel] |
Pydantic model where default values should be removed. |
required |
Returns:
Type | Description |
---|---|
Type[BaseModel] |
Pydantic model with the default values set. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def set_default_values(
model: Type[BaseModel], origin_model: Type[BaseModel]
) -> Type[BaseModel]:
"""
Sets the default values and default factory of a pydantic model cored on a original model.
Args:
model (Type[BaseModel]): Pydantic model where default values should be removed.
Returns:
Type[BaseModel]: Pydantic model with the default values set.
"""
# TODO: validate if this method is still needed in pydantic 2.0
for field_name, fieldinfo in origin_model.model_fields.items():
if union_type_field_check(fieldinfo):
original_sub_types = typing.get_args(fieldinfo.annotation)
model_sub_types = typing.get_args(model.model_fields[field_name].annotation)
new_types = []
for original_sub_type, model_sub_type in zip(
original_sub_types, model_sub_types
):
new_type = set_default_values(model_sub_type, original_sub_type)
new_types.append(new_type)
model.model_fields[field_name].annotation = typing.Union[tuple(new_types)]
elif core_model_check(fieldinfo):
new_type = set_default_values(
model.model_fields[field_name].annotation, fieldinfo.annotation
)
model.model_fields[field_name].annotation = new_type
if not fieldinfo.is_required() and (
fieldinfo.default
or fieldinfo.default == ""
or fieldinfo.default == 0
or fieldinfo.default == 0.0
or fieldinfo.default == False
or fieldinfo.default == []
or fieldinfo.default == {}
):
model.model_fields[field_name].default = fieldinfo.default
else:
model.model_fields[field_name].default = None
if not fieldinfo.is_required() and fieldinfo.default_factory:
model.model_fields[field_name].default_factory = fieldinfo.default_factory
else:
model.model_fields[field_name].default_factory = None
return model
set_example_values(model)
Sets the example values of a pydantic model cored on its default values.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type[BaseModel] |
Pydantic model. |
required |
Returns:
Type | Description |
---|---|
Type[BaseModel] |
Pydantic model with the example values set. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def set_example_values(model: Type[BaseModel]) -> Type[BaseModel]:
"""
Sets the example values of a pydantic model cored on its default values.
Args:
model (Type[BaseModel]): Pydantic model.
Returns:
Type[BaseModel]: Pydantic model with the example values set.
"""
# TODO: potentially delete this method, since not required...
example_dict = {}
for field_name, fieldinfo in model.model_fields.items():
if issubclass(fieldinfo.annotation, BaseModel):
config_dict = ConfigDict(
json_schema_extra={"examples": [fieldinfo.default.model_dump_json()]}
)
fieldinfo.annotation.model_config = config_dict
example_dict[field_name] = get_field_default_value(fieldinfo)
serialized_example = model(**example_dict).model_dump_json()
config_dict = ConfigDict(json_schema_extra={"examples": [serialized_example]})
model.model_config = config_dict
return model
set_required_fields(model, origin_model)
Sets the required fields of a pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type[BaseModel] |
Pydantic model. |
required |
origin_model |
Type[BaseModel] |
Pydantic model from which the required fields should be copied. |
required |
Returns:
Type | Description |
---|---|
Type[BaseModel] |
Pydantic model with the required fields set. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def set_required_fields(
model: Type[BaseModel], origin_model: Type[BaseModel]
) -> Type[BaseModel]:
"""
Sets the required fields of a pydantic model.
Args:
model (Type[BaseModel]): Pydantic model.
origin_model (Type[BaseModel]): Pydantic model from which the required fields should be copied.
Returns:
Type[BaseModel]: Pydantic model with the required fields set.
"""
# TODO: potentially delete this method, since not required in pydantic v2
for field_name, fieldinfo in origin_model.model_fields.items():
if union_type_field_check(fieldinfo):
original_sub_types = typing.get_args(fieldinfo.annotation)
model_sub_types = typing.get_args(model.model_fields[field_name].annotation)
new_types = []
for original_sub_type, model_sub_type in zip(
original_sub_types, model_sub_types
):
new_type = set_required_fields(model_sub_type, original_sub_type)
new_types.append(new_type)
model.model_fields[field_name].annotation = typing.Union[tuple(new_types)]
elif core_model_check(fieldinfo):
new_type = set_required_fields(
model.model_fields[field_name].annotation, fieldinfo.annotation
)
model.model_fields[field_name].annotation = new_type
if fieldinfo.is_required():
model.model_fields[field_name].default = None
model.model_fields[field_name].default_factory = True
return model
union_type_check(model)
Checks if a type is a union type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type |
Type. |
required |
Returns:
Type | Description |
---|---|
bool |
If the type is a union type. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
def union_type_check(model: Type) -> bool:
"""
Checks if a type is a union type.
Args:
model (Type): Type.
Returns:
bool: If the type is a union type.
"""
if typing.get_origin(model) == typing.Union:
args = typing.get_args(model)
if all(issubclass(arg, BaseModel) for arg in args):
return True
else:
False
else:
return False
union_type_field_check(fieldinfo)
Checks if a pydantic model field is a union type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
fieldinfo |
FieldInfo |
Pydantic model field. |
required |
Returns:
Type | Description |
---|---|
bool |
If the model field is a union type. |
Source code in aas_middleware\model\formatting\aas\aas_middleware_util.py
aas_model
AAS (Identifiable)
Base class for all Asset Administration Shells (AAS).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id |
str |
Global id of the object. |
required |
id_short |
str |
Local id of the object. |
required |
description |
str |
Description of the object. Defaults to None. |
required |
Source code in aas_middleware\model\formatting\aas\aas_model.py
class AAS(Identifiable):
"""
Base class for all Asset Administration Shells (AAS).
Args:
id (str): Global id of the object.
id_short (str): Local id of the object.
description (str, optional): Description of the object. Defaults to None.
"""
@model_validator(mode="before")
@classmethod
def set_optional_fields_to_None(cls, data):
if isinstance(data, BaseModel):
data = data.model_dump()
for field_name, field_info in cls.model_fields.items():
if field_name in data:
continue
if typing.get_origin(field_info.annotation) == Union and type(None) in typing.get_args(field_info.annotation):
data[field_name] = None
return data
@model_validator(mode="after")
def check_submodels(self) -> Self:
for field_name, field_info in self.model_fields.items():
if field_name in ["id", "id_short", "description"]:
continue
elif typing.get_origin(field_info.annotation) == Union and type(None) in typing.get_args(field_info.annotation) and getattr(self, field_name) is None:
continue
try:
Submodel.model_validate(getattr(self, field_name))
except ValidationError:
assert (
False
), f"All attributes of an AAS must be of type Submodel or inherit from Submodel"
return self
HasSemantics (BaseModel)
Base class for all classes that have semantics of the AAS meta model. Semantics are defined by a semantic id, which reference the semantic definition of the object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
semantic_id |
str |
Semantic id of the object. Defaults to None. |
required |
Source code in aas_middleware\model\formatting\aas\aas_model.py
Identifiable (Referable)
Base class for all identifiable classes in the AAS Meta model. An Identifiable is a Referable with a global id (id_).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id |
str |
Global id of the object. |
required |
id_short |
str |
Local id of the object. |
required |
description |
str |
Description of the object. Defaults to None. |
required |
Source code in aas_middleware\model\formatting\aas\aas_model.py
class Identifiable(Referable):
"""
Base class for all identifiable classes in the AAS Meta model. An Identifiable is a Referable with a global id (id_).
Args:
id (str): Global id of the object.
id_short (str): Local id of the object.
description (str, optional): Description of the object. Defaults to None.
"""
id: AasIdString
@model_validator(mode="before")
@classmethod
def check_id_and_id_short(cls, data: Any) -> Any:
if isinstance(data, BaseModel):
data = data.model_dump()
elif not isinstance(data, dict):
data = {
"id": getattr(data, "id", ""),
"id_short": getattr(data, "id_short", ""),
}
assert "id" in data or "id_short" in data, "Either id or id_short must be set"
if "id_short" not in data:
data["id_short"] = data["id"]
if "id" not in data:
data["id"] = data["id_short"]
return data
Referable (BaseModel)
Base class for all referable classes of the AAS meta model. A Referable is an object with a local id (id_short) and a description.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id_short |
IdString |
Local id of the object. |
required |
description |
str |
Description of the object. Defaults to None. |
required |
Source code in aas_middleware\model\formatting\aas\aas_model.py
class Referable(BaseModel):
"""
Base class for all referable classes of the AAS meta model. A Referable is an object with a local id (id_short) and a description.
Args:
id_short (IdString): Local id of the object.
description (str): Description of the object. Defaults to None.
"""
id_short: AasIdString
description: str = ""
Submodel (HasSemantics, Identifiable)
Base class for all submodels.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id |
str |
Global id of the object. |
required |
id_short |
str |
Local id of the object. |
required |
description |
str |
Description of the object. Defaults to None. |
required |
semantic_id |
str |
Semantic id of the object. Defaults to None. |
required |
Source code in aas_middleware\model\formatting\aas\aas_model.py
class Submodel(HasSemantics, Identifiable):
"""
Base class for all submodels.
Args:
id (str): Global id of the object.
id_short (str): Local id of the object.
description (str, optional): Description of the object. Defaults to None.
semantic_id (str, optional): Semantic id of the object. Defaults to None.
"""
@model_validator(mode="after")
def check_submodel_elements(self) -> Self:
for field_name in self.model_fields:
if field_name in ["id", "id_short", "description", "semantic_id"]:
continue
assert is_valid_submodel_element(
getattr(self, field_name)
), f"All attributes of a Submodel must be valid SubmodelElements."
return self
SubmodelElementCollection (HasSemantics, Referable)
Base class for all submodel element collections.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id_short |
str |
Local id of the object. |
required |
description |
str |
Description of the object. Defaults to None. |
required |
semantic_id |
str |
Semantic id of the object. Defaults to None. |
required |
Source code in aas_middleware\model\formatting\aas\aas_model.py
class SubmodelElementCollection(HasSemantics, Referable):
"""
Base class for all submodel element collections.
Args:
id_short (str): Local id of the object.
description (str, optional): Description of the object. Defaults to None.
semantic_id (str, optional): Semantic id of the object. Defaults to None.
"""
@model_validator(mode="after")
def check_submodel_elements(self) -> Self:
for field_name in self.model_fields:
if field_name in ["id", "id_short", "description", "semantic_id"]:
continue
assert is_valid_submodel_element(
getattr(self, field_name)
), f"All attributes of a SubmodelElementCollection must be valid SubmodelElements. Field {field_name} is not valid."
return self
basyx_formatter
BasyxFormatter
Allows to serialize and deserialize Basyx AAS objects (AssetAdministrationShells, Submodels or Containers of both) to a DataModel.
Source code in aas_middleware\model\formatting\aas\basyx_formatter.py
class BasyxFormatter:
"""
Allows to serialize and deserialize Basyx AAS objects (AssetAdministrationShells, Submodels or Containers of both) to a DataModel.
"""
def serialize(self, data: DataModel) -> DictObjectStore[model.Identifiable]:
"""
Serialize a DataModel object to the specific format of the formatter.
Args:
data (DataModel): A data model
Returns:
Objectstore: the basyx object store contain all AAS elements
"""
aas_models, submodel_models = infere_aas_structure(data)
obj_store = DictObjectStore()
for aas in aas_models:
obj_store_to_add = convert_model_to_aas(aas)
for identifiable in obj_store_to_add:
if obj_store.get(identifiable.id_short) is not None:
continue
obj_store.add(identifiable)
for submodel in submodel_models:
submodel_to_add = convert_model_to_submodel(submodel)
if obj_store.get(submodel_to_add.id_short) is not None:
continue
obj_store.add(submodel_to_add)
return obj_store
def deserialize(self, data: BasyxModels) -> DataModel:
"""
Deserialize the specific format of the formater to a DataModel object.
Args:
data (Any): The specific format of the formatter.
Returns:
DataModel: A data model that holds the objects that were deserialized
"""
if not isinstance(data, DictObjectStore):
data = DictObjectStore(data)
models = convert_object_store_to_pydantic_models(data)
return DataModel.from_models(*models)
deserialize(self, data)
Deserialize the specific format of the formater to a DataModel object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Any |
The specific format of the formatter. |
required |
Returns:
Type | Description |
---|---|
DataModel |
A data model that holds the objects that were deserialized |
Source code in aas_middleware\model\formatting\aas\basyx_formatter.py
def deserialize(self, data: BasyxModels) -> DataModel:
"""
Deserialize the specific format of the formater to a DataModel object.
Args:
data (Any): The specific format of the formatter.
Returns:
DataModel: A data model that holds the objects that were deserialized
"""
if not isinstance(data, DictObjectStore):
data = DictObjectStore(data)
models = convert_object_store_to_pydantic_models(data)
return DataModel.from_models(*models)
serialize(self, data)
Serialize a DataModel object to the specific format of the formatter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
DataModel |
A data model |
required |
Returns:
Type | Description |
---|---|
Objectstore |
the basyx object store contain all AAS elements |
Source code in aas_middleware\model\formatting\aas\basyx_formatter.py
def serialize(self, data: DataModel) -> DictObjectStore[model.Identifiable]:
"""
Serialize a DataModel object to the specific format of the formatter.
Args:
data (DataModel): A data model
Returns:
Objectstore: the basyx object store contain all AAS elements
"""
aas_models, submodel_models = infere_aas_structure(data)
obj_store = DictObjectStore()
for aas in aas_models:
obj_store_to_add = convert_model_to_aas(aas)
for identifiable in obj_store_to_add:
if obj_store.get(identifiable.id_short) is not None:
continue
obj_store.add(identifiable)
for submodel in submodel_models:
submodel_to_add = convert_model_to_submodel(submodel)
if obj_store.get(submodel_to_add.id_short) is not None:
continue
obj_store.add(submodel_to_add)
return obj_store
convert_aas
convert_aas_to_pydantic_model(aas, pydantic_submodels)
Converts an AAS to a Pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
aas |
model.AssetAdministrationShell |
AAS to convert |
required |
Returns:
Type | Description |
---|---|
aas_model.AAS |
Pydantic model of the asset administration shell |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_aas_to_pydantic_model(
aas: model.AssetAdministrationShell,
pydantic_submodels: typing.List[aas_model.Submodel],
) -> aas_model.AAS:
"""
Converts an AAS to a Pydantic model.
Args:
aas (model.AssetAdministrationShell): AAS to convert
Returns:
aas_model.AAS: Pydantic model of the asset administration shell
"""
aas_class_name = convert_util.get_class_name_from_basyx_model(aas)
dict_dynamic_model_creation = get_initial_dict_for_dynamic_model_creation(aas)
dict_model_instantiation = get_initial_dict_for_model_instantiation(aas)
aas_submodel_ids = [sm.get_identifier() for sm in aas.submodel]
for sm in pydantic_submodels:
if not sm.id in aas_submodel_ids:
continue
attribute_name_of_submodel = convert_util.get_attribute_name_from_basyx_model(
aas, sm.id
)
dict_dynamic_model_creation.update(
{
attribute_name_of_submodel: typing.Annotated[
type(sm), Field(examples=[sm])
]
}
)
dict_model_instantiation.update({attribute_name_of_submodel: sm.model_dump()})
model_type = create_model(
aas_class_name, **dict_dynamic_model_creation, __base__=aas_model.AAS
)
return model_type(**dict_model_instantiation)
convert_object_store_to_pydantic_models(obj_store)
Converts an object store with AAS and submodels to pydantic models, representing the original data structure.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj_store |
model.DictObjectStore |
Object store with AAS and submodels |
required |
Returns:
Type | Description |
---|---|
List[aas_model.AAS] |
List of pydantic models |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_object_store_to_pydantic_models(
obj_store: model.DictObjectStore,
) -> typing.List[aas_model.AAS]:
"""
Converts an object store with AAS and submodels to pydantic models, representing the original data structure.
Args:
obj_store (model.DictObjectStore): Object store with AAS and submodels
Returns:
typing.List[aas_model.AAS]: List of pydantic models
"""
pydantic_submodels: typing.List[aas_model.Submodel] = []
for identifiable in obj_store:
if isinstance(identifiable, model.Submodel):
pydantic_submodel = convert_submodel_to_model(identifiable)
pydantic_submodels.append(pydantic_submodel)
pydantic_aas_list: typing.List[aas_model.AAS] = []
for identifiable in obj_store:
if isinstance(identifiable, model.AssetAdministrationShell):
pydantic_aas = convert_aas_to_pydantic_model(
identifiable, pydantic_submodels
)
pydantic_aas_list.append(pydantic_aas)
return pydantic_aas_list
convert_property_to_pydantic_model(sm_element)
Converts a Property to a Pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm_element |
model.Property |
Property to convert. |
required |
Returns:
Type | Description |
---|---|
aas_model.PrimitiveSubmodelElement |
Value of the Property. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_property_to_pydantic_model(
sm_element: model.Property,
) -> aas_model.PrimitiveSubmodelElement:
"""
Converts a Property to a Pydantic model.
Args:
sm_element (model.Property): Property to convert.
Returns:
aas_model.PrimitiveSubmodelElement: Value of the Property.
"""
return sm_element.value
convert_reference_element_to_pydantic_model(sm_element)
Converts a ReferenceElement to a Pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm_element |
model.ReferenceElement |
ReferenceElement to convert. |
required |
Returns:
Type | Description |
---|---|
str |
Value of the ReferenceElement. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_reference_element_to_pydantic_model(
sm_element: model.ReferenceElement,
) -> str:
"""
Converts a ReferenceElement to a Pydantic model.
Args:
sm_element (model.ReferenceElement): ReferenceElement to convert.
Returns:
str: Value of the ReferenceElement.
"""
return sm_element.value.key[0].value
convert_submodel_collection_to_pydantic_model(sm_element)
Converts a SubmodelElementCollection to a Pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm_element |
model.SubmodelElementCollection |
SubmodelElementCollection to convert. |
required |
Returns:
Type | Description |
---|---|
aas_model.SubmodelElementCollection |
Pydantic model of the submodel element collection. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_submodel_collection_to_pydantic_model(
sm_element: model.SubmodelElementCollection,
) -> aas_model.SubmodelElementCollection:
"""
Converts a SubmodelElementCollection to a Pydantic model.
Args:
sm_element (model.SubmodelElementCollection): SubmodelElementCollection to convert.
Returns:
aas_model.SubmodelElementCollection: Pydantic model of the submodel element collection.
"""
class_name = convert_util.get_class_name_from_basyx_model(sm_element)
dict_dynamic_model_creation = get_initial_dict_for_dynamic_model_creation(
sm_element
)
dict_model_instantiation = get_initial_dict_for_model_instantiation(sm_element)
for sub_sm_element in sm_element.value:
attribute_name = convert_util.get_attribute_name_from_basyx_model(
sm_element, sub_sm_element.id_short
)
immutable = is_attribute_from_basyx_model_immutable(
sm_element, sub_sm_element.id_short
)
attribute_value = get_submodel_element_value(sub_sm_element, immutable)
dict_sme = get_dynamic_model_creation_dict_from_submodel_element(
attribute_name, attribute_value
)
dict_dynamic_model_creation.update(dict_sme)
dict_sme_instantiation = get_model_instantiation_dict_from_submodel_element(
attribute_name, attribute_value
)
dict_model_instantiation.update(dict_sme_instantiation)
model_type = create_model(
class_name,
**dict_dynamic_model_creation,
__base__=aas_model.SubmodelElementCollection,
)
return model_type(**dict_model_instantiation)
convert_submodel_list_to_pydantic_model(sm_element, immutable=False)
Converts a SubmodelElementList to a Pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm_element |
model.SubmodelElementList |
SubmodelElementList to convert. |
required |
Returns:
Type | Description |
---|---|
List[aas_model.SubmodelElement] |
List of Pydantic models of the submodel elements. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_submodel_list_to_pydantic_model(
sm_element: model.SubmodelElementList, immutable: bool = False
) -> typing.Union[typing.List[aas_model.SubmodelElement], typing.Set[aas_model.SubmodelElement], typing.Tuple[aas_model.SubmodelElement]]:
"""
Converts a SubmodelElementList to a Pydantic model.
Args:
sm_element (model.SubmodelElementList): SubmodelElementList to convert.
Returns:
typing.List[aas_model.SubmodelElement]: List of Pydantic models of the submodel elements.
"""
sme_pydantic_models = []
for sme in sm_element.value:
if isinstance(sme, model.SubmodelElementCollection):
sme = unpatch_id_short_from_temp_attribute(sme)
sme_pydantic_models.append(
convert_submodel_collection_to_pydantic_model(sme)
)
elif isinstance(sme, model.SubmodelElementList):
sme_pydantic_models.append(convert_submodel_list_to_pydantic_model(sme))
elif isinstance(sme, model.ReferenceElement):
sme_pydantic_models.append(convert_reference_element_to_pydantic_model(sme))
elif isinstance(sme, model.Property):
sme_pydantic_models.append(sme.value)
else:
raise NotImplementedError("Type not implemented:", type(sme))
if not sm_element.order_relevant:
return set(sme_pydantic_models)
if immutable:
return tuple(sme_pydantic_models)
return sme_pydantic_models
convert_submodel_to_model(sm)
Converts a Submodel to a Pydantic model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm |
model.Submodel |
Submodel to convert. |
required |
Returns:
Type | Description |
---|---|
aas_model.Submodel |
Pydantic model of the submodel. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def convert_submodel_to_model(sm: model.Submodel) -> aas_model.Submodel:
"""
Converts a Submodel to a Pydantic model.
Args:
sm (model.Submodel): Submodel to convert.
Returns:
aas_model.Submodel: Pydantic model of the submodel.
"""
class_name = convert_util.get_class_name_from_basyx_model(sm)
dict_dynamic_model_creation = get_initial_dict_for_dynamic_model_creation(sm)
dict_model_instantiation = get_initial_dict_for_model_instantiation(sm)
for sm_element in sm.submodel_element:
attribute_name = convert_util.get_attribute_name_from_basyx_model(
sm, sm_element.id_short
)
immutable = is_attribute_from_basyx_model_immutable(sm, sm_element.id_short)
attribute_value = get_submodel_element_value(sm_element, immutable)
sme_model_creation_dict = get_dynamic_model_creation_dict_from_submodel_element(
attribute_name, attribute_value
)
dict_dynamic_model_creation.update(sme_model_creation_dict)
sme_model_instantiation_dict = (
get_model_instantiation_dict_from_submodel_element(
attribute_name, attribute_value
)
)
dict_model_instantiation.update(sme_model_instantiation_dict)
model_type = create_model(
class_name, **dict_dynamic_model_creation, __base__=aas_model.Submodel
)
return model_type(**dict_model_instantiation)
get_dynamic_model_creation_dict_from_submodel_element(attribute_name, attribute_value)
Converts a SubmodelElement to a dict.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
attribute_name |
str |
Name of the attribute to create in the dictionary. |
required |
sm_element |
model.SubmodelElement |
SubmodelElement to convert. |
required |
Returns:
Type | Description |
---|---|
dict |
Dictionary that can be used to create a Pydantic model, with Annoated types for the attributes and examples. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def get_dynamic_model_creation_dict_from_submodel_element(
attribute_name: str, attribute_value: typing.Any
) -> typing.Dict[str, typing.Any]:
"""
Converts a SubmodelElement to a dict.
Args:
attribute_name (str): Name of the attribute to create in the dictionary.
sm_element (model.SubmodelElement): SubmodelElement to convert.
Returns:
dict: Dictionary that can be used to create a Pydantic model, with Annoated types for the attributes and examples.
"""
if isinstance(attribute_value, list) and attribute_value:
inner_type = type(attribute_value[0])
attribute_type = typing.List[inner_type]
elif isinstance(attribute_value, set) and attribute_value:
inner_type = type(next(iter(attribute_value)))
attribute_type = typing.Set[inner_type]
elif isinstance(attribute_value, tuple) and attribute_value:
inner_type = type(attribute_value[0])
attribute_type = typing.Tuple[inner_type, ...]
else:
attribute_type = type(attribute_value)
return {
attribute_name: typing.Annotated[
attribute_type, Field(examples=[attribute_value])
]
}
get_initial_dict_for_dynamic_model_creation(basyx_model)
Returns a dictionary that can be used to create a Pydantic model based on a provided basyx submodel.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
basyx_model |
model.Submodel | model.AssetAdministrationShell | model.SubmodelElementCollection |
Basyx model to create the dictionary from. |
required |
Returns:
Type | Description |
---|---|
Dict[str, Any] |
Dictionary that can be used to create a Pydantic model. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def get_initial_dict_for_dynamic_model_creation(
basyx_model: (
model.Submodel
| model.AssetAdministrationShell
| model.SubmodelElementCollection
),
) -> typing.Dict[str, typing.Any]:
"""
Returns a dictionary that can be used to create a Pydantic model based on a provided basyx submodel.
Args:
basyx_model (model.Submodel | model.AssetAdministrationShell | model.SubmodelElementCollection): Basyx model to create the dictionary from.
Returns:
typing.Dict[str, typing.Any]: Dictionary that can be used to create a Pydantic model.
"""
model_creation_dict = {
"id_short": typing.Annotated[str, Field(examples=[basyx_model.id_short])],
"description": typing.Annotated[
str,
Field(examples=[convert_util.get_str_description(basyx_model.description)]),
],
}
if isinstance(basyx_model, model.Identifiable):
model_creation_dict["id"] = typing.Annotated[
str, Field(examples=[str(basyx_model.id)])
]
if isinstance(basyx_model, model.HasSemantics):
model_creation_dict["semantic_id"] = typing.Annotated[
str, Field(examples=[get_semantic_id_value_of_model(basyx_model)])
]
return model_creation_dict
get_initial_dict_for_model_instantiation(basyx_model)
Returns a dictionary that can be used to instantiate a Pydantic model based on a provided basyx submodel.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
basyx_model |
model.Submodel | model.AssetAdministrationShell | model.SubmodelElementCollection |
Basyx model to create the dictionary from. |
required |
Returns:
Type | Description |
---|---|
Dict[str, Any] |
Dictionary that can be used to instantiate a Pydantic model. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def get_initial_dict_for_model_instantiation(
basyx_model: (
model.Submodel
| model.AssetAdministrationShell
| model.SubmodelElementCollection
),
) -> typing.Dict[str, typing.Any]:
"""
Returns a dictionary that can be used to instantiate a Pydantic model based on a provided basyx submodel.
Args:
basyx_model (model.Submodel | model.AssetAdministrationShell | model.SubmodelElementCollection): Basyx model to create the dictionary from.
Returns:
typing.Dict[str, typing.Any]: Dictionary that can be used to instantiate a Pydantic model.
"""
model_instantiation_dict = {
"id_short": basyx_model.id_short,
"description": convert_util.get_str_description(basyx_model.description),
}
if isinstance(basyx_model, model.Identifiable):
model_instantiation_dict["id"] = str(basyx_model.id)
if isinstance(basyx_model, model.HasSemantics):
model_instantiation_dict["semantic_id"] = get_semantic_id_value_of_model(
basyx_model
)
return model_instantiation_dict
get_model_instantiation_dict_from_submodel_element(attribute_name, attribute_value)
Converts a SubmodelElement to a dict.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
attribute_name |
str |
Name of the attribute to create in the dictionary. |
required |
sm_element |
model.SubmodelElement |
SubmodelElement to convert. |
required |
Returns:
Type | Description |
---|---|
dict |
Dictionary that can be used to instantiate a Pydantic model. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def get_model_instantiation_dict_from_submodel_element(
attribute_name: str, attribute_value: typing.Any
) -> typing.Dict[str, typing.Any]:
"""
Converts a SubmodelElement to a dict.
Args:
attribute_name (str): Name of the attribute to create in the dictionary.
sm_element (model.SubmodelElement): SubmodelElement to convert.
Returns:
dict: Dictionary that can be used to instantiate a Pydantic model.
"""
if isinstance(attribute_value, BaseModel):
attribute_value = attribute_value.model_dump()
elif isinstance(attribute_value, (list, set, tuple)) and any(
isinstance(element, BaseModel) for element in attribute_value
):
attribute_value = [element.model_dump() for element in attribute_value]
return {attribute_name: attribute_value}
get_submodel_element_value(sm_element, immutable=False)
Returns the value of a SubmodelElement.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm_element |
model.SubmodelElement |
SubmodelElement to get the value from. |
required |
Returns:
Type | Description |
---|---|
aas_model.SubmodelElement |
Value of the SubmodelElement. |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def get_submodel_element_value(
sm_element: model.SubmodelElement, immutable: bool = False
) -> aas_model.SubmodelElement:
"""
Returns the value of a SubmodelElement.
Args:
sm_element (model.SubmodelElement): SubmodelElement to get the value from.
Returns:
aas_model.SubmodelElement: Value of the SubmodelElement.
"""
if isinstance(sm_element, model.SubmodelElementCollection):
return convert_submodel_collection_to_pydantic_model(sm_element)
elif isinstance(sm_element, model.SubmodelElementList):
return convert_submodel_list_to_pydantic_model(sm_element, immutable)
elif isinstance(sm_element, model.ReferenceElement):
return convert_reference_element_to_pydantic_model(sm_element)
elif isinstance(sm_element, model.Property):
return convert_property_to_pydantic_model(sm_element)
else:
raise NotImplementedError("Type not implemented:", type(sm_element))
unpatch_id_short_from_temp_attribute(smec)
Unpatches the id_short attribute of a SubmodelElementCollection from the temporary attribute.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sm_element |
model.SubmodelElementCollection |
SubmodelElementCollection to unpatch. |
required |
Source code in aas_middleware\model\formatting\aas\convert_aas.py
def unpatch_id_short_from_temp_attribute(smec: model.SubmodelElementCollection):
"""
Unpatches the id_short attribute of a SubmodelElementCollection from the temporary attribute.
Args:
sm_element (model.SubmodelElementCollection): SubmodelElementCollection to unpatch.
"""
if not smec.id_short.startswith("generated_submodel_list_hack_"):
return smec
if not any(isinstance(sm_element, model.Property) and sm_element.id_short.startswith("temp_id_short_attribute") for sm_element in smec.value):
raise ValueError("No temporary id_short attribute found in SubmodelElementCollection.")
no_temp_values = []
id_short = None
for sm_element in smec.value:
if isinstance(sm_element, model.Property) and sm_element.id_short.startswith("temp_id_short_attribute"):
id_short = sm_element.value
continue
no_temp_values.append(sm_element)
for value in no_temp_values:
smec.value.remove(value)
new_smec = model.SubmodelElementCollection(
id_short=id_short, value=no_temp_values,
embedded_data_specifications=smec.embedded_data_specifications,
)
# new_smec.value.remove(contained_sm_element)
return new_smec
convert_pydantic
convert_model_to_aas(model_aas)
Convert a model aas to an Basyx AssetAdministrationShell and return it as a DictObjectStore with all Submodels
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_aas |
aas_model.AAS |
model aas to convert |
required |
Returns:
Type | Description |
---|---|
model.DictObjectStore[model.Identifiable] |
DictObjectStore with all Submodels |
Source code in aas_middleware\model\formatting\aas\convert_pydantic.py
def convert_model_to_aas(
model_aas: aas_model.AAS,
) -> model.DictObjectStore[model.Identifiable]:
"""
Convert a model aas to an Basyx AssetAdministrationShell and return it as a DictObjectStore with all Submodels
Args:
model_aas (aas_model.AAS): model aas to convert
Returns:
model.DictObjectStore[model.Identifiable]: DictObjectStore with all Submodels
"""
aas_attributes = get_attribute_dict(model_aas)
aas_submodels = [] # placeholder for submodels created
aas_submodel_data_specifications = []
for attribute_name, attribute_value in aas_attributes.items():
if isinstance(attribute_value, aas_model.Submodel):
tempsubmodel = convert_model_to_submodel(model_submodel=attribute_value)
aas_submodels.append(tempsubmodel)
attribute_data_specifications = convert_util.get_data_specification_for_attribute(
attribute_name, attribute_value.id, attribute_value
)
aas_submodel_data_specifications += attribute_data_specifications
asset_information = model.AssetInformation(
global_asset_id=model.Identifier(model_aas.id),
)
basyx_aas = model.AssetAdministrationShell(
asset_information=asset_information,
id_short=get_id_short(model_aas),
id_=model.Identifier(model_aas.id),
description=convert_util.get_basyx_description_from_model(model_aas),
submodel={
model.ModelReference.from_referable(submodel) for submodel in aas_submodels
},
embedded_data_specifications=convert_util.get_data_specification_for_model(model_aas) + aas_submodel_data_specifications,
)
obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
obj_store.add(basyx_aas)
for sm in aas_submodels:
obj_store.add(sm)
return obj_store
create_submodel_element(attribute_name, attribute_value)
Create a basyx SubmodelElement from a model SubmodelElementCollection or a primitive type
Parameters:
Name | Type | Description | Default |
---|---|---|---|
attribute_name |
str |
Name of the attribute that is used for ID and id_short |
required |
attribute_value |
Union[ aas_model.SubmodelElementCollection, str, float, int, bool, tuple, list, set ] |
Value of the attribute |
required |
Returns:
Type | Description |
---|---|
model.SubmodelElement |
basyx SubmodelElement |
Source code in aas_middleware\model\formatting\aas\convert_pydantic.py
def create_submodel_element(
attribute_name: str,
attribute_value: Union[
aas_model.SubmodelElementCollection, str, float, int, bool, tuple, list, set
],
) -> model.SubmodelElement:
"""
Create a basyx SubmodelElement from a model SubmodelElementCollection or a primitive type
Args:
attribute_name (str): Name of the attribute that is used for ID and id_short
attribute_value (Union[ aas_model.SubmodelElementCollection, str, float, int, bool, tuple, list, set ]): Value of the attribute
Returns:
model.SubmodelElement: basyx SubmodelElement
"""
if isinstance(attribute_value, aas_model.SubmodelElementCollection):
smc = create_submodel_element_collection(attribute_value)
return smc
elif isinstance(attribute_value, list):
sml = create_submodel_element_list(attribute_name, attribute_value)
return sml
elif isinstance(attribute_value, tuple):
attribute_value_as_list = list(attribute_value)
sml = create_submodel_element_list(attribute_name, attribute_value_as_list)
return sml
elif isinstance(attribute_value, set):
attribute_value_as_list = list(attribute_value)
sml = create_submodel_element_list(
attribute_name, attribute_value_as_list, ordered=False
)
return sml
elif (isinstance(attribute_value, str)) and (
(
parse.urlparse(attribute_value).scheme
and parse.urlparse(attribute_value).netloc
)
or (attribute_value.split("_")[-1] in ["id", "ids"])
):
key = model.Key(
type_=model.KeyTypes.ASSET_ADMINISTRATION_SHELL,
value=attribute_value,
)
reference = model.ModelReference(key=(key,), type_="")
reference_element = model.ReferenceElement(
id_short=attribute_name,
value=reference,
)
return reference_element
else:
property = create_property(attribute_name, attribute_value)
return property
infere_aas_structure(data)
The function assert that the data contained in the data model fulfills the aas meta model structure.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
DataModel |
The Data Model containing the objects that should be transformed to AAS models |
required |
Returns:
Type | Description |
---|---|
Tuple[List[aas_model.AAS], List[aas_model.Submodel]] |
Tuple with AAS models and Submodel models |
Source code in aas_middleware\model\formatting\aas\convert_pydantic.py
def infere_aas_structure(
data: DataModel,
) -> Tuple[List[aas_model.AAS], List[aas_model.Submodel]]:
"""
The function assert that the data contained in the data model fulfills the aas meta model structure.
Args:
data (DataModel): The Data Model containing the objects that should be transformed to AAS models
Returns:
Tuple[List[aas_model.AAS], List[aas_model.Submodel]]: Tuple with AAS models and Submodel models
"""
if all(isinstance(model, aas_model.AAS) for model in data.get_top_level_models()):
return data.get_top_level_models(), []
logger.warning(
"The data model does not contain only AAS models. Trying to infer the AAS structure by rebuilding the data model."
)
new_data_model = DataModelRebuilder(data).rebuild_data_model_for_AAS_structure()
top_level_models_list = []
for models in new_data_model.get_top_level_models().values():
top_level_models_list += models
aas_models = [
model for model in top_level_models_list if isinstance(model, aas_model.AAS)
]
submodel_models = [
model
for model in top_level_models_list
if isinstance(model, aas_model.Submodel)
]
return aas_models, submodel_models
patch_id_short_with_temp_attribute(submodel_element_collection)
Patch the id_short of a SubmodelElementCollection as an attribute in the value of the SubmodelElementCollection, to make it accesible after retrieving from the value list.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
submodel_element_collection |
model.SubmodelElementCollection |
SubmodelElementCollection to patch |
required |
Source code in aas_middleware\model\formatting\aas\convert_pydantic.py
def patch_id_short_with_temp_attribute(
submodel_element_collection: model.SubmodelElementCollection
) -> None:
"""
Patch the id_short of a SubmodelElementCollection as an attribute in the value of the SubmodelElementCollection, to make it accesible after retrieving from the value list.
Args:
submodel_element_collection (model.SubmodelElementCollection): SubmodelElementCollection to patch
"""
temp_id_short_property = model.Property(
id_short="temp_id_short_attribute_" + uuid.uuid4().hex,
value_type=get_value_type_of_attribute(str),
value=submodel_element_collection.id_short,
)
submodel_element_collection.value.add(temp_id_short_property)
convert_util
get_attribute_dict(obj)
Returns a dictionary of all attributes of an object that are not None, do not start with an underscore and are not standard attributes of the aas object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Union[aas_model.AAS, aas_model.Submodel, aas_model.SubmodelElementCollection] |
Object to get the attributes from |
required |
Returns:
Type | Description |
---|---|
Dict[str, Union[aas_model.Submodel, aas_model.SubmodelElement]] |
Dictionary of all attributes of the object and their respective values |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def get_attribute_dict(
obj: Union[aas_model.AAS, aas_model.Submodel, aas_model.SubmodelElementCollection]
) -> Dict[str, Union[aas_model.Submodel, aas_model.SubmodelElement]]:
"""
Returns a dictionary of all attributes of an object that are not None, do not start with an underscore and are not standard attributes of the aas object.
Args:
obj (Union[aas_model.AAS, aas_model.Submodel, aas_model.SubmodelElementCollection]): Object to get the attributes from
Returns:
Dict[str, Union[aas_model.Submodel, aas_model.SubmodelElement]]: Dictionary of all attributes of the object and their respective values
"""
vars_dict = vars(obj)
vars_dict = {key: value for key, value in vars_dict.items() if key[0] != "_"}
vars_dict = {key: value for key, value in vars_dict.items() if value is not None}
vars_dict = {key: value for key, value in vars_dict.items() if key != "id"}
vars_dict = {key: value for key, value in vars_dict.items() if key != "description"}
vars_dict = {key: value for key, value in vars_dict.items() if key != "id_short"}
vars_dict = {key: value for key, value in vars_dict.items() if key != "semantic_id"}
return vars_dict
get_attribute_name_from_basyx_model(item, referenced_item_id)
Returns the attribute name of the referenced element of the item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
item |
Union[model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection] |
The container of the refernced item |
required |
referenced_item_id |
str |
The id of the referenced item |
required |
Exceptions:
Type | Description |
---|---|
ValueError |
If not data specifications are found in the item or if no attribute name is found |
Returns:
Type | Description |
---|---|
str |
The attribute name of the referenced item |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def get_attribute_name_from_basyx_model(
item: typing.Union[
model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection
],
referenced_item_id: str,
) -> str:
"""
Returns the attribute name of the referenced element of the item.
Args:
item (typing.Union[model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection]): The container of the refernced item
referenced_item_id (str): The id of the referenced item
Raises:
ValueError: If not data specifications are found in the item or if no attribute name is found
Returns:
str: The attribute name of the referenced item
"""
if not item.embedded_data_specifications:
raise ValueError("No data specifications found in item:", item)
for data_spec in item.embedded_data_specifications:
content = data_spec.data_specification_content
if not isinstance(content, model.DataSpecificationIEC61360):
continue
if not any(
key.value == referenced_item_id for key in data_spec.data_specification.key
):
continue
if not content.preferred_name.get("en") == "attribute":
continue
return content.value
raise ValueError(
f"Attribute reference to {referenced_item_id} could not be found in {item.id_short} of type {type(item)}"
)
get_basyx_description_from_model(model_object)
Creates a LangStringSet from an aas model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model_object |
aas_model.AAS | aas_model.Submodel | aas_model.SubmodelElementCollection |
The model to get the description from. |
required |
Returns:
Type | Description |
---|---|
model.LangStringSet |
LangStringSet description representation of the model object |
Exceptions:
Type | Description |
---|---|
ValueError |
If the description of the model object is not a dict or a string |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def get_basyx_description_from_model(
model_object: (
aas_model.AAS | aas_model.Submodel | aas_model.SubmodelElementCollection
),
) -> model.LangStringSet:
"""
Creates a LangStringSet from an aas model.
Args:
model_object (aas_model.AAS | aas_model.Submodel | aas_model.SubmodelElementCollection): The model to get the description from.
Returns:
model.LangStringSet: LangStringSet description representation of the model object
Raises:
ValueError: If the description of the model object is not a dict or a string
"""
if not model_object.description:
return None
try:
dict_description = json.loads(model_object.description)
if not isinstance(dict_description, dict):
raise ValueError
except ValueError:
dict_description = {"en": model_object.description}
return model.LangStringSet(dict_description)
get_class_name_from_basyx_model(item)
Returns the class name of an basyx model from the data specifications.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
item |
model.HasDataSpecification |
Basyx model to get the class name from |
required |
Exceptions:
Type | Description |
---|---|
ValueError |
If no data specifications are found in the item or if no class name is found |
Returns:
Type | Description |
---|---|
str |
Class name of the basyx model |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def get_class_name_from_basyx_model(
item: typing.Union[
model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection
]
) -> str:
"""
Returns the class name of an basyx model from the data specifications.
Args:
item (model.HasDataSpecification): Basyx model to get the class name from
Raises:
ValueError: If no data specifications are found in the item or if no class name is found
Returns:
str: Class name of the basyx model
"""
if not item.embedded_data_specifications:
raise ValueError("No data specifications found in item:", item)
for data_spec in item.embedded_data_specifications:
content = data_spec.data_specification_content
if not isinstance(content, model.DataSpecificationIEC61360):
continue
if not any(
key.value == item.id_short for key in data_spec.data_specification.key
):
continue
if not content.preferred_name.get("en") == "class":
continue
return content.value
raise ValueError(
f"No class name found in item with id {item.id_short} and type {type(item)}"
)
get_semantic_id_value_of_model(basyx_model)
Returns the semantic id of a submodel or submodel element.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
basyx_model |
model.Submodel | model.SubmodelElement |
Basyx model to get the semantic id from. |
required |
Returns:
Type | Description |
---|---|
str |
Semantic id of the model. |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def get_semantic_id_value_of_model(
basyx_model: typing.Union[model.Submodel, model.SubmodelElement]
) -> str:
"""
Returns the semantic id of a submodel or submodel element.
Args:
basyx_model (model.Submodel | model.SubmodelElement): Basyx model to get the semantic id from.
Returns:
str: Semantic id of the model.
"""
if not isinstance(basyx_model, model.HasSemantics):
raise NotImplementedError("Type not implemented:", type(basyx_model))
if not basyx_model.semantic_id:
return ""
return basyx_model.semantic_id.key[0].value
get_str_description(langstring_set)
Converts a LangStringSet to a string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
langstring_set |
model.LangStringSet |
LangStringSet to convert |
required |
Returns:
Type | Description |
---|---|
str |
String representation of the LangStringSet |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def get_str_description(langstring_set: model.LangStringSet) -> str:
"""
Converts a LangStringSet to a string.
Args:
langstring_set (model.LangStringSet): LangStringSet to convert
Returns:
str: String representation of the LangStringSet
"""
if not langstring_set:
return ""
dict_description = {}
if "en" in langstring_set:
return str(langstring_set.get("en"))
elif "ger" in langstring_set:
return str(langstring_set.get("ger"))
elif "de" in langstring_set:
return str(langstring_set.get("de"))
else:
return str(langstring_set.get(list(langstring_set.keys())[0]))
is_attribute_from_basyx_model_immutable(item, referenced_item_id)
Returns if the referenced item of the item is immutable.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
item |
Union[model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection] |
The container of the refernced item |
required |
referenced_item_id |
str |
The id of the referenced item |
required |
Exceptions:
Type | Description |
---|---|
ValueError |
If not data specifications are found in the item or if no attribute name is found |
Returns:
Type | Description |
---|---|
bool |
If the referenced item is immutable |
Source code in aas_middleware\model\formatting\aas\convert_util.py
def is_attribute_from_basyx_model_immutable(
item: typing.Union[
model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection
],
referenced_item_id: str,
) -> bool:
"""
Returns if the referenced item of the item is immutable.
Args:
item (typing.Union[model.AssetAdministrationShell, model.Submodel, model.SubmodelElementCollection]): The container of the refernced item
referenced_item_id (str): The id of the referenced item
Raises:
ValueError: If not data specifications are found in the item or if no attribute name is found
Returns:
bool: If the referenced item is immutable
"""
if not item.embedded_data_specifications:
raise ValueError("No data specifications found in item:", item)
for data_spec in item.embedded_data_specifications:
content = data_spec.data_specification_content
if not isinstance(content, model.DataSpecificationIEC61360):
continue
if not any(
key.value == referenced_item_id for key in data_spec.data_specification.key
):
continue
if not content.preferred_name.get("en") == "immutable":
continue
return content.value == "true"
raise ValueError(
f"Attribute reference to {referenced_item_id} could not be found in {item.id_short} of type {type(item)}"
)
formatter
Formatter (Protocol)
Protocol for all formatters that are used to serialize and deserialize data models.
Source code in aas_middleware\model\formatting\formatter.py
class Formatter(Protocol):
"""
Protocol for all formatters that are used to serialize and deserialize data models.
"""
def serialize(self, data: DataModel) -> Any:
"""
Serialize a DataModel object to the specific format of the formatter.
Args:
data (DataModel): A data model
Returns:
Any: A string in the specific format of the formatter.
"""
...
def deserialize(self, data: Any) -> DataModel:
"""
Deserialize the specific format of the formater to a DataModel object.
Args:
data (Any): The specific format of the formatter.
Returns:
DataModel: A data model that holds the objects that were deserialized
"""
...
deserialize(self, data)
Deserialize the specific format of the formater to a DataModel object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Any |
The specific format of the formatter. |
required |
Returns:
Type | Description |
---|---|
DataModel |
A data model that holds the objects that were deserialized |
Source code in aas_middleware\model\formatting\formatter.py
serialize(self, data)
Serialize a DataModel object to the specific format of the formatter.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
DataModel |
A data model |
required |
Returns:
Type | Description |
---|---|
Any |
A string in the specific format of the formatter. |
mapping
special
mapper
Mapper (Protocol)
Protocol for all mappers that are used to map data models to other data models.
Source code in aas_middleware\model\mapping\mapper.py
@typing.runtime_checkable
class Mapper(Protocol, Generic[S, T]):
"""
Protocol for all mappers that are used to map data models to other data models.
"""
def map(self, data: S) -> T:
"""
Map a DataModel object to another DataModel object with different types and structure.
Args:
data (DataModel): A data model
Returns:
DataModel: The mapped data model.
"""
...
map(self, data)
Map a DataModel object to another DataModel object with different types and structure.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
DataModel |
A data model |
required |
Returns:
Type | Description |
---|---|
DataModel |
The mapped data model. |
reference_finder
ReferenceFinder
Source code in aas_middleware\model\reference_finder.py
class ReferenceFinder:
model: Identifiable
contained_models: List[Identifiable] = []
references: List[ReferenceInfo] = []
contained_schemas: List[Type[Identifiable]] = []
schema_references: List[ReferenceInfo] = []
@classmethod
def find(
cls, model: Identifiable
) -> Tuple[List[Identifiable], Set[ReferenceInfo]]:
"""
Method to find all contained models (inclusive the model itself) and references in a given model.
Args:
model (Identifiable): The model to find contained models and references in.
Returns:
Tuple[List[Identifiable], List[ReferenceInfo]]: A tuple containing the list of contained models and the list of references.
"""
finder = cls()
finder.model = model
finder.find_contained_identifiables_and_references()
return finder.contained_models, finder.references
def find_contained_identifiables_and_references(self):
"""
Method to find all contained identifiables (inclusive the model itself) and references in the model.
"""
self.contained_models = get_all_contained_identifiables(self.model)
self.references = get_reference_infos(self.contained_models)
@classmethod
def find_schema_references(
cls,
model: Identifiable,
) -> Tuple[List[Identifiable], Set[ReferenceInfo]]:
"""
Method to find all contained models (inclusive the model itself) and references in a given model.
Args:
model (Identifiable): The model to find contained models and references in.
Returns:
Tuple[List[Identifiable], List[ReferenceInfo]]: A tuple containing the list of contained models and the list of references.
"""
finder = cls()
finder.model = model
finder.find_contained_schemas_and_references()
return finder.contained_schemas, finder.schema_references
def find_contained_schemas_and_references(self):
"""
Method to find all contained identifiables (inclusive the model itself) and references in the model.
"""
self.contained_schemas = get_all_contained_schemas(self.model)
self.schema_references = get_schema_reference_infos(self.contained_schemas)
# FIXME: resolve empty referenced nodes without an associated type -> either find subclasses or classes that contain the referenced name (e.g. "acticePoleHousing" for class "PoleHousing")
find(model)
classmethod
Method to find all contained models (inclusive the model itself) and references in a given model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Identifiable |
The model to find contained models and references in. |
required |
Returns:
Type | Description |
---|---|
Tuple[List[Identifiable], List[ReferenceInfo]] |
A tuple containing the list of contained models and the list of references. |
Source code in aas_middleware\model\reference_finder.py
@classmethod
def find(
cls, model: Identifiable
) -> Tuple[List[Identifiable], Set[ReferenceInfo]]:
"""
Method to find all contained models (inclusive the model itself) and references in a given model.
Args:
model (Identifiable): The model to find contained models and references in.
Returns:
Tuple[List[Identifiable], List[ReferenceInfo]]: A tuple containing the list of contained models and the list of references.
"""
finder = cls()
finder.model = model
finder.find_contained_identifiables_and_references()
return finder.contained_models, finder.references
find_contained_identifiables_and_references(self)
Method to find all contained identifiables (inclusive the model itself) and references in the model.
Source code in aas_middleware\model\reference_finder.py
find_contained_schemas_and_references(self)
Method to find all contained identifiables (inclusive the model itself) and references in the model.
Source code in aas_middleware\model\reference_finder.py
def find_contained_schemas_and_references(self):
"""
Method to find all contained identifiables (inclusive the model itself) and references in the model.
"""
self.contained_schemas = get_all_contained_schemas(self.model)
self.schema_references = get_schema_reference_infos(self.contained_schemas)
# FIXME: resolve empty referenced nodes without an associated type -> either find subclasses or classes that contain the referenced name (e.g. "acticePoleHousing" for class "PoleHousing")
find_schema_references(model)
classmethod
Method to find all contained models (inclusive the model itself) and references in a given model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Identifiable |
The model to find contained models and references in. |
required |
Returns:
Type | Description |
---|---|
Tuple[List[Identifiable], List[ReferenceInfo]] |
A tuple containing the list of contained models and the list of references. |
Source code in aas_middleware\model\reference_finder.py
@classmethod
def find_schema_references(
cls,
model: Identifiable,
) -> Tuple[List[Identifiable], Set[ReferenceInfo]]:
"""
Method to find all contained models (inclusive the model itself) and references in a given model.
Args:
model (Identifiable): The model to find contained models and references in.
Returns:
Tuple[List[Identifiable], List[ReferenceInfo]]: A tuple containing the list of contained models and the list of references.
"""
finder = cls()
finder.model = model
finder.find_contained_schemas_and_references()
return finder.contained_schemas, finder.schema_references
ReferenceInfo (BaseModel)
Object reference to a model in the data model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
identifiable_id |
str |
The id of the identifiable. |
required |
reference_id |
str |
The id of the referenced identifiable. |
required |
reference_type |
ReferenceType |
The type of the reference. |
required |
Source code in aas_middleware\model\reference_finder.py
class ReferenceInfo(BaseModel):
"""
Object reference to a model in the data model.
Args:
identifiable_id (str): The id of the identifiable.
reference_id (str): The id of the referenced identifiable.
reference_type (ReferenceType): The type of the reference.
"""
identifiable_id: str
reference_id: str
reference_type: ReferenceType
model_config = ConfigDict(frozen=True)
ReferenceType (Enum)
Enum for the reference types. There exist three types of references: - Association: The reference is done by an association between two objects, where the model has the referenced object as an attribute. - Reference: The reference element is an object and the reference in the model is done by referencing the id of the referenced object. - Attribute: The referenced element is an primitive attribute of the model.
Source code in aas_middleware\model\reference_finder.py
class ReferenceType(Enum):
"""
Enum for the reference types. There exist three types of references:
- Association: The reference is done by an association between two objects, where the model has the referenced object as an attribute.
- Reference: The reference element is an object and the reference in the model is done by referencing the id of the referenced object.
- Attribute: The referenced element is an primitive attribute of the model.
"""
ASSOCIATION = "association"
REFERENCE = "reference"
ATTRIBUTE = "attribute"
get_reference_infos(identifiables)
Method to get all reference infos of a list of identifiables.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
identifiables |
List[Identifiable] |
The list of identifiables. |
required |
Returns:
Type | Description |
---|---|
Set[ReferenceInfo] |
The list of reference infos. |
Source code in aas_middleware\model\reference_finder.py
def get_reference_infos(identifiables: List[Identifiable]) -> Set[ReferenceInfo]:
"""
Method to get all reference infos of a list of identifiables.
Args:
identifiables (List[Identifiable]): The list of identifiables.
Returns:
Set[ReferenceInfo]: The list of reference infos.
"""
reference_infos = set()
for identifiable in identifiables:
reference_infos = reference_infos | get_reference_infos_of_model(identifiable)
return reference_infos
get_reference_infos_of_model(model)
Method to add information about referencing model ids of the input model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Referable |
The model to add the information for. |
required |
Returns:
Type | Description |
---|---|
Set[ReferenceInfo] |
The list of reference infos. |
Source code in aas_middleware\model\reference_finder.py
def get_reference_infos_of_model(model: Identifiable) -> Set[ReferenceInfo]:
"""
Method to add information about referencing model ids of the input model.
Args:
model (Referable): The model to add the information for.
Returns:
Set[ReferenceInfo]: The list of reference infos.
"""
reference_infos = set()
identifiables_of_model = get_identifiable_attributes_of_model(model)
for identifiable in identifiables_of_model:
if identifiable == model:
continue
reference_info = ReferenceInfo(
identifiable_id=get_id_with_patch(model),
reference_id=get_id_with_patch(identifiable),
reference_type=ReferenceType.ASSOCIATION,
)
reference_infos.add(reference_info)
indirect_references = get_referenced_ids_of_model(model)
for indirect_reference in indirect_references:
reference_info = ReferenceInfo(
identifiable_id=get_id_with_patch(model),
reference_id=indirect_reference,
reference_type=ReferenceType.REFERENCE,
)
reference_infos.add(reference_info)
unidentifiable_attributes = get_unidentifiable_attributes_of_model(model)
for attribute_name, attribute_value in unidentifiable_attributes.items():
reference_info = ReferenceInfo(
identifiable_id=get_id_with_patch(model),
reference_id=f"{attribute_name}={attribute_value}",
reference_type=ReferenceType.ATTRIBUTE,
)
reference_infos.add(reference_info)
return reference_infos
get_reference_infos_of_schema(schema)
Method to add information about referencing schema ids of the input schema.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Identifiable] |
The schema to add the information for. |
required |
Returns:
Type | Description |
---|---|
Set[ReferenceInfo] |
The list of reference infos. |
Source code in aas_middleware\model\reference_finder.py
def get_reference_infos_of_schema(schema: Type[Identifiable]) -> Set[ReferenceInfo]:
"""
Method to add information about referencing schema ids of the input schema.
Args:
schema (Type[Identifiable]): The schema to add the information for.
Returns:
Set[ReferenceInfo]: The list of reference infos.
"""
reference_infos = set()
attribute_dict_of_schema = get_attribute_dict_of_schema(schema)
for attribute_name, attribute_type in attribute_dict_of_schema.items():
attribute_types = get_identifiable_types(attribute_type)
for arg in attribute_types:
reference_info = get_reference_info_for_schema(schema, attribute_name, arg)
if not reference_info:
continue
reference_infos.add(reference_info)
return reference_infos
get_schema_reference_infos(schemas)
Method to get all reference infos of a list of schemas.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schemas |
List[Type[Identifiable]] |
The list of schemas. |
required |
Returns:
Type | Description |
---|---|
List[ReferenceInfo] |
The list of reference infos. |
Source code in aas_middleware\model\reference_finder.py
def get_schema_reference_infos(schemas: List[Type[Identifiable]]) -> Set[ReferenceInfo]:
"""
Method to get all reference infos of a list of schemas.
Args:
schemas (List[Type[Identifiable]]): The list of schemas.
Returns:
List[ReferenceInfo]: The list of reference infos.
"""
reference_infos = set()
for schema in schemas:
reference_infos = reference_infos | get_reference_infos_of_schema(schema)
return reference_infos
schema_util
add_non_redundant_schema(schema, schemas)
Method to add a schema to a list of schemas if it is not already in the list.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Identifiable] |
The schema to add. |
required |
schemas |
List[Type[Identifiable]] |
The list of schemas. |
required |
Source code in aas_middleware\model\schema_util.py
def add_non_redundant_schema(schema: Type[Identifiable], schemas: List[Type[Identifiable]]):
"""
Method to add a schema to a list of schemas if it is not already in the list.
Args:
schema (Type[Identifiable]): The schema to add.
schemas (List[Type[Identifiable]]): The list of schemas.
"""
if schema not in schemas:
schemas.append(schema)
get_all_contained_schemas(schema)
Method to iterate over an Identifiable model and get all contained Identifiables.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Identifiable] |
The referable data model. |
required |
Returns:
Type | Description |
---|---|
List[Type[Referable]] |
The list of referables. |
Source code in aas_middleware\model\schema_util.py
def get_all_contained_schemas(schema: Type[Identifiable]) -> List[Type[Identifiable]]:
"""
Method to iterate over an Identifiable model and get all contained Identifiables.
Args:
schema (Type[Identifiable]): The referable data model.
Returns:
List[Type[Referable]]: The list of referables.
"""
contained_schemas = []
identifiable_schema_attributes = get_identifiable_attributes(schema)
for identifiable_schema_attribute in identifiable_schema_attributes.values():
in_attribute_contained_identifiable_schema = get_all_contained_schemas(
identifiable_schema_attribute
)
for schema_attribute in in_attribute_contained_identifiable_schema:
add_non_redundant_schema(schema_attribute, contained_schemas)
if is_identifiable_type_container(schema):
for item in typing.get_args(schema):
in_attribute_contained_identifiable_schema = get_all_contained_schemas(item)
for schema_attribute in in_attribute_contained_identifiable_schema:
add_non_redundant_schema(schema_attribute, contained_schemas)
elif is_identifiable_type(schema):
add_non_redundant_schema(schema, contained_schemas)
return contained_schemas
get_attribute_dict_of_schema(schema)
Method to get all attributes of a model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Type[Identifiable] |
The referable data model. |
required |
Returns:
Type | Description |
---|---|
Dict[str, Type[Identifiable]] |
The dictionary of attributes. |
Source code in aas_middleware\model\schema_util.py
def get_attribute_dict_of_schema(schema: Type[Identifiable]) -> Dict[str, Type[Identifiable]]:
"""
Method to get all attributes of a model.
Args:
model (Type[Identifiable]): The referable data model.
Returns:
Dict[str, Type[Identifiable]]: The dictionary of attributes.
"""
attribute_dict = {}
if not isinstance(schema, type):
return attribute_dict
if issubclass(schema, BaseModel):
for field_name, field in schema.model_fields.items():
attribute_dict[field_name] = field.annotation
else:
annotations = typing.get_type_hints(schema.__init__)
for parameter_name, parameter in annotations.items():
attribute_dict[parameter_name] = parameter
return attribute_dict
get_identifiable_attributes(schema)
Method to get all attributes of a model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Identifiable] |
The referable data model. |
required |
Returns:
Type | Description |
---|---|
List[str] |
The list of attributes. |
Source code in aas_middleware\model\schema_util.py
def get_identifiable_attributes(schema: Type[Identifiable]) -> Dict[str, Type[Identifiable]]:
"""
Method to get all attributes of a model.
Args:
schema (Type[Identifiable]): The referable data model.
Returns:
List[str]: The list of attributes.
"""
schema_attributes = get_attribute_dict_of_schema(schema)
identifiable_attributes = {}
for attribute_name, attribute_type in schema_attributes.items():
if is_identifiable_type(attribute_type) or is_identifiable_type_container(attribute_type):
identifiable_attributes[attribute_name] = attribute_type
return identifiable_attributes
util
add_non_redundant_identifiable(model, identifiables)
Method to add an Identifiable to a list of Identifiables if it is not already in the list.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Identifiable |
The Identifiable to add. |
required |
identifiables |
List[Identifiable] |
The list of contained Identifiables. |
required |
Returns:
Type | Description |
---|---|
List[Identifiable] |
The list of Identifiables with the added model. |
Source code in aas_middleware\model\util.py
def add_non_redundant_identifiable(
model: Identifiable, identifiables: List[Identifiable]
) -> List[Identifiable]:
"""
Method to add an Identifiable to a list of Identifiables if it is not already in the list.
Args:
model (Identifiable): The Identifiable to add.
identifiables (List[Identifiable]): The list of contained Identifiables.
Returns:
List[Identifiable]: The list of Identifiables with the added model.
"""
# TODO: maybe use directly a dict here to avoid iteration by using hashable ids
if not any(
get_id_with_patch(model) == get_id_with_patch(other_referable)
for other_referable in identifiables
):
identifiables.append(model)
return identifiables
convert_camel_case_to_underscrore_str(came_case_string)
Convert a camel case string to an underscore seperated string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
class_name |
str |
The camel case string to convert. |
required |
Returns:
Type | Description |
---|---|
str |
The underscore seperated string. |
Source code in aas_middleware\model\util.py
def convert_camel_case_to_underscrore_str(came_case_string: str) -> str:
"""
Convert a camel case string to an underscore seperated string.
Args:
class_name (str): The camel case string to convert.
Returns:
str: The underscore seperated string.
"""
came_case_string = came_case_string[0].lower() + came_case_string[1:]
new_class_name = re.sub(r"(?<!^)(?=[A-Z])", "_", came_case_string).lower()
if all(len(el) == 1 for el in new_class_name.split("_")):
new_class_name = new_class_name.replace("_", "")
return new_class_name
convert_to_fitting_identifiable_container_type(list_container, container_type)
Function to convert a list of identifiables to a fitting container type.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
list_container |
List[Identifiable] |
The list of identifiables. |
required |
container_type |
Type[Any] |
The container type. |
required |
Returns:
Type | Description |
---|---|
List[Identifiable] | Tuple[Identifiable] | Set[Identifiable] |
The container type. |
Source code in aas_middleware\model\util.py
def convert_to_fitting_identifiable_container_type(list_container: List[Identifiable], container_type: Type[Any]) -> List[Identifiable] | Tuple[Identifiable] | Set[Identifiable]:
"""
Function to convert a list of identifiables to a fitting container type.
Args:
list_container (List[Identifiable]): The list of identifiables.
container_type (Type[Any]): The container type.
Returns:
List[Identifiable] | Tuple[Identifiable] | Set[Identifiable]: The container type.
"""
if container_type == list:
return list_container
elif container_type == tuple:
return tuple(list_container)
elif container_type == set:
return set(list_container)
else:
raise ValueError("Container type not supported.")
convert_under_score_to_camel_case_str(underscore_str)
Convert a underscore seperated string to a camel case string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
class_name |
str |
The underscore seperated string to convert. |
required |
Returns:
Type | Description |
---|---|
str |
The camel case string. |
Source code in aas_middleware\model\util.py
def convert_under_score_to_camel_case_str(underscore_str: str) -> str:
"""
Convert a underscore seperated string to a camel case string.
Args:
class_name (str): The underscore seperated string to convert.
Returns:
str: The camel case string.
"""
words = underscore_str.split("_")
camel_case_str = "".join(word[0].capitalize() + word[1:] for word in words)
return camel_case_str
get_all_contained_identifiables(model)
Method to iterate over an Identifiable model and get all contained Identifiables.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
REFERABLE_DATA_MODEL |
The referable data model. |
required |
Returns:
Type | Description |
---|---|
List[Referable] |
The list of referables. |
Source code in aas_middleware\model\util.py
def get_all_contained_identifiables(model: Identifiable) -> List[Identifiable]:
"""
Method to iterate over an Identifiable model and get all contained Identifiables.
Args:
model (REFERABLE_DATA_MODEL): The referable data model.
Returns:
List[Referable]: The list of referables.
"""
contained_identifiables = []
identifiable_attributes = get_identifiable_attributes_of_model(model)
for identifiable_attribute in identifiable_attributes:
in_attribute_contained_identifiables = get_all_contained_identifiables(
identifiable_attribute
)
for identifiable in in_attribute_contained_identifiables:
add_non_redundant_identifiable(identifiable, contained_identifiables)
if is_identifiable_container(model):
for item in model:
in_attribute_contained_identifiables = get_all_contained_identifiables(item)
for identifiable in in_attribute_contained_identifiables:
add_non_redundant_identifiable(identifiable, contained_identifiables)
elif is_identifiable(model):
add_non_redundant_identifiable(model, contained_identifiables)
return contained_identifiables
get_attribute_name_encoded_references(model)
Function to get the referenced ids of a model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Referable |
The model. |
required |
Returns:
Type | Description |
---|---|
List[str] |
The referenced ids. |
Source code in aas_middleware\model\util.py
def get_attribute_name_encoded_references(model: Identifiable) -> List[str]:
"""
Function to get the referenced ids of a model.
Args:
model (Referable): The model.
Returns:
List[str]: The referenced ids.
"""
referenced_ids = []
for attribute_name, attribute_value in vars(model).items():
if (
attribute_name in STANDARD_AAS_FIELDS
or attribute_name in REFERENCE_ATTRIBUTE_NAMES_SUFFIXES
):
continue
if not any(
attribute_name.endswith(suffix)
for suffix in REFERENCE_ATTRIBUTE_NAMES_SUFFIXES
):
continue
if isinstance(attribute_value, str | int | UUID):
referenced_ids.append(str(attribute_value))
else:
referenced_ids += [str(item) for item in attribute_value if item]
return referenced_ids
get_id(model)
Function to get the id attribute of an arbitrary model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Any |
The model. |
required |
Returns:
Type | Description |
---|---|
Optional[str | int | UUID] |
The id attribute. |
Exceptions:
Type | Description |
---|---|
ValueError |
if the model is not an object, BaseModel or dict or if no id attribute is available |
Source code in aas_middleware\model\util.py
def get_id(model: Any) -> str | int | UUID:
"""
Function to get the id attribute of an arbitrary model.
Args:
model (Any): The model.
Returns:
Optional[str | int | UUID]: The id attribute.
Raises:
ValueError: if the model is not an object, BaseModel or dict or if no id attribute is available
"""
if not is_identifiable(model):
raise ValueError("Model is a basic type and has no id attribute.")
if isinstance(model, BaseModel):
identifiable_fields = get_identifier_type_fields(model.model_fields)
if len(identifiable_fields) > 1:
raise ValueError(f"Model has multiple Identifier attributes: {model}")
if identifiable_fields:
return getattr(model, identifiable_fields[0])
elif hasattr(model, "__dict__"):
# TODO: use typing.get_type_hints instead of inspect.signature
sig = inspect.signature(type(model).__init__)
potential_identifier = []
for param in sig.parameters.values():
if param.annotation == Identifier or param.annotation == "Identifier":
potential_identifier.append(param.name)
if len(potential_identifier) > 1:
raise ValueError(f"Model {model} has multiple Identifier attributes.")
if potential_identifier:
return getattr(model, potential_identifier[0])
if isinstance(model, BaseModel):
data = model.model_dump()
elif isinstance(model, dict):
data = model
else:
data = vars(model)
potential_id_attributes = [
"id",
"id_short",
"Id",
"ID",
"Identifier",
"identifier",
"Identity",
"identity",
]
for id_attribute in potential_id_attributes:
if id_attribute in data and isinstance(data[id_attribute], str | int | UUID):
return data[id_attribute]
raise ValueError(
f"Model {model} has no attribute that can be used as id attribute."
)
get_id_with_patch(model)
Function to get the id attribute of an arbitrary model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Any |
The model. |
required |
Returns:
Type | Description |
---|---|
Optional[str | int | UUID] |
The id attribute. |
Source code in aas_middleware\model\util.py
def get_id_with_patch(model: Any) -> str:
"""
Function to get the id attribute of an arbitrary model.
Args:
model (Any): The model.
Returns:
Optional[str | int | UUID]: The id attribute.
"""
if not is_identifiable(model):
raise ValueError("Not identifiable object supplied.")
try:
return str(get_id(model))
except ValueError:
return "id_" + str(id(model))
get_identifier_type_fields(field_info_dict)
Function to get the fields of a model that are of type Identifier.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
BaseModel |
A Basemodel that is checked for identifier fields |
required |
Returns:
Type | Description |
---|---|
List[str] |
The field names that are Identifiers |
Source code in aas_middleware\model\util.py
def get_identifier_type_fields(field_info_dict: Dict[str, FieldInfo]) -> List[str]:
"""
Function to get the fields of a model that are of type Identifier.
Args:
model (BaseModel): A Basemodel that is checked for identifier fields
Returns:
List[str]: The field names that are Identifiers
"""
model_fields = []
for field_name, field_info in field_info_dict.items():
if field_info.annotation == Identifier:
model_fields.append(field_name)
return model_fields
get_reference_name(attribute_name, attribute_type)
Function to get the reference name of an attribute.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
attribute_name |
str |
The attribute name. |
required |
attribute_type |
Type[Any] |
The type of the attribute. |
required |
Returns:
Type | Description |
---|---|
str |
The name of the referenced type. |
Source code in aas_middleware\model\util.py
def get_reference_name(attribute_name: str, attribute_type: Type[Any]) -> Optional[str]:
"""
Function to get the reference name of an attribute.
Args:
attribute_name (str): The attribute name.
attribute_type (Type[Any]): The type of the attribute.
Returns:
str: The name of the referenced type.
"""
if attribute_name in REFERENCE_ATTRIBUTE_NAMES_SUFFIXES or attribute_name in STANDARD_AAS_FIELDS:
return
if attribute_type == Reference or attribute_type == "Reference":
return attribute_name
elif typing.get_origin(attribute_type) in [List, Set, Tuple, Union] and Reference in typing.get_args(attribute_type):
return attribute_name
elif any (attribute_name.endswith(suffix) for suffix in REFERENCE_ATTRIBUTE_NAMES_SUFFIXES):
suffix = next(suffix for suffix in REFERENCE_ATTRIBUTE_NAMES_SUFFIXES if attribute_name.endswith(suffix))
underscore_consideration = False
if attribute_name.endswith(f"_{suffix}"):
underscore_consideration = True
attribute_name_without_suffix = attribute_name[:-(len(suffix) + underscore_consideration)]
if attribute_name_without_suffix.endswith("s") and not attribute_name_without_suffix.endswith("ss"):
attribute_name_without_suffix = attribute_name_without_suffix[:-1]
return convert_under_score_to_camel_case_str(attribute_name_without_suffix)
get_referenced_ids_of_model(model)
Function to get the referenced ids of a model by searching for type Reference and attribute names which suggest references.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Referable |
The model to get the references from. |
required |
Returns:
Type | Description |
---|---|
List[str] |
The referenced ids. |
Source code in aas_middleware\model\util.py
def get_referenced_ids_of_model(model: Identifiable) -> Set[str]:
"""
Function to get the referenced ids of a model by searching for type Reference and attribute names which suggest references.
Args:
model (Referable): The model to get the references from.
Returns:
List[str]: The referenced ids.
"""
referenced_ids = []
if isinstance(model, BaseModel):
referenced_ids += get_references_of_reference_type_for_basemodel(model)
elif hasattr(model, "__dict__"):
referenced_ids += get_references_of_reference_type_for_object(model)
referenced_ids += get_attribute_name_encoded_references(model)
return set(referenced_ids)
get_references_of_reference_type_for_basemodel(model)
Function to get the references of a model that are of type Reference.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
BaseModel |
The model. |
required |
Returns:
Type | Description |
---|---|
List[str] |
The reference fields. |
Source code in aas_middleware\model\util.py
def get_references_of_reference_type_for_basemodel(model: BaseModel) -> List[str]:
"""
Function to get the references of a model that are of type Reference.
Args:
model (BaseModel): The model.
Returns:
List[str]: The reference fields.
"""
references = []
for field_name, field_info in model.model_fields.items():
if field_info.annotation == Reference or field_info.annotation == "Reference":
references.append(getattr(model, field_name))
if field_info.annotation == List[Reference]:
references += getattr(model, field_name)
return [str(ref) for ref in references if ref]
get_references_of_reference_type_for_object(model)
Function to get the references of a model that are of type Reference.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
BaseModel |
The model. |
required |
Returns:
Type | Description |
---|---|
List[str] |
The reference fields. |
Source code in aas_middleware\model\util.py
def get_references_of_reference_type_for_object(model: object) -> List[str]:
"""
Function to get the references of a model that are of type Reference.
Args:
model (BaseModel): The model.
Returns:
List[str]: The reference fields.
"""
references = []
sig = inspect.signature(type(model).__init__)
for param in sig.parameters.values():
if param.annotation == Reference:
references.append(getattr(model, param.name))
if param.annotation == List[Reference]:
references += getattr(model, param.name)
return [str(ref) for ref in references if ref]
get_value_attributes(obj)
Function to get an dict of all attributes of an object without the private attributes and standard AAS attributes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
object |
The object. |
required |
Returns:
Type | Description |
---|---|
dict |
The value attributes. |
Source code in aas_middleware\model\util.py
def get_value_attributes(obj: object) -> Dict[str, Any]:
"""
Function to get an dict of all attributes of an object without the private attributes and standard AAS attributes.
Args:
obj (object): The object.
Returns:
dict: The value attributes.
"""
vars_dict = {}
object_id = get_id_with_patch(obj)
for attribute_name, attribute_value in vars(obj).items():
if attribute_name.startswith("_"):
continue
if attribute_name in STANDARD_AAS_FIELDS:
continue
if attribute_value == object_id:
continue
if attribute_value is None:
continue
vars_dict[attribute_name] = attribute_value
return vars_dict
is_identifiable(model)
Function to check if a model is identifiable.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Any |
The model. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the model is identifiable, False otherwise. |
is_identifiable_container(model)
Function to check if a model is an identifiable container.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Any |
The model. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the model is an identifiable container, False otherwise. |
Source code in aas_middleware\model\util.py
def is_identifiable_container(model: Any) -> bool:
"""
Function to check if a model is an identifiable container.
Args:
model (Any): The model.
Returns:
bool: True if the model is an identifiable container, False otherwise.
"""
if not isinstance(model, list | tuple | set | dict):
return False
if isinstance(model, list | tuple | set) and not all(
is_identifiable(element) for element in model
):
return False
return True
is_identifiable_type(schema)
Function to check if a schema is identifiable.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Any] |
The schema. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the schema is identifiable, False otherwise. |
Source code in aas_middleware\model\util.py
def is_identifiable_type(schema: Type[Any]) -> bool:
"""
Function to check if a schema is identifiable.
Args:
schema (Type[Any]): The schema.
Returns:
bool: True if the schema is identifiable, False otherwise.
"""
# TODO: refactor to combine is_identifiable and is_identifiable_type
# TODO: handle here also union types
if not isinstance(schema, type):
return False
if issubclass(schema, UnIdentifiable):
return False
return True
is_identifiable_type_container(schema)
Method to check if a schema is a container of identifiables.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
schema |
Type[Any] |
The schema. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the schema is a container of identifiables, False otherwise. |
Source code in aas_middleware\model\util.py
def is_identifiable_type_container(schema: Type[Any]) -> bool:
"""
Method to check if a schema is a container of identifiables.
Args:
schema (Type[Any]): The schema.
Returns:
bool: True if the schema is a container of identifiables, False otherwise.
"""
# TODO: refactor to combine is_identifiable_container and is_identifiable_type_container
if typing.get_origin(schema):
outer_type = typing.get_origin(schema)
else:
outer_type = schema
if not outer_type in [list, tuple, set, dict, Union]:
return False
if outer_type == dict:
raise NotImplementedError("Dicts are not supported yet. Try using classes instead.")
type_arguments = get_identifiable_types(schema)
if not type_arguments:
return False
type_arguments_with_none = [arg for arg in type_arguments if arg != NoneType]
if not all(is_identifiable_type(element) for element in type_arguments_with_none):
return False
return True
models_are_equal(model1, model2)
Function to compare two models for equality.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model1 |
Identifiable |
The first model. |
required |
model2 |
Identifiable |
The second model. |
required |
Returns:
Type | Description |
---|---|
bool |
True if the models are equal, False otherwise. |
Source code in aas_middleware\model\util.py
def models_are_equal(model1: Identifiable, model2: Identifiable) -> bool:
"""
Function to compare two models for equality.
Args:
model1 (Identifiable): The first model.
model2 (Identifiable): The second model.
Returns:
bool: True if the models are equal, False otherwise.
"""
model1_attributes = get_value_attributes(model1)
model2_attributes = get_value_attributes(model2)
if set(model1_attributes.keys()) != set(model2_attributes.keys()):
return False
for attribute_name1, attribute_value1 in model1_attributes.items():
if is_identifiable(attribute_value1):
if not models_are_equal(
attribute_value1, model2_attributes[attribute_name1]
):
return False
elif is_identifiable_container(attribute_value1):
if not is_identifiable_container(model2_attributes[attribute_name1]):
return False
if not len(attribute_value1) == len(model2_attributes[attribute_name1]):
return False
if not all(
models_are_equal(item1, item2)
for item1, item2 in zip(
attribute_value1, model2_attributes[attribute_name1]
)
):
return False
elif attribute_value1 != model2_attributes[attribute_name1]:
return False
return True
replace_attribute_with_model(model, existing_model)
Function to replace an attribute with a model.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Identifiable |
The model. |
required |
existing_model |
Identifiable |
The existing model. |
required |
Source code in aas_middleware\model\util.py
def replace_attribute_with_model(model: Identifiable, existing_model: Identifiable):
"""
Function to replace an attribute with a model.
Args:
model (Identifiable): The model.
existing_model (Identifiable): The existing model.
"""
for attribute_name, attribute_value in vars(model).items():
if is_identifiable(attribute_value):
if attribute_value == existing_model:
setattr(model, attribute_name, existing_model)
else:
replace_attribute_with_model(attribute_value, existing_model)
elif is_identifiable_container(attribute_value):
list_attribute_value = list(attribute_value)
for i, item in enumerate(list_attribute_value):
if item == existing_model:
list_attribute_value[i] = existing_model
else:
replace_attribute_with_model(item, existing_model)
setattr(model, attribute_name, convert_to_fitting_identifiable_container_type(list_attribute_value, type(attribute_value)))