feat: only updating the class attributes with the values from the JSON if the types are the same

This commit is contained in:
Mose Müller 2023-08-02 12:06:22 +02:00
parent 3e72e25f9f
commit 2e683df6ef
2 changed files with 43 additions and 20 deletions

View File

@ -16,7 +16,7 @@ from pyDataInterface.utils.helpers import (
get_nested_value_by_path_and_key, get_nested_value_by_path_and_key,
get_object_attr_from_path, get_object_attr_from_path,
parse_list_attr_and_index, parse_list_attr_and_index,
set_if_differs, update_value_if_changed,
) )
from pyDataInterface.utils.warnings import ( from pyDataInterface.utils.warnings import (
warn_if_instance_class_does_not_inherit_from_DataService, warn_if_instance_class_does_not_inherit_from_DataService,
@ -110,17 +110,26 @@ class DataService(rpyc.Service, TaskManager):
def load_DataService_from_JSON(self, json_dict: dict[str, Any]) -> None: def load_DataService_from_JSON(self, json_dict: dict[str, Any]) -> None:
# Traverse the serialized representation and set the attributes of the class # Traverse the serialized representation and set the attributes of the class
serialized_class = self.serialize()
for path in generate_paths_from_DataService_dict(json_dict): for path in generate_paths_from_DataService_dict(json_dict):
value = get_nested_value_by_path_and_key(json_dict, path=path) value = get_nested_value_by_path_and_key(json_dict, path=path)
value_type = get_nested_value_by_path_and_key( value_type = get_nested_value_by_path_and_key(
json_dict, path=path, key="type" json_dict, path=path, key="type"
) )
class_value_type = get_nested_value_by_path_and_key(
serialized_class, path=path, key="type"
)
if class_value_type == value_type:
# Split the path into parts
parts = path.split(".")
attr_name = parts[-1]
# Split the path into parts self.update_DataService_attribute(parts[:-1], attr_name, value)
parts = path.split(".") else:
attr_name = parts[-1] logger.info(
f'Attribute type of "{path}" changed from "{value_type}" to '
self.update_DataService_attribute(parts[:-1], attr_name, value, value_type) f'"{class_value_type}". Ignoring value from JSON file...'
)
def __setattr__(self, __name: str, __value: Any) -> None: def __setattr__(self, __name: str, __value: Any) -> None:
current_value = getattr(self, __name, None) current_value = getattr(self, __name, None)
@ -607,7 +616,6 @@ class DataService(rpyc.Service, TaskManager):
path_list: list[str], path_list: list[str],
attr_name: str, attr_name: str,
value: Any, value: Any,
attr_type: Optional[str] = None,
) -> None: ) -> None:
# If attr_name corresponds to a list entry, extract the attr_name and the index # If attr_name corresponds to a list entry, extract the attr_name and the index
attr_name, index = parse_list_attr_and_index(attr_name) attr_name, index = parse_list_attr_and_index(attr_name)
@ -622,13 +630,13 @@ class DataService(rpyc.Service, TaskManager):
# Set the attribute at the terminal point of the path # Set the attribute at the terminal point of the path
if isinstance(attr, Enum): if isinstance(attr, Enum):
set_if_differs(target_obj, attr_name, attr.__class__[value]) update_value_if_changed(target_obj, attr_name, attr.__class__[value])
elif isinstance(attr, list) and index is not None: elif isinstance(attr, list) and index is not None:
set_if_differs(attr, index, value) update_value_if_changed(attr, index, value)
elif isinstance(attr, DataService) and isinstance(value, dict): elif isinstance(attr, DataService) and isinstance(value, dict):
for key, v in value.items(): for key, v in value.items():
self.update_DataService_attribute([*path_list, attr_name], key, v) self.update_DataService_attribute([*path_list, attr_name], key, v)
elif callable(attr): elif callable(attr):
return process_callable_attribute(attr, value["args"]) return process_callable_attribute(attr, value["args"])
else: else:
set_if_differs(target_obj, attr_name, value) update_value_if_changed(target_obj, attr_name, value)

View File

@ -236,24 +236,39 @@ def convert_arguments_to_hinted_types(
return args return args
def set_if_differs(target: Any, attr_name: str | int, new_value: Any) -> None: def update_value_if_changed(target: Any, attr_name: str | int, new_value: Any) -> None:
""" """
Set the value of an attribute or a list element on a target object to a new value, Updates the value of an attribute or a list element on a target object if the new
but only if the current value of the attribute or the list element differs from the value differs from the current one.
new value.
This function supports updating both attributes of an object and elements of a list.
- For objects, the function first checks the current value of the attribute. If the
current value differs from the new value, the function updates the attribute.
- For lists, the function checks the current value at the specified index. If the
current value differs from the new value, the function updates the list element
at the given index.
Args: Args:
target: The object that has the attribute or the list. target (Any):
attr_name: The name of the attribute or the index of the list element. The target object that has the attribute or the list.
new_value: The new value for the attribute or the list element. attr_name (str | int):
The name of the attribute or the index of the list element.
new_value (Any):
The new value for the attribute or the list element.
""" """
if isinstance(target, list) and isinstance(attr_name, int): if isinstance(target, list) and isinstance(attr_name, int):
# Case for a list
if target[attr_name] != new_value: if target[attr_name] != new_value:
target[attr_name] = new_value target[attr_name] = new_value
elif isinstance(attr_name, str): elif isinstance(attr_name, str):
# Case for an attribute # Get the current value of the attribute
if getattr(target, attr_name) != new_value: attr_value = getattr(target, attr_name)
# If the type matches and the current value is different from the new value,
# update the attribute.
if attr_value != new_value:
setattr(target, attr_name, new_value) setattr(target, attr_name, new_value)
else: else:
logger.error(f"Incompatible arguments: {target}, {attr_name}.") logger.error(f"Incompatible arguments: {target}, {attr_name}.")