Merge pull request #30 from tiqi-group/29-protected-lists-crash-pydase

fix: removes notification for updating protected lists
This commit is contained in:
Mose Müller 2023-10-12 14:25:23 +02:00 committed by GitHub
commit 4abea8785c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 5 deletions

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "pydase"
version = "0.2.0"
version = "0.2.1"
description = "A flexible and robust Python library for creating, managing, and interacting with data services, with built-in support for web and RPC servers, and customizable features for diverse use cases."
authors = ["Mose Mueller <mosmuell@ethz.ch>"]
readme = "README.md"

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import inspect
from collections.abc import Callable
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, cast
from loguru import logger
@ -55,9 +55,10 @@ class CallbackManager:
self, obj: "AbstractDataService", parent_path: str
) -> None:
"""
This method ensures that notifications are emitted whenever a list attribute of
a DataService instance changes. These notifications pertain solely to the list
item changes, not to changes in attributes of objects within the list.
This method ensures that notifications are emitted whenever a public list
attribute of a DataService instance changes. These notifications pertain solely
to the list item changes, not to changes in attributes of objects within the
list.
The method works by converting all list attributes (both at the class and
instance levels) into DataServiceList objects. Each DataServiceList is then
@ -101,6 +102,8 @@ class CallbackManager:
value=value,
)
if self.service == self.service.__root__
# Skip private and protected lists
and not cast(str, attr_name).startswith("_")
else None
)
@ -109,9 +112,12 @@ class CallbackManager:
attr_value.add_callback(callback)
continue
if id(attr_value) in self._list_mapping:
# If the list `attr_value` was already referenced somewhere else
notifying_list = self._list_mapping[id(attr_value)]
notifying_list.add_callback(callback)
else:
# convert the builtin list into a DataServiceList and add the
# callback
notifying_list = DataServiceList(attr_value, callback=[callback])
self._list_mapping[id(attr_value)] = notifying_list

View File

@ -99,3 +99,29 @@ def test_nested_reused_instance_list_attribute(capsys: CaptureFixture) -> None:
)
actual_output = sorted(captured.out.strip().split("\n"))
assert actual_output == expected_output
def test_protected_list_attribute(capsys: CaptureFixture) -> None:
"""Changing protected lists should not emit notifications for the lists themselves, but
still for all properties depending on them.
"""
class ServiceClass(DataService):
_attr = [0, 1]
@property
def list_dependend_property(self) -> int:
return self._attr[0]
service_instance = ServiceClass()
service_instance._attr[0] = 1337
captured = capsys.readouterr()
expected_output = sorted(
[
"ServiceClass.list_dependend_property = 1337",
]
)
actual_output = sorted(captured.out.strip().split("\n")) # type: ignore
assert actual_output == expected_output