pydase/src/pyDataInterface/utils/apply_update_to_data_service.py
2023-08-02 12:06:21 +02:00

68 lines
2.2 KiB
Python

import re
from enum import Enum
from typing import Any, Optional, TypedDict, get_type_hints
from loguru import logger
from pyDataInterface.data_service.data_service import DataService
from .helpers import get_attr_from_path
class UpdateDictionary(TypedDict):
name: str
"""Name of the attribute."""
parent_path: str
"""Full access path of the attribute."""
value: Any
"""New value of the attribute."""
def apply_updates_to_data_service(service: Any, data: UpdateDictionary) -> Any:
parent_path = data["parent_path"].split(".")
attr_name = data["name"]
# Traverse the object tree according to parent_path
target_obj = get_attr_from_path(service, parent_path)
# Check if attr_name contains an index for a list item
index: Optional[int] = None
if re.search(r"\[.*\]", attr_name):
attr_name, index_str = attr_name.split("[")
try:
index = int(
index_str.replace("]", "")
) # Remove closing bracket and convert to int
except ValueError:
logger.error(f"Invalid list index: {index_str}")
return
attr = getattr(target_obj, attr_name)
if isinstance(attr, DataService):
attr.apply_updates(data["value"])
elif isinstance(attr, Enum):
setattr(service, data["name"], attr.__class__[data["value"]["value"]])
elif callable(attr):
args: dict[str, Any] = data["value"]["args"]
type_hints = get_type_hints(attr)
# Convert arguments to their hinted types
for arg_name, arg_value in args.items():
if arg_name in type_hints:
arg_type = type_hints[arg_name]
if isinstance(arg_type, type):
# Attempt to convert the argument to its hinted type
try:
args[arg_name] = arg_type(arg_value)
except ValueError:
msg = f"Failed to convert argument '{arg_name}' to type {arg_type.__name__}"
logger.error(msg)
return msg
return attr(**args)
elif isinstance(attr, list):
attr[index] = data["value"]
else:
setattr(target_obj, attr_name, data["value"])