From 2e03c797cf7b28a9cb1ba4d48352ecd43428801d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 28 Nov 2024 09:37:15 +0100 Subject: [PATCH 1/2] adds test with expected output --- .../test_data_service_observer.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/data_service/test_data_service_observer.py b/tests/data_service/test_data_service_observer.py index 347ff542..4880aa8c 100644 --- a/tests/data_service/test_data_service_observer.py +++ b/tests/data_service/test_data_service_observer.py @@ -184,3 +184,22 @@ def __init__(self) -> None: ) assert service_instance.service_dict["one"].prop == 12.0 assert "'service_dict[\"one\"].prop' changed to '12.0'" in caplog.text + + +def test_read_only_dict_property(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(pydase.DataService): + def __init__(self) -> None: + super().__init__() + self._dict_attr = {"dotted.key": 1.0} + + @property + def dict_attr(self) -> dict[str, Any]: + return self._dict_attr + + service_instance = MyObservable() + state_manager = StateManager(service=service_instance) + DataServiceObserver(state_manager) + + service_instance._dict_attr["dotted.key"] = 2.0 + + assert "'dict_attr[\"dotted.key\"]' changed to '2.0'" in caplog.text From d28a09de71b13c96d360c0035889a2a5c4769b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Thu, 28 Nov 2024 09:37:48 +0100 Subject: [PATCH 2/2] fix: updates how changed_props are computed This might come with performance hit. Dig deeper! --- src/pydase/data_service/data_service_observer.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pydase/data_service/data_service_observer.py b/src/pydase/data_service/data_service_observer.py index 75a78b5a..6da9851d 100644 --- a/src/pydase/data_service/data_service_observer.py +++ b/src/pydase/data_service/data_service_observer.py @@ -102,8 +102,9 @@ def _update_cache_value( ) def _notify_dependent_property_changes(self, changed_attr_path: str) -> None: - normalized_attr_path = normalize_full_access_path_string(changed_attr_path) - changed_props = self.property_deps_dict.get(normalized_attr_path, []) + changed_props = self._get_changed_props_from_changed_attr_path( + changed_attr_path + ) for prop in changed_props: # only notify about changing attribute if it is not currently being # "changed" e.g. when calling the getter of a property within another @@ -114,6 +115,17 @@ def _notify_dependent_property_changes(self, changed_attr_path: str) -> None: get_object_attr_from_path(self.observable, prop), ) + def _get_changed_props_from_changed_attr_path( + self, changed_attr_path: str + ) -> list[str]: + changed_props: list[str] = [] + normalized_attr_path = normalize_full_access_path_string(changed_attr_path) + for key, value in self.property_deps_dict.items(): + if normalized_attr_path.startswith(key): + changed_props.extend(value) + + return changed_props + def add_notification_callback( self, callback: Callable[[str, Any, SerializedObject], None] ) -> None: