fixed serialization of class deriving from class which derives from DataService

This commit is contained in:
Mose Müller 2023-12-11 17:25:03 +01:00
parent 49984b7c2e
commit 88886e3fd6
3 changed files with 52 additions and 23 deletions

View File

@ -177,19 +177,21 @@ def parse_list_attr_and_index(attr_string: str) -> tuple[str, int | None]:
return attr_name, index
def get_component_class_names() -> list[str]:
def get_component_classes() -> list[type]:
"""
Returns the names of the component classes in a list.
It takes the names from the pydase/components/__init__.py file, so this file should
always be up-to-date with the currently available components.
Returns:
list[str]: List of component class names
Returns references to the component classes in a list.
"""
import pydase.components
return pydase.components.__all__
return [
getattr(pydase.components, cls_name) for cls_name in pydase.components.__all__
]
def get_data_service_class_reference() -> Any:
import pydase.data_service.data_service
return getattr(pydase.data_service.data_service, "DataService")
def is_property_attribute(target_obj: Any, attr_name: str) -> bool:

View File

@ -8,7 +8,8 @@ import pydase.units as u
from pydase.data_service.abstract_data_service import AbstractDataService
from pydase.utils.helpers import (
get_attribute_doc,
get_component_class_names,
get_component_classes,
get_data_service_class_reference,
parse_list_attr_and_index,
)
@ -157,24 +158,26 @@ class Serializer:
def _serialize_data_service(obj: AbstractDataService) -> dict[str, Any]:
readonly = False
doc = get_attribute_doc(obj)
obj_type = type(obj).__name__
if type(obj).__name__ not in get_component_class_names():
obj_type = "DataService"
obj_type = "DataService"
# Get the dictionary of the base class
base_set = set(type(obj).__base__.__dict__)
# Get the dictionary of the derived class
derived_set = set(type(obj).__dict__)
# Get the difference between the two dictionaries
derived_only_set = derived_set - base_set
# Get component base class if any
component_base_cls = next(
(cls for cls in get_component_classes() if isinstance(obj, cls)), None
)
if component_base_cls:
obj_type = component_base_cls.__name__
# Get the set of DataService class attributes
data_service_attr_set = set(dir(get_data_service_class_reference()))
# Get the set of the object attributes
obj_attr_set = set(dir(obj))
# Get the difference between the two sets
derived_only_attr_set = obj_attr_set - data_service_attr_set
instance_dict = set(obj.__dict__)
# Merge the class and instance dictionaries
merged_set = derived_only_set | instance_dict
value = {}
# Iterate over attributes, properties, class attributes, and methods
for key in sorted(merged_set):
for key in sorted(derived_only_attr_set):
if key.startswith("_"):
continue # Skip attributes that start with underscore

View File

@ -294,6 +294,30 @@ def test_dict_serialization() -> None:
}
def test_derived_data_service_serialization() -> None:
class BaseService(pydase.DataService):
class_attr = 1337
def __init__(self) -> None:
super().__init__()
self._name = "Service"
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, value: str) -> None:
self._name = value
class DerivedService(BaseService):
...
base_instance = BaseService()
service_instance = DerivedService()
assert service_instance.serialize() == base_instance.serialize()
@pytest.fixture
def setup_dict():
class MySubclass(pydase.DataService):