add create DICT and LIST from JSON string
This commit is contained in:
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Add "create DICT from JSON string" and "create LIST from JSON string" nodes to
|
||||
parse a multiline JSON object/array into a DICT/LIST
|
||||
|
||||
## [1.8.1] - 2026-09-06
|
||||
|
||||
- Add optional additional input for image saving to also save the prompt when provided
|
||||
|
||||
@@ -71,7 +71,7 @@ ComfyUI list manipulation nodes (for processing individual items):
|
||||
|
||||
Dictionary manipulation nodes:
|
||||
|
||||
- **Creation**: create (generic and type-specific), create from items, create from lists, fromkeys
|
||||
- **Creation**: create (generic and type-specific), create from JSON string, create from items, create from lists, fromkeys
|
||||
- **Access**: get, get_multiple, keys, values, items
|
||||
- **Modification**: set, update, setdefault, merge
|
||||
- **Removal**: pop, popitem, pop random, remove
|
||||
@@ -102,7 +102,7 @@ Integer operation nodes:
|
||||
|
||||
Python list manipulation nodes (as a single variable):
|
||||
|
||||
- **Creation**: create LIST (generic and type-specific versions)
|
||||
- **Creation**: create LIST (generic and type-specific versions), create LIST from JSON string
|
||||
- **Modification**: append, extend, insert, remove, pop, pop random, set_item, shuffle
|
||||
- **Access**: get_item, first, last, slice, index, contains
|
||||
- **Information**: length, count
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import (
|
||||
)
|
||||
|
||||
from inspect import cleandoc
|
||||
import json
|
||||
import random
|
||||
|
||||
try:
|
||||
@@ -1067,12 +1068,49 @@ class DictValues(ComfyNodeABC):
|
||||
return (list(input_dict.values()),)
|
||||
|
||||
|
||||
class DictCreateFromJSONString(ComfyNodeABC):
|
||||
"""
|
||||
Creates a DICT from a JSON object string.
|
||||
|
||||
This node takes a STRING that must contain a valid JSON object and
|
||||
parses it into a DICT. The input must be a JSON object (enclosed in curly
|
||||
braces); otherwise a clear error is raised.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_string": (IO.STRING, {"default": "{}", "widgetType": "STRING", "tooltip": "STRING containing a JSON object to parse, e.g. {\"a\": 1}."}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("DICT",)
|
||||
RETURN_NAMES = ("dict",)
|
||||
OUTPUT_TOOLTIPS = ("The DICT parsed from the JSON object string.",)
|
||||
CATEGORY = "Basic/DICT"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "create_from_json"
|
||||
|
||||
def create_from_json(self, json_string: str) -> tuple[dict]:
|
||||
try:
|
||||
result = json.loads(json_string)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON in input string: {e}")
|
||||
if not isinstance(result, dict):
|
||||
raise ValueError(
|
||||
"The JSON string must be a JSON object (enclosed in curly braces), "
|
||||
f"not {type(result).__name__}."
|
||||
)
|
||||
return (result,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"Basic data handling: DictCreate": DictCreate,
|
||||
"Basic data handling: DictCreateFromBoolean": DictCreateFromBoolean,
|
||||
"Basic data handling: DictCreateFromFloat": DictCreateFromFloat,
|
||||
"Basic data handling: DictCreateFromInt": DictCreateFromInt,
|
||||
"Basic data handling: DictCreateFromString": DictCreateFromString,
|
||||
"Basic data handling: DictCreateFromJSONString": DictCreateFromJSONString,
|
||||
"Basic data handling: DictCreateFromItemsDataList": DictCreateFromItemsDataList,
|
||||
"Basic data handling: DictCreateFromItemsList": DictCreateFromItemsList,
|
||||
"Basic data handling: DictCreateFromLists": DictCreateFromLists,
|
||||
@@ -1105,6 +1143,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"Basic data handling: DictCreateFromFloat": "create DICT from FLOATs",
|
||||
"Basic data handling: DictCreateFromInt": "create DICT from INTs",
|
||||
"Basic data handling: DictCreateFromString": "create DICT from STRINGs",
|
||||
"Basic data handling: DictCreateFromJSONString": "create DICT from JSON string",
|
||||
"Basic data handling: DictCreateFromItemsDataList": "create from items (data list)",
|
||||
"Basic data handling: DictCreateFromItemsList": "create from items (LIST)",
|
||||
"Basic data handling: DictCreateFromLists": "create from LISTs",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from typing import Any
|
||||
from inspect import cleandoc
|
||||
import json
|
||||
|
||||
try:
|
||||
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
|
||||
@@ -972,12 +973,49 @@ class ListToSet(ComfyNodeABC):
|
||||
return (set(list),)
|
||||
|
||||
|
||||
class ListCreateFromJSONString(ComfyNodeABC):
|
||||
"""
|
||||
Creates a LIST from a JSON array string.
|
||||
|
||||
This node takes a STRING that must contain a valid JSON array and
|
||||
parses it into a LIST. The input must be a JSON array (enclosed in square
|
||||
brackets); otherwise a clear error is raised.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"json_string": (IO.STRING, {"default": "[]", "widgetType": "STRING", "tooltip": "STRING containing a JSON array to parse, e.g. [1, 2, 3]."}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("LIST",)
|
||||
RETURN_NAMES = ("list",)
|
||||
OUTPUT_TOOLTIPS = ("The LIST parsed from the JSON array string.",)
|
||||
CATEGORY = "Basic/LIST"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "create_from_json"
|
||||
|
||||
def create_from_json(self, json_string: str) -> tuple[list[Any]]:
|
||||
try:
|
||||
result = json.loads(json_string)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON in input string: {e}")
|
||||
if not isinstance(result, list):
|
||||
raise ValueError(
|
||||
"The JSON string must be a JSON array (enclosed in square brackets), "
|
||||
f"not {type(result).__name__}."
|
||||
)
|
||||
return (result,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"Basic data handling: ListCreate": ListCreate,
|
||||
"Basic data handling: ListCreateFromBoolean": ListCreateFromBoolean,
|
||||
"Basic data handling: ListCreateFromFloat": ListCreateFromFloat,
|
||||
"Basic data handling: ListCreateFromInt": ListCreateFromInt,
|
||||
"Basic data handling: ListCreateFromString": ListCreateFromString,
|
||||
"Basic data handling: ListCreateFromJSONString": ListCreateFromJSONString,
|
||||
"Basic data handling: ListAll": ListAll,
|
||||
"Basic data handling: ListAny": ListAny,
|
||||
"Basic data handling: ListAppend": ListAppend,
|
||||
@@ -1013,6 +1051,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"Basic data handling: ListCreateFromFloat": "create LIST from FLOATs",
|
||||
"Basic data handling: ListCreateFromInt": "create LIST from INTs",
|
||||
"Basic data handling: ListCreateFromString": "create LIST from STRINGs",
|
||||
"Basic data handling: ListCreateFromJSONString": "create LIST from JSON string",
|
||||
"Basic data handling: ListAll": "all",
|
||||
"Basic data handling: ListAny": "any",
|
||||
"Basic data handling: ListAppend": "append",
|
||||
|
||||
@@ -11,6 +11,7 @@ from src.basic_data_handling.dict_nodes import (
|
||||
DictCreateFromItemsList,
|
||||
DictCreateFromLists,
|
||||
DictCreateFromString,
|
||||
DictCreateFromJSONString,
|
||||
DictExcludeKeys,
|
||||
DictFilterByKeys,
|
||||
DictFromKeys,
|
||||
@@ -112,6 +113,20 @@ def test_dict_create_from_string():
|
||||
assert node.create() == ({},)
|
||||
|
||||
|
||||
def test_dict_create_from_json_string():
|
||||
node = DictCreateFromJSONString()
|
||||
# Single-line JSON object
|
||||
assert node.create_from_json('{\n "key1": "value1",\n "key2": 2\n}') == ({"key1": "value1", "key2": 2},)
|
||||
# Empty object
|
||||
assert node.create_from_json("{}") == ({},)
|
||||
# JSON array is not a valid object -> error
|
||||
with pytest.raises(ValueError, match="JSON object"):
|
||||
node.create_from_json("[1, 2, 3]")
|
||||
# Malformed JSON -> error
|
||||
with pytest.raises(ValueError):
|
||||
node.create_from_json("{not json}")
|
||||
|
||||
|
||||
def test_dict_create_from_items_datalist():
|
||||
node = DictCreateFromItemsDataList()
|
||||
assert node.create_from_items(item=[("key1", "value1"), ("key2", "value2")]) == (_dict_x2,)
|
||||
|
||||
@@ -10,6 +10,7 @@ from src.basic_data_handling.list_nodes import (
|
||||
ListCreateFromFloat,
|
||||
ListCreateFromInt,
|
||||
ListCreateFromString,
|
||||
ListCreateFromJSONString,
|
||||
ListEnumerate,
|
||||
ListExtend,
|
||||
ListFirst,
|
||||
@@ -257,6 +258,22 @@ def test_list_create_from_string():
|
||||
assert node.create_list() == ([],)
|
||||
|
||||
|
||||
def test_list_create_from_json_string():
|
||||
node = ListCreateFromJSONString()
|
||||
# Multiline JSON array
|
||||
assert node.create_from_json('[\n 1,\n 2,\n 3\n]') == ([1, 2, 3],)
|
||||
# Empty array
|
||||
assert node.create_from_json("[]") == ([],)
|
||||
# Mix of JSON types
|
||||
assert node.create_from_json('["a", 1, true, null]') == (["a", 1, True, None],)
|
||||
# JSON object is not a valid array -> error
|
||||
with pytest.raises(ValueError, match="JSON array"):
|
||||
node.create_from_json('{"a": 1}')
|
||||
# Malformed JSON -> error
|
||||
with pytest.raises(ValueError):
|
||||
node.create_from_json("[1, 2,")
|
||||
|
||||
|
||||
def test_list_to_data_list():
|
||||
node = ListToDataList()
|
||||
input_list = [1, 2, 3]
|
||||
|
||||
Reference in New Issue
Block a user