From 091d80cd5b154b77a891c0b6ead88b2e1c9bb6d6 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Thu, 7 Mar 2024 12:26:43 -0300 Subject: [PATCH] Add dotdict class for accessing dictionary elements using dot notation --- src/backend/langflow/schema/__init__.py | 3 +- src/backend/langflow/schema/dotdict.py | 71 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/backend/langflow/schema/dotdict.py diff --git a/src/backend/langflow/schema/__init__.py b/src/backend/langflow/schema/__init__.py index 8cd0af848..14230578c 100644 --- a/src/backend/langflow/schema/__init__.py +++ b/src/backend/langflow/schema/__init__.py @@ -1,3 +1,4 @@ +from .dotdict import dotdict from .schema import Record -__all__ = ["Record"] +__all__ = ["Record", "dotdict"] diff --git a/src/backend/langflow/schema/dotdict.py b/src/backend/langflow/schema/dotdict.py new file mode 100644 index 000000000..f85c928bb --- /dev/null +++ b/src/backend/langflow/schema/dotdict.py @@ -0,0 +1,71 @@ +class dotdict(dict): + """ + dotdict allows accessing dictionary elements using dot notation (e.g., dict.key instead of dict['key']). + It automatically converts nested dictionaries into dotdict instances, enabling dot notation on them as well. + + Note: + - Only keys that are valid attribute names (e.g., strings that could be variable names) are accessible via dot notation. + - Keys which are not valid Python attribute names or collide with the dict method names (like 'items', 'keys') + should be accessed using the traditional dict['key'] notation. + """ + + def __getattr__(self, attr): + """ + Override dot access to behave like dictionary lookup. Automatically convert nested dicts to dotdicts. + + Args: + attr (str): Attribute to access. + + Returns: + The value associated with 'attr' in the dictionary, converted to dotdict if it is a dict. + + Raises: + AttributeError: If the attribute is not found in the dictionary. + """ + try: + value = self[attr] + if isinstance(value, dict) and not isinstance(value, dotdict): + value = dotdict(value) + self[attr] = value # Update self to nest dotdict for future accesses + return value + except KeyError: + raise AttributeError(f"'dotdict' object has no attribute '{attr}'") + + def __setattr__(self, key, value): + """ + Override attribute setting to work as dictionary item assignment. + + Args: + key (str): The key under which to store the value. + value: The value to store in the dictionary. + """ + if isinstance(value, dict) and not isinstance(value, dotdict): + value = dotdict(value) + self[key] = value + + def __delattr__(self, key): + """ + Override attribute deletion to work as dictionary item deletion. + + Args: + key (str): The key of the item to delete from the dictionary. + + Raises: + AttributeError: If the key is not found in the dictionary. + """ + try: + del self[key] + except KeyError: + raise AttributeError(f"'dotdict' object has no attribute '{key}'") + + def __missing__(self, key): + """ + Handle missing keys by returning an empty dotdict. This allows chaining access without raising KeyError. + + Args: + key: The missing key. + + Returns: + An empty dotdict instance for the given missing key. + """ + return dotdict()