Required Object Attributes¶
Overview¶
The RequiredObjectAttributes class is a subclass of CalculationRequirement that is used to check if a list of attributes are present for an object. This is useful when a calculation requires a specific set of attributes to be present in an object, and it is necessary to check if they exist before proceeding with the calculation.
Usage¶
This requirement can be instantiated with a list of attributes that need to be present for each object. Below there is an example of how to use this requirement:
requirement = RequiredObjectAttributes(attributes={"SDM1-VRN1-01": ["nominal_power", "rotor_diameter"]})
After calling check and get_data methods, the data attribute of the requirement will be a dictionary with the object as the key and a dictionary with the attributes as the value. Below there is an example of how this data is stored:
{
"SDM1-VRN1-01": {
"nominal_power": 4200.0,
"rotor_diameter": 150.0
}
}
Database Requirements¶
This requirements expects that the object_attributes table is set with the necessary attributes for each object. This can easily be done with the database function set_attribute. Below is a query example to set the attributes for the object SDM1-VRN1-01:
SELECT * FROM performance.fn_set_attribute('SDM1-VRN1-01', 'object', 'nominal_power', '{"attribute_value": 4200.0}');
SELECT * FROM performance.fn_set_attribute('SDM1-VRN1-01', 'object', 'rotor_diameter', '{"attribute_value": 150.0}');
To check if the attributes are set correctly, go to the v_object_attributes view in the database.
Class Definition¶
RequiredObjectAttributes(attributes, optional=False)
¶
Subclass of CalculationRequirement that defines the object attributes that are required for the calculation.
This will check the performance database for the existence of the required object attributes for the wanted objects.
Parameters:
-
(attributes¶dict[str, list[str]]) –Object attributes that are required for the calculation.
Should be in the format {object_name: [attribute_name, ...], ...}.
-
(optional¶bool, default:False) –Set to True if this is an optional requirement. by default False
Source code in echo_energycalc/calculation_requirement_object_attributes.py
def __init__(self, attributes: dict[str, list[str]], optional: bool = False) -> None:
"""
Constructor of the RequiredObjectAttributes class.
This will check the performance database for the existence of the required object attributes for the wanted objects.
Parameters
----------
attributes : dict[str, list[str]]
Object attributes that are required for the calculation.
Should be in the format {object_name: [attribute_name, ...], ...}.
optional : bool, optional
Set to True if this is an optional requirement. by default False
"""
super().__init__(optional)
# check if attributes is a dict with str keys and list of str values
if not isinstance(attributes, dict):
raise TypeError(f"attributes must be a dict, not {type(attributes)}")
if not all(isinstance(key, str) for key in attributes):
raise TypeError(f"all attributes keys must be str, not {[type(key) for key in attributes]}")
if not all(isinstance(value, list) for value in attributes.values()):
raise TypeError(f"all attributes values must be list, not {[type(value) for value in attributes.values()]}")
if not all(all(isinstance(item, str) for item in value) for value in attributes.values()):
raise TypeError(
f"all values of the attributes argument must be list of str, not {[type(item) for value in attributes.values() for item in value]}",
)
self._attributes = attributes
attributes
property
¶
Object attributes that are required for the calculation.
Returns:
-
dict[str, list[str]]–Object attributes that are required for the calculation in the format {object_name: [attribute_name, ...], ...}.
checked
property
¶
Attribute that defines if the requirement has been checked. It's value will start as False and will be set to True after the check method is called.
Returns:
-
bool–True if the requirement has been checked.
data
property
¶
Object attributes that are required for the calculation.
Returns:
-
dict[str, dict[str, Any]]–Object attributes that are required for the calculation in the format {object_name: {attribute_name: attribute_value, ...}, ...}.
optional
property
¶
Attribute that defines if the requirement is optional.
If optional is True, the requirement is only validated to check if it could exist, not if it is actually present. This is useful for requirements that are not necessary for all calculations, but are useful for some of them.
Returns:
-
bool–True if the requirement is optional.
check()
¶
Method used to check if all required object_attributes are present in the database for each object.
This will raise an error if any of the required attributes are missing.
This method will also act like the "get_data" method because it will need to get the attributes to check if they are ok anyway, so we will store the data in the object property "data" to avoid querying the database again.
Returns:
-
bool–Returns True if all required object attributes are present in the database for each object.
Source code in echo_energycalc/calculation_requirement_object_attributes.py
def check(self) -> bool:
"""
Method used to check if all required object_attributes are present in the database for each object.
This will raise an error if any of the required attributes are missing.
This method will also act like the "get_data" method because it will need to get the attributes to check if they are ok anyway, so we will store the data in the object property "data" to avoid querying the database again.
Returns
-------
bool
Returns True if all required object attributes are present in the database for each object.
"""
# initializing self._data as an empty dict
self._data = {}
# iterating each object and checking if all attributes are present
for object_name, req_attributes in self.attributes.items():
# getting existing attributes
exist_attributes = self._perfdb.objects.instances.get(
object_names=[object_name],
get_attributes=True,
attribute_names=req_attributes,
)
if object_name not in exist_attributes:
if self.optional:
continue
raise ValueError(f"Object {object_name} does not exist in performance_db")
exist_attributes = exist_attributes[object_name]
if not exist_attributes:
if self.optional:
continue
raise ValueError(f"Object {object_name} does not have attributes {req_attributes}")
# checking if all required attributes are present
missing_attributes = set(req_attributes) - set(exist_attributes.keys())
if len(missing_attributes) > 0 and not self.optional:
raise ValueError(f"Attributes {missing_attributes} do not exist for object {object_name}")
# filtering existing attributes to only include the required attributes
exist_attributes = {attr: exist_attributes[attr] for attr in req_attributes if attr in exist_attributes}
# saving attributes to self._data
self._data[object_name] = copy.deepcopy(exist_attributes)
self._checked = True
return True
get_data(**kwargs)
¶
Method used to get the required object attributes from performance database.
This will not do anything other than call the check() method because the check() method already gets the data.
Returns:
-
dict[str, dict[str, Any]]–Dict in the format {object_name: {attribute_name: attribute_value, ...}, ...}.
Source code in echo_energycalc/calculation_requirement_object_attributes.py
def get_data(self, **kwargs) -> dict[str, dict[str, Any]]: # noqa: ARG002
"""
Method used to get the required object attributes from performance database.
This will not do anything other than call the check() method because the check() method already gets the data.
Returns
-------
dict[str, dict[str, Any]]
Dict in the format {object_name: {attribute_name: attribute_value, ...}, ...}.
"""
# in case check() was not called before get_data(), calling it now
if not self._checked:
self.check()
# nothing else needs to be done here because check() already gets the data
return self.data