feat(nodes): add basic dictionary manipulation nodes

Signed-off-by: bigcat88 <bigcat88@icloud.com>
This commit is contained in:
bigcat88 2025-07-06 12:29:22 +03:00
parent ee615ac269
commit 597fe7fd07
No known key found for this signature in database
GPG Key ID: 1F0BF0EC3CF22721
3 changed files with 127 additions and 0 deletions

View File

@ -21,6 +21,7 @@ class IO(StrEnum):
"""
STRING = "STRING"
DICT = "DICT"
IMAGE = "IMAGE"
MASK = "MASK"
LATENT = "LATENT"

125
comfy_extras/nodes_dict.py Normal file
View File

@ -0,0 +1,125 @@
import contextlib
import json
from typing import Optional
from comfy.comfy_types.node_typing import IO
class DictionaryNew:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"key_1": (IO.STRING, {"default": "", "multiline": False}),
"value_1": (IO.STRING, {"default": "", "multiline": False}),
},
"optional": {
"key_2": (IO.STRING, {"default": "", "multiline": False}),
"value_2": (IO.STRING, {"default": "", "multiline": False}),
"key_3": (IO.STRING, {"default": "", "multiline": False}),
"value_3": (IO.STRING, {"default": "", "multiline": False}),
"key_4": (IO.STRING, {"default": "", "multiline": False}),
"value_4": (IO.STRING, {"default": "", "multiline": False}),
},
}
RETURN_TYPES = (IO.DICT,)
FUNCTION = "execute"
CATEGORY = "utils/dict"
@classmethod
def execute(
cls, key_1: str, value_1: str, key_2: str, value_2: str, key_3: str, value_3: str, key_4: str, value_4: str,
):
return (
{
k: v
for k, v in [
(key_1, value_1),
(key_2, value_2),
(key_3, value_3),
(key_4, value_4),
]
if k
},
)
class DictionaryConvert:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {"dictionary_text": (IO.STRING, {"forceInput": True})},
"optional": {"fallback_dict": (IO.DICT,)},
}
DESCRIPTION = "Parses a string into a dictionary"
RETURN_TYPES = (IO.DICT,)
FUNCTION = "execute"
CATEGORY = "utils/dict"
@classmethod
def execute(cls, dictionary_text: str, fallback_dict: Optional[dict] = None):
with contextlib.suppress(Exception):
return json.loads(dictionary_text),
return (fallback_dict,) if fallback_dict is not None else ({},)
class DictionaryGet:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"dictionary": (IO.DICT,),
"key": (IO.STRING, {"default": "", "multiline": False}),
},
"optional": {
"default_value": (IO.STRING, {"default": "", "multiline": False}),
},
}
RETURN_TYPES = (IO.DICT,)
FUNCTION = "execute"
CATEGORY = "utils/dict"
@classmethod
def execute(cls, dictionary: dict, key: str, default_value=""):
return (str(dictionary.get(key, default_value)),)
class DictionaryUpdate:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"dict_1": (IO.DICT,),
"dict_2": (IO.DICT,),
},
"optional": {
"dict_3": (IO.DICT,),
"dict_4": (IO.DICT,),
},
}
RETURN_TYPES = (IO.DICT,)
FUNCTION = "execute"
CATEGORY = "utils/dict"
@classmethod
def execute(cls, dict_1: dict, dict_2: dict, dict_3: Optional[dict] = None, dict_4: Optional[dict] = None):
return ({**dict_1, **dict_2, **(dict_3 or {}), **(dict_4 or {})},)
NODE_CLASS_MAPPINGS = {
"DictionaryNew": DictionaryNew,
"DictionaryConvert": DictionaryConvert,
"DictionaryGet": DictionaryGet,
"DictionaryUpdate": DictionaryUpdate,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"DictionaryNew": "Dictionary New",
"DictionaryConvert": "Convert to Dictionary",
"DictionaryGet": "Dictionary Get",
"DictionaryUpdate": "Dictionary Update",
}

View File

@ -2281,6 +2281,7 @@ def init_builtin_extra_nodes():
"nodes_preview_any.py",
"nodes_ace.py",
"nodes_string.py",
"nodes_dict.py",
"nodes_camera_trajectory.py",
"nodes_edit_model.py",
"nodes_tcfg.py"