diff --git a/wobbl_tools/data_file.py b/wobbl_tools/data_file.py index 6a5bc08..8c5cb61 100644 --- a/wobbl_tools/data_file.py +++ b/wobbl_tools/data_file.py @@ -8,13 +8,34 @@ import os import json -def load_dataclass_json(dataclass, file_path: str, builtin_save: bool=True): +def _on_attribute_change(self, key, value): + # call function without automatically passing "self" as argument using __func__ - + # and if it returns "True", set the attribute + + if key == "attribute_change_event" or self.attribute_change_event.__func__(self.app, key, value): + self.__dict__[key] = value + + +def _set_attribute_change_event(self, event): + self.attribute_change_event = event + + +def load_dataclass_json( + dataclass, + file_path: str, + app: any=None, + builtin_save: bool=True, + builtin_change_event: bool=True +): """ Loads a dataclass instance from a json file. :param dataclass: The dataclass from which the instance will be created. :param str file_path: The path to the json file from which the data gets loaded. + :param app: This is necessary if you want the dataclass to execute a function on attribute change. :param bool builtin_save: If True, you can simply call instance.save(file_path) to store the data. + :param bool builtin_change_event: If True, the returned instance will call the instance.attribute_change_event + on the specified app. :return: An instance of the dataclass containing the data from the json file. """ @@ -28,9 +49,19 @@ def load_dataclass_json(dataclass, file_path: str, builtin_save: bool=True): instance = dataclass(**class_dict) + if not app is None: + instance.app = app + if builtin_save: # add save method so that we can easily do "instance.save()" dataclass.save = save_dataclass_json + if builtin_change_event: + if app is None: + raise TypeError("You need to specify the app, else this won't work.") + + dataclass.set_attribute_change_event = _set_attribute_change_event + dataclass.__setattr__ = _on_attribute_change + return instance @@ -42,6 +73,9 @@ def save_dataclass_json(class_instance, file_path: str, indent: None | int | str :param None|int|str indent: The indentation level for cleaner output. """ + if hasattr(class_instance, "app"): # remove app because it can't and doesn't need to be stored in the file + del class_instance.app + class_dict = class_instance.__dict__ class_dict = dict(filter(lambda pair: not callable(pair[1]), class_dict.items())) # filter out functions