From 2e683df6ef5a162d80cbfc5f201c9a0c482f1a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Wed, 2 Aug 2023 12:06:22 +0200 Subject: [PATCH] feat: only updating the class attributes with the values from the JSON if the types are the same --- .../data_service/data_service.py | 28 +++++++++------ src/pyDataInterface/utils/helpers.py | 35 +++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/pyDataInterface/data_service/data_service.py b/src/pyDataInterface/data_service/data_service.py index 8efb043..faadf66 100644 --- a/src/pyDataInterface/data_service/data_service.py +++ b/src/pyDataInterface/data_service/data_service.py @@ -16,7 +16,7 @@ from pyDataInterface.utils.helpers import ( get_nested_value_by_path_and_key, get_object_attr_from_path, parse_list_attr_and_index, - set_if_differs, + update_value_if_changed, ) from pyDataInterface.utils.warnings import ( 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: # 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): value = get_nested_value_by_path_and_key(json_dict, path=path) value_type = get_nested_value_by_path_and_key( 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 - parts = path.split(".") - attr_name = parts[-1] - - self.update_DataService_attribute(parts[:-1], attr_name, value, value_type) + self.update_DataService_attribute(parts[:-1], attr_name, value) + else: + logger.info( + f'Attribute type of "{path}" changed from "{value_type}" to ' + f'"{class_value_type}". Ignoring value from JSON file...' + ) def __setattr__(self, __name: str, __value: Any) -> None: current_value = getattr(self, __name, None) @@ -607,7 +616,6 @@ class DataService(rpyc.Service, TaskManager): path_list: list[str], attr_name: str, value: Any, - attr_type: Optional[str] = None, ) -> None: # 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) @@ -622,13 +630,13 @@ class DataService(rpyc.Service, TaskManager): # Set the attribute at the terminal point of the path 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: - set_if_differs(attr, index, value) + update_value_if_changed(attr, index, value) elif isinstance(attr, DataService) and isinstance(value, dict): for key, v in value.items(): self.update_DataService_attribute([*path_list, attr_name], key, v) elif callable(attr): return process_callable_attribute(attr, value["args"]) else: - set_if_differs(target_obj, attr_name, value) + update_value_if_changed(target_obj, attr_name, value) diff --git a/src/pyDataInterface/utils/helpers.py b/src/pyDataInterface/utils/helpers.py index 645e323..37506ff 100644 --- a/src/pyDataInterface/utils/helpers.py +++ b/src/pyDataInterface/utils/helpers.py @@ -236,24 +236,39 @@ def convert_arguments_to_hinted_types( 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, - but only if the current value of the attribute or the list element differs from the - new value. + Updates the value of an attribute or a list element on a target object if the new + value differs from the current one. + + 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: - target: The object that has the attribute or the list. - attr_name: The name of the attribute or the index of the list element. - new_value: The new value for the attribute or the list element. + target (Any): + The target object that has the attribute or the list. + 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): - # Case for a list if target[attr_name] != new_value: target[attr_name] = new_value elif isinstance(attr_name, str): - # Case for an attribute - if getattr(target, attr_name) != new_value: + # Get the current value of the attribute + 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) else: logger.error(f"Incompatible arguments: {target}, {attr_name}.")