mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-22 01:00:02 +02:00
revert: moving DataServiceSerializer functionality back to
DataService
This commit is contained in:
parent
6c9a09eabc
commit
a288c35c50
@ -22,7 +22,6 @@ from pyDataInterface.utils.helpers import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .data_service_list import DataServiceList
|
from .data_service_list import DataServiceList
|
||||||
from .data_service_serializer import DataServiceSerializer
|
|
||||||
from .task_manager import TaskManager
|
from .task_manager import TaskManager
|
||||||
|
|
||||||
|
|
||||||
@ -148,6 +147,8 @@ def update_DataService_by_path(service: "DataService", data: UpdateDict) -> Any:
|
|||||||
else:
|
else:
|
||||||
set_if_differs(target_obj, attr_name, data["value"])
|
set_if_differs(target_obj, attr_name, data["value"])
|
||||||
|
|
||||||
|
|
||||||
|
class DataService(rpyc.Service, TaskManager):
|
||||||
_list_mapping: dict[int, DataServiceList] = {}
|
_list_mapping: dict[int, DataServiceList] = {}
|
||||||
"""
|
"""
|
||||||
A dictionary mapping the id of the original lists to the corresponding
|
A dictionary mapping the id of the original lists to the corresponding
|
||||||
@ -571,3 +572,138 @@ def update_DataService_by_path(service: "DataService", data: UpdateDict) -> Any:
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"Attribute {key} does not exist in the DataService instance."
|
f"Attribute {key} does not exist in the DataService instance."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def serialize(self) -> dict[str, dict[str, Any]]: # noqa
|
||||||
|
"""
|
||||||
|
Serializes the instance into a dictionary, preserving the structure of the
|
||||||
|
instance.
|
||||||
|
|
||||||
|
For each attribute, method, and property, the method includes its name, type,
|
||||||
|
value, readonly status, and documentation if any in the resulting dictionary.
|
||||||
|
Attributes and methods starting with an underscore are ignored.
|
||||||
|
|
||||||
|
For attributes, methods, and properties unique to the class (not inherited from
|
||||||
|
the base class), the method uses the format "<prefix>.<key>" for keys in the
|
||||||
|
dictionary. If no prefix is provided, the key format is simply "<key>".
|
||||||
|
|
||||||
|
For nested DataService instances, the method serializes recursively and appends
|
||||||
|
the key of the nested instance to the prefix in the format "<prefix>.<key>".
|
||||||
|
|
||||||
|
For attributes of type list, each item in the list is serialized individually.
|
||||||
|
If an item in the list is an instance of DataService, it is serialized
|
||||||
|
recursively with its key in the format "<prefix>.<key>.<item_id>", where
|
||||||
|
"item_id" is the id of the item itself.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prefix (str, optional): The prefix for each key in the serialized
|
||||||
|
dictionary. This is mainly used when this method is called recursively to
|
||||||
|
maintain the structure of nested instances.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The serialized instance.
|
||||||
|
"""
|
||||||
|
result: dict[str, dict[str, Any]] = {}
|
||||||
|
|
||||||
|
# Get the dictionary of the base class
|
||||||
|
base_set = set(type(super()).__dict__)
|
||||||
|
# Get the dictionary of the derived class
|
||||||
|
derived_set = set(type(self).__dict__)
|
||||||
|
# Get the difference between the two dictionaries
|
||||||
|
derived_only_set = derived_set - base_set
|
||||||
|
|
||||||
|
instance_dict = set(self.__dict__)
|
||||||
|
# Merge the class and instance dictionaries
|
||||||
|
merged_set = derived_only_set | instance_dict
|
||||||
|
|
||||||
|
# Iterate over attributes, properties, class attributes, and methods
|
||||||
|
for key in merged_set:
|
||||||
|
if key.startswith("_"):
|
||||||
|
continue # Skip attributes that start with underscore
|
||||||
|
|
||||||
|
# Skip keys that start with "start_" or "stop_" and end with an async method
|
||||||
|
# name
|
||||||
|
if (key.startswith("start_") or key.startswith("stop_")) and key.split(
|
||||||
|
"_", 1
|
||||||
|
)[1] in {
|
||||||
|
name
|
||||||
|
for name, _ in inspect.getmembers(
|
||||||
|
self, predicate=inspect.iscoroutinefunction
|
||||||
|
)
|
||||||
|
}:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get the value of the current attribute or method
|
||||||
|
value = getattr(self, key)
|
||||||
|
|
||||||
|
if isinstance(value, DataService):
|
||||||
|
result[key] = {
|
||||||
|
"type": type(value).__name__
|
||||||
|
if type(value).__name__ in ("NumberSlider")
|
||||||
|
else "DataService",
|
||||||
|
"value": value.serialize(),
|
||||||
|
"readonly": False,
|
||||||
|
"doc": inspect.getdoc(value),
|
||||||
|
}
|
||||||
|
elif isinstance(value, list):
|
||||||
|
result[key] = {
|
||||||
|
"type": "list",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"type": "DataService"
|
||||||
|
if isinstance(item, DataService)
|
||||||
|
and type(item).__name__ not in ("NumberSlider")
|
||||||
|
else type(item).__name__,
|
||||||
|
"value": item.serialize()
|
||||||
|
if isinstance(item, DataService)
|
||||||
|
else item,
|
||||||
|
"readonly": False,
|
||||||
|
}
|
||||||
|
for item in value
|
||||||
|
],
|
||||||
|
"readonly": False,
|
||||||
|
}
|
||||||
|
elif inspect.isfunction(value) or inspect.ismethod(value):
|
||||||
|
sig = inspect.signature(value)
|
||||||
|
parameters = {
|
||||||
|
k: v.annotation.__name__
|
||||||
|
if v.annotation is not inspect._empty
|
||||||
|
else None
|
||||||
|
for k, v in sig.parameters.items()
|
||||||
|
}
|
||||||
|
running_task_info = None
|
||||||
|
if key in self._tasks: # If there's a running task for this method
|
||||||
|
task_info = self._tasks[key]
|
||||||
|
running_task_info = task_info["kwargs"]
|
||||||
|
|
||||||
|
result[key] = {
|
||||||
|
"type": "method",
|
||||||
|
"async": asyncio.iscoroutinefunction(value),
|
||||||
|
"parameters": parameters,
|
||||||
|
"doc": inspect.getdoc(value),
|
||||||
|
"value": running_task_info,
|
||||||
|
}
|
||||||
|
elif isinstance(getattr(self.__class__, key, None), property):
|
||||||
|
prop: property = getattr(self.__class__, key)
|
||||||
|
result[key] = {
|
||||||
|
"type": type(value).__name__,
|
||||||
|
"value": value,
|
||||||
|
"readonly": prop.fset is None,
|
||||||
|
"doc": inspect.getdoc(prop),
|
||||||
|
}
|
||||||
|
elif isinstance(value, Enum):
|
||||||
|
result[key] = {
|
||||||
|
"type": "Enum",
|
||||||
|
"value": value.name,
|
||||||
|
"enum": {
|
||||||
|
name: member.value
|
||||||
|
for name, member in value.__class__.__members__.items()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
result[key] = {
|
||||||
|
"type": type(value).__name__,
|
||||||
|
"value": value,
|
||||||
|
"readonly": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
@ -1,148 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import inspect
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
from enum import Enum
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from .task_manager import TaskDict
|
|
||||||
|
|
||||||
|
|
||||||
class DataServiceSerializer:
|
|
||||||
def __init__(self, filename: str) -> None:
|
|
||||||
self._tasks: dict[str, TaskDict]
|
|
||||||
|
|
||||||
def serialize(self) -> dict[str, dict[str, Any]]: # noqa
|
|
||||||
"""
|
|
||||||
Serializes the instance into a dictionary, preserving the structure of the
|
|
||||||
instance.
|
|
||||||
|
|
||||||
For each attribute, method, and property, the method includes its name, type,
|
|
||||||
value, readonly status, and documentation if any in the resulting dictionary.
|
|
||||||
Attributes and methods starting with an underscore are ignored.
|
|
||||||
|
|
||||||
For attributes, methods, and properties unique to the class (not inherited from
|
|
||||||
the base class), the method uses the format "<prefix>.<key>" for keys in the
|
|
||||||
dictionary. If no prefix is provided, the key format is simply "<key>".
|
|
||||||
|
|
||||||
For nested DataService instances, the method serializes recursively and appends
|
|
||||||
the key of the nested instance to the prefix in the format "<prefix>.<key>".
|
|
||||||
|
|
||||||
For attributes of type list, each item in the list is serialized individually.
|
|
||||||
If an item in the list is an instance of DataService, it is serialized
|
|
||||||
recursively with its key in the format "<prefix>.<key>.<item_id>", where
|
|
||||||
"item_id" is the id of the item itself.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
prefix (str, optional): The prefix for each key in the serialized
|
|
||||||
dictionary. This is mainly used when this method is called recursively to
|
|
||||||
maintain the structure of nested instances.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: The serialized instance.
|
|
||||||
"""
|
|
||||||
result: dict[str, dict[str, Any]] = {}
|
|
||||||
|
|
||||||
# Get the dictionary of the base class
|
|
||||||
base_set = set(type(super()).__dict__)
|
|
||||||
# Get the dictionary of the derived class
|
|
||||||
derived_set = set(type(self).__dict__)
|
|
||||||
# Get the difference between the two dictionaries
|
|
||||||
derived_only_set = derived_set - base_set
|
|
||||||
|
|
||||||
instance_dict = set(self.__dict__)
|
|
||||||
# Merge the class and instance dictionaries
|
|
||||||
merged_set = derived_only_set | instance_dict
|
|
||||||
|
|
||||||
# Iterate over attributes, properties, class attributes, and methods
|
|
||||||
for key in merged_set:
|
|
||||||
if key.startswith("_"):
|
|
||||||
continue # Skip attributes that start with underscore
|
|
||||||
|
|
||||||
# Skip keys that start with "start_" or "stop_" and end with an async method
|
|
||||||
# name
|
|
||||||
if (key.startswith("start_") or key.startswith("stop_")) and key.split(
|
|
||||||
"_", 1
|
|
||||||
)[1] in {
|
|
||||||
name
|
|
||||||
for name, _ in inspect.getmembers(
|
|
||||||
self, predicate=inspect.iscoroutinefunction
|
|
||||||
)
|
|
||||||
}:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Get the value of the current attribute or method
|
|
||||||
value = getattr(self, key)
|
|
||||||
|
|
||||||
if isinstance(value, DataServiceSerializer):
|
|
||||||
result[key] = {
|
|
||||||
"type": type(value).__name__
|
|
||||||
if type(value).__name__ in ("NumberSlider")
|
|
||||||
else "DataService",
|
|
||||||
"value": value.serialize(),
|
|
||||||
"readonly": False,
|
|
||||||
"doc": inspect.getdoc(value),
|
|
||||||
}
|
|
||||||
elif isinstance(value, list):
|
|
||||||
result[key] = {
|
|
||||||
"type": "list",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"type": "DataService"
|
|
||||||
if isinstance(item, DataServiceSerializer)
|
|
||||||
and type(item).__name__ not in ("NumberSlider")
|
|
||||||
else type(item).__name__,
|
|
||||||
"value": item.serialize()
|
|
||||||
if isinstance(item, DataServiceSerializer)
|
|
||||||
else item,
|
|
||||||
"readonly": False,
|
|
||||||
}
|
|
||||||
for item in value
|
|
||||||
],
|
|
||||||
"readonly": False,
|
|
||||||
}
|
|
||||||
elif inspect.isfunction(value) or inspect.ismethod(value):
|
|
||||||
sig = inspect.signature(value)
|
|
||||||
parameters = {
|
|
||||||
k: v.annotation.__name__
|
|
||||||
if v.annotation is not inspect._empty
|
|
||||||
else None
|
|
||||||
for k, v in sig.parameters.items()
|
|
||||||
}
|
|
||||||
running_task_info = None
|
|
||||||
if key in self._tasks: # If there's a running task for this method
|
|
||||||
task_info = self._tasks[key]
|
|
||||||
running_task_info = task_info["kwargs"]
|
|
||||||
|
|
||||||
result[key] = {
|
|
||||||
"type": "method",
|
|
||||||
"async": asyncio.iscoroutinefunction(value),
|
|
||||||
"parameters": parameters,
|
|
||||||
"doc": inspect.getdoc(value),
|
|
||||||
"value": running_task_info,
|
|
||||||
}
|
|
||||||
elif isinstance(getattr(self.__class__, key, None), property):
|
|
||||||
prop: property = getattr(self.__class__, key)
|
|
||||||
result[key] = {
|
|
||||||
"type": type(value).__name__,
|
|
||||||
"value": value,
|
|
||||||
"readonly": prop.fset is None,
|
|
||||||
"doc": inspect.getdoc(prop),
|
|
||||||
}
|
|
||||||
elif isinstance(value, Enum):
|
|
||||||
result[key] = {
|
|
||||||
"type": "Enum",
|
|
||||||
"value": value.name,
|
|
||||||
"enum": {
|
|
||||||
name: member.value
|
|
||||||
for name, member in value.__class__.__members__.items()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
result[key] = {
|
|
||||||
"type": type(value).__name__,
|
|
||||||
"value": value,
|
|
||||||
"readonly": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
Loading…
x
Reference in New Issue
Block a user