Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
359 changes: 261 additions & 98 deletions README.md

Large diffs are not rendered by default.

25 changes: 20 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,28 @@ build-backend = "setuptools.build_meta"

[project]
name = "basic_data_handling"
version = "0.3.4"
version = "0.3.5"
description = """NOTE: Still in development! Expect breaking changes!

Basic Python functions for manipulating data that every programmer is used to.
Currently supported ComfyUI data types: BOOLEAN, FLOAT, INT, STRING and data lists.
Additionally supported Python data types as custom data types: DICT, LIST.
Data handling is supported with comparisons and control flow operations.
Also contains math, regex, and file system path manipulation functions."""
Comprehensive node collection for data manipulation in ComfyUI workflows.

Supported data types:
- ComfyUI native: BOOLEAN, FLOAT, INT, STRING, and data lists
- Python types as custom data types: DICT, LIST, SET

Feature categories:
- Boolean logic operations (and, or, not, xor, nand, nor)
- Type casting/conversion between all supported data types
- Comparison operations (equality, numerical comparison, range checking)
- Data structures manipulation (data lists, LIST, DICT, SET)
- Flow control (conditionals, branching, execution order)
- Mathematical operations (arithmetic, trigonometry, logarithmic functions)
- String manipulation (case conversion, formatting, splitting, validation)
- File system path handling (path operations, information, searching)
- SET operations (creation, modification, comparison, mathematical set theory)

All nodes are lightweight with no additional dependencies required."""
authors = [
{name = "StableLlama"}
]
Expand Down
26 changes: 15 additions & 11 deletions src/basic_data_handling/data_list_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class DataListCreate(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.ANY, {"_dynamic": "number"}),
"item_0": (IO.ANY, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -41,7 +41,8 @@ def INPUT_TYPES(cls):
OUTPUT_IS_LIST = (True,)

def create_list(self, **kwargs: list[Any]) -> tuple[list]:
return (list(kwargs.values()),)
values = list(kwargs.values())
return (values[:-1],)


class DataListCreateFromBoolean(ComfyNodeABC):
Expand All @@ -56,7 +57,7 @@ class DataListCreateFromBoolean(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.BOOLEAN, {"_dynamic": "number"}),
"item_0": (IO.BOOLEAN, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -68,7 +69,8 @@ def INPUT_TYPES(cls):
OUTPUT_IS_LIST = (True,)

def create_list(self, **kwargs: list[Any]) -> tuple[list]:
return ([bool(value) for value in kwargs.values()],)
values = [bool(value) for value in kwargs.values()]
return (values[:-1],)


class DataListCreateFromFloat(ComfyNodeABC):
Expand All @@ -83,7 +85,7 @@ class DataListCreateFromFloat(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.FLOAT, {"_dynamic": "number"}),
"item_0": (IO.FLOAT, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -95,7 +97,8 @@ def INPUT_TYPES(cls):
OUTPUT_IS_LIST = (True,)

def create_list(self, **kwargs: list[Any]) -> tuple[list]:
return ([float(value) for value in kwargs.values()],)
values = [float(value) for value in kwargs.values()]
return (values[:-1],)


class DataListCreateFromInt(ComfyNodeABC):
Expand All @@ -110,7 +113,7 @@ class DataListCreateFromInt(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.INT, {"_dynamic": "number"}),
"item_0": (IO.INT, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -122,7 +125,8 @@ def INPUT_TYPES(cls):
OUTPUT_IS_LIST = (True,)

def create_list(self, **kwargs: list[Any]) -> tuple[list]:
return ([int(value) for value in kwargs.values()],)
values = [int(value) for value in kwargs.values()]
return (values[:-1],)


class DataListCreateFromString(ComfyNodeABC):
Expand All @@ -137,7 +141,7 @@ class DataListCreateFromString(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.STRING, {"_dynamic": "number"}),
"item_0": (IO.STRING, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -149,7 +153,8 @@ def INPUT_TYPES(cls):
OUTPUT_IS_LIST = (True,)

def create_list(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return ([str(value) for value in kwargs.values()],)
values = [str(value) for value in kwargs.values()]
return (values[:-1],)


class DataListAppend(ComfyNodeABC):
Expand Down Expand Up @@ -806,7 +811,6 @@ def slice(self, **kwargs: list[Any]) -> tuple[list[Any]]:
start = kwargs.get('start', [0])[0]
stop = kwargs.get('stop', [INT_MAX])[0]
step = kwargs.get('step', [1])[0]
print(f"start: {start}, stop: {stop}, step: {step}; input_list: {input_list}")

return (input_list[start:stop:step],)

Expand Down
30 changes: 15 additions & 15 deletions src/basic_data_handling/dict_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class DictCreate(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
"value_0": (IO.ANY, {"_dynamic": "number", "_dynamicGroup": 0}),
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
"value_0": (IO.ANY, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
})
}

Expand All @@ -40,7 +40,7 @@ def INPUT_TYPES(cls):
def create(self, **kwargs: list[Any]) -> tuple[dict]:
result = {}
# Process all key_X/value_X pairs from dynamic inputs
for i in range(len(kwargs) // 2): # Divide by 2 since we have key/value pairs
for i in range(len(kwargs) // 2 - 1): # Divide by 2 since we have key/value pairs
key_name = f"key_{i}"
value_name = f"value_{i}"
if key_name in kwargs and value_name in kwargs:
Expand All @@ -59,8 +59,8 @@ class DictCreateFromBoolean(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
"value_0": (IO.BOOLEAN, {"_dynamic": "number", "_dynamicGroup": 0}),
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
"value_0": (IO.BOOLEAN, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
})
}

Expand All @@ -72,7 +72,7 @@ def INPUT_TYPES(cls):
def create(self, **kwargs: list[Any]) -> tuple[dict]:
result = {}
# Process all key_X/value_X pairs from dynamic inputs
for i in range(len(kwargs) // 2): # Divide by 2 since we have key/value pairs
for i in range(len(kwargs) // 2 - 1): # Divide by 2 since we have key/value pairs
key_name = f"key_{i}"
value_name = f"value_{i}"
if key_name in kwargs and value_name in kwargs:
Expand All @@ -91,8 +91,8 @@ class DictCreateFromFloat(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
"value_0": (IO.FLOAT, {"_dynamic": "number", "_dynamicGroup": 0}),
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
"value_0": (IO.FLOAT, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
})
}

Expand All @@ -104,7 +104,7 @@ def INPUT_TYPES(cls):
def create(self, **kwargs: list[Any]) -> tuple[dict]:
result = {}
# Process all key_X/value_X pairs from dynamic inputs
for i in range(len(kwargs) // 2): # Divide by 2 since we have key/value pairs
for i in range(len(kwargs) // 2 - 1): # Divide by 2 since we have key/value pairs
key_name = f"key_{i}"
value_name = f"value_{i}"
if key_name in kwargs and value_name in kwargs:
Expand All @@ -123,8 +123,8 @@ class DictCreateFromInt(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
"value_0": (IO.INT, {"_dynamic": "number", "_dynamicGroup": 0}),
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
"value_0": (IO.INT, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
})
}

Expand All @@ -136,7 +136,7 @@ def INPUT_TYPES(cls):
def create(self, **kwargs: list[Any]) -> tuple[dict]:
result = {}
# Process all key_X/value_X pairs from dynamic inputs
for i in range(len(kwargs) // 2): # Divide by 2 since we have key/value pairs
for i in range(len(kwargs) // 2 - 1): # Divide by 2 since we have key/value pairs
key_name = f"key_{i}"
value_name = f"value_{i}"
if key_name in kwargs and value_name in kwargs:
Expand All @@ -155,8 +155,8 @@ class DictCreateFromString(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
"value_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
"value_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
})
}

Expand All @@ -168,7 +168,7 @@ def INPUT_TYPES(cls):
def create(self, **kwargs: list[Any]) -> tuple[dict]:
result = {}
# Process all key_X/value_X pairs from dynamic inputs
for i in range(len(kwargs) // 2): # Divide by 2 since we have key/value pairs
for i in range(len(kwargs) // 2 - 1): # Divide by 2 since we have key/value pairs
key_name = f"key_{i}"
value_name = f"value_{i}"
if key_name in kwargs and value_name in kwargs:
Expand Down
23 changes: 14 additions & 9 deletions src/basic_data_handling/list_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ListCreate(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.ANY, {"_dynamic": "number"}),
"item_0": (IO.ANY, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -39,7 +39,8 @@ def INPUT_TYPES(cls):
FUNCTION = "create_list"

def create_list(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return (list(kwargs.values()),)
values = list(kwargs.values())
return (values[:-1],)


class ListCreateFromBoolean(ComfyNodeABC):
Expand All @@ -54,7 +55,7 @@ class ListCreateFromBoolean(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.BOOLEAN, {"_dynamic": "number"}),
"item_0": (IO.BOOLEAN, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -64,7 +65,8 @@ def INPUT_TYPES(cls):
FUNCTION = "create_list"

def create_list(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return ([bool(value) for value in kwargs.values()],)
values = [bool(value) for value in kwargs.values()]
return (values[:-1],)


class ListCreateFromFloat(ComfyNodeABC):
Expand All @@ -79,7 +81,7 @@ class ListCreateFromFloat(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.FLOAT, {"_dynamic": "number"}),
"item_0": (IO.FLOAT, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -89,7 +91,8 @@ def INPUT_TYPES(cls):
FUNCTION = "create_list"

def create_list(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return ([float(value) for value in kwargs.values()],)
values = [float(value) for value in list(kwargs.values())[:-1]]
return (values,)


class ListCreateFromInt(ComfyNodeABC):
Expand All @@ -104,7 +107,7 @@ class ListCreateFromInt(ComfyNodeABC):
def INPUT_TYPES(cls):
return {
"optional": ContainsDynamicDict({
"item_0": (IO.INT, {"_dynamic": "number"}),
"item_0": (IO.INT, {"_dynamic": "number", "widgetType": "STRING"}),
})
}

Expand All @@ -114,7 +117,8 @@ def INPUT_TYPES(cls):
FUNCTION = "create_list"

def create_list(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return ([int(value) for value in kwargs.values()],)
values = [int(value) for value in list(kwargs.values())[:-1]]
return (values,)


class ListCreateFromString(ComfyNodeABC):
Expand All @@ -139,7 +143,8 @@ def INPUT_TYPES(cls):
FUNCTION = "create_list"

def create_list(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return ([str(value) for value in kwargs.values()],)
values = [str(value) for value in list(kwargs.values())[:-1]]
return (values,)


class ListAppend(ComfyNodeABC):
Expand Down
Loading