From 32e2a8a4d1ffd76ceff9a050064c6c49e175a0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Mon, 22 Apr 2024 19:10:34 +0200 Subject: [PATCH] replaces parse_list_attr_and_index with parse_keyed_attribute to support dictionaries --- src/pydase/data_service/state_manager.py | 4 +- src/pydase/utils/helpers.py | 50 ++++++++++++-------- src/pydase/utils/serialization/serializer.py | 4 +- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/pydase/data_service/state_manager.py b/src/pydase/data_service/state_manager.py index cd59bf5..67fef43 100644 --- a/src/pydase/data_service/state_manager.py +++ b/src/pydase/data_service/state_manager.py @@ -9,7 +9,7 @@ from pydase.data_service.data_service_cache import DataServiceCache from pydase.utils.helpers import ( get_object_attr_from_path, is_property_attribute, - parse_list_attr_and_index, + parse_keyed_attribute, ) from pydase.utils.serialization.deserializer import loads from pydase.utils.serialization.serializer import ( @@ -240,7 +240,7 @@ class StateManager: # If attr_name corresponds to a list entry, extract the attr_name and the # index - attr_name, index = parse_list_attr_and_index(attr_name) + attr_name, index = parse_keyed_attribute(attr_name) # Update path to reflect the attribute without list indices path = f"{parent_path}.{attr_name}" if parent_path != "" else attr_name diff --git a/src/pydase/utils/helpers.py b/src/pydase/utils/helpers.py index 638c45c..f68f995 100644 --- a/src/pydase/utils/helpers.py +++ b/src/pydase/utils/helpers.py @@ -101,39 +101,51 @@ def update_value_if_changed( logger.error("Incompatible arguments: %s, %s.", target, attr_name_or_index) -def parse_list_attr_and_index(attr_string: str) -> tuple[str, int | None]: +def parse_keyed_attribute(attr_string: str) -> tuple[str, str | float | int | None]: """ - Parses an attribute string and extracts a potential list attribute name and its - index. - Logs an error if the index is not a valid digit. + Parses an attribute string and extracts a potential attribute name and its key. + The key can be a string (for dictionary keys) or an integer (for list indices). Args: attr_string (str): The attribute string to parse. Can be a regular attribute name (e.g., - 'attr_name') or a list attribute with an index (e.g., 'list_attr[2]'). + 'attr_name'), a list attribute with an index (e.g., 'list_attr[2]'), or + a dictionary attribute with a key (e.g., 'dict_attr["key"]' or + 'dict_attr[0]'). Returns: - tuple[str, Optional[int]]: - A tuple containing the attribute name as a string and the index as an - integer if present, otherwise None. + tuple[str, str | float | int | None]: + A tuple containing the attribute name and the key as either a string, + an integer if it's a digit, or None if no key is present. Examples: - >>> parse_attribute_and_index('list_attr[2]') - ('list_attr', 2) - >>> parse_attribute_and_index('attr_name') - ('attr_name', None) + ```python + >>> parse_keyed_attribute('list_attr[2]') + ("list_attr", 2) + >>> parse_keyed_attribute('attr_name') + ("attr_name", None) + >>> parse_keyed_attribute('dict_attr["key"]') + ("dict_attr", 'key') + >>> parse_keyed_attribute("dict_attr["0"]") + ("dict_attr", "0") + >>> parse_keyed_attribute("dict_attr[0]") + ("dict_attr", 0) + ``` """ - index = None + key = None attr_name = attr_string if "[" in attr_string and attr_string.endswith("]"): - attr_name, index_part = attr_string.split("[", 1) - index_part = index_part.rstrip("]") - if index_part.isdigit(): - index = int(index_part) + attr_name, key_part = attr_string.split("[", 1) + key_part = key_part.rstrip("]") + # Remove quotes if present (supports both single and double quotes) + if key_part.startswith('"') and key_part.endswith('"'): + key = key_part[1:-1] + elif "." in key_part: + key = float(key_part) else: - logger.error("Invalid index format in key: %s", attr_name) - return attr_name, index + key = int(key_part) + return attr_name, key def get_component_classes() -> list[type]: diff --git a/src/pydase/utils/serialization/serializer.py b/src/pydase/utils/serialization/serializer.py index ecdd425..33f133e 100644 --- a/src/pydase/utils/serialization/serializer.py +++ b/src/pydase/utils/serialization/serializer.py @@ -13,7 +13,7 @@ from pydase.utils.helpers import ( get_attribute_doc, get_component_classes, get_data_service_class_reference, - parse_list_attr_and_index, + parse_keyed_attribute, render_in_frontend, ) from pydase.utils.serialization.types import ( @@ -402,7 +402,7 @@ def get_next_level_dict_by_key( SerializationValueError: If the expected nested structure is not a dictionary. """ # Check if the key contains an index part like 'attr_name[]' - attr_name, index = parse_list_attr_and_index(attr_name) + attr_name, index = parse_keyed_attribute(attr_name) try: if index is not None: