Skip to content

Commit b4e0089

Browse files
authored
Merge pull request #13 from StableLlama/dynamic_nodes4
Dynamic nodes4
2 parents f9b9a52 + f2322ea commit b4e0089

File tree

12 files changed

+1004
-426
lines changed

12 files changed

+1004
-426
lines changed

README.md

Lines changed: 261 additions & 98 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,28 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "basic_data_handling"
7-
version = "0.3.4"
7+
version = "0.3.5"
88
description = """NOTE: Still in development! Expect breaking changes!
9+
910
Basic Python functions for manipulating data that every programmer is used to.
10-
Currently supported ComfyUI data types: BOOLEAN, FLOAT, INT, STRING and data lists.
11-
Additionally supported Python data types as custom data types: DICT, LIST.
12-
Data handling is supported with comparisons and control flow operations.
13-
Also contains math, regex, and file system path manipulation functions."""
11+
Comprehensive node collection for data manipulation in ComfyUI workflows.
12+
13+
Supported data types:
14+
- ComfyUI native: BOOLEAN, FLOAT, INT, STRING, and data lists
15+
- Python types as custom data types: DICT, LIST, SET
16+
17+
Feature categories:
18+
- Boolean logic operations (and, or, not, xor, nand, nor)
19+
- Type casting/conversion between all supported data types
20+
- Comparison operations (equality, numerical comparison, range checking)
21+
- Data structures manipulation (data lists, LIST, DICT, SET)
22+
- Flow control (conditionals, branching, execution order)
23+
- Mathematical operations (arithmetic, trigonometry, logarithmic functions)
24+
- String manipulation (case conversion, formatting, splitting, validation)
25+
- File system path handling (path operations, information, searching)
26+
- SET operations (creation, modification, comparison, mathematical set theory)
27+
28+
All nodes are lightweight with no additional dependencies required."""
1429
authors = [
1530
{name = "StableLlama"}
1631
]

src/basic_data_handling/data_list_nodes.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class DataListCreate(ComfyNodeABC):
2929
def INPUT_TYPES(cls):
3030
return {
3131
"optional": ContainsDynamicDict({
32-
"item_0": (IO.ANY, {"_dynamic": "number"}),
32+
"item_0": (IO.ANY, {"_dynamic": "number", "widgetType": "STRING"}),
3333
})
3434
}
3535

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

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

4647

4748
class DataListCreateFromBoolean(ComfyNodeABC):
@@ -56,7 +57,7 @@ class DataListCreateFromBoolean(ComfyNodeABC):
5657
def INPUT_TYPES(cls):
5758
return {
5859
"optional": ContainsDynamicDict({
59-
"item_0": (IO.BOOLEAN, {"_dynamic": "number"}),
60+
"item_0": (IO.BOOLEAN, {"_dynamic": "number", "widgetType": "STRING"}),
6061
})
6162
}
6263

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

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

7375

7476
class DataListCreateFromFloat(ComfyNodeABC):
@@ -83,7 +85,7 @@ class DataListCreateFromFloat(ComfyNodeABC):
8385
def INPUT_TYPES(cls):
8486
return {
8587
"optional": ContainsDynamicDict({
86-
"item_0": (IO.FLOAT, {"_dynamic": "number"}),
88+
"item_0": (IO.FLOAT, {"_dynamic": "number", "widgetType": "STRING"}),
8789
})
8890
}
8991

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

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

100103

101104
class DataListCreateFromInt(ComfyNodeABC):
@@ -110,7 +113,7 @@ class DataListCreateFromInt(ComfyNodeABC):
110113
def INPUT_TYPES(cls):
111114
return {
112115
"optional": ContainsDynamicDict({
113-
"item_0": (IO.INT, {"_dynamic": "number"}),
116+
"item_0": (IO.INT, {"_dynamic": "number", "widgetType": "STRING"}),
114117
})
115118
}
116119

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

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

127131

128132
class DataListCreateFromString(ComfyNodeABC):
@@ -137,7 +141,7 @@ class DataListCreateFromString(ComfyNodeABC):
137141
def INPUT_TYPES(cls):
138142
return {
139143
"optional": ContainsDynamicDict({
140-
"item_0": (IO.STRING, {"_dynamic": "number"}),
144+
"item_0": (IO.STRING, {"_dynamic": "number", "widgetType": "STRING"}),
141145
})
142146
}
143147

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

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

154159

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

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

src/basic_data_handling/dict_nodes.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ class DictCreate(ComfyNodeABC):
2727
def INPUT_TYPES(cls):
2828
return {
2929
"optional": ContainsDynamicDict({
30-
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0}),
31-
"value_0": (IO.ANY, {"_dynamic": "number", "_dynamicGroup": 0}),
30+
"key_0": (IO.STRING, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
31+
"value_0": (IO.ANY, {"_dynamic": "number", "_dynamicGroup": 0, "widgetType": "STRING"}),
3232
})
3333
}
3434

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

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

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

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

@@ -168,7 +168,7 @@ def INPUT_TYPES(cls):
168168
def create(self, **kwargs: list[Any]) -> tuple[dict]:
169169
result = {}
170170
# Process all key_X/value_X pairs from dynamic inputs
171-
for i in range(len(kwargs) // 2): # Divide by 2 since we have key/value pairs
171+
for i in range(len(kwargs) // 2 - 1): # Divide by 2 since we have key/value pairs
172172
key_name = f"key_{i}"
173173
value_name = f"value_{i}"
174174
if key_name in kwargs and value_name in kwargs:

src/basic_data_handling/list_nodes.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ListCreate(ComfyNodeABC):
2929
def INPUT_TYPES(cls):
3030
return {
3131
"optional": ContainsDynamicDict({
32-
"item_0": (IO.ANY, {"_dynamic": "number"}),
32+
"item_0": (IO.ANY, {"_dynamic": "number", "widgetType": "STRING"}),
3333
})
3434
}
3535

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

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

4445

4546
class ListCreateFromBoolean(ComfyNodeABC):
@@ -54,7 +55,7 @@ class ListCreateFromBoolean(ComfyNodeABC):
5455
def INPUT_TYPES(cls):
5556
return {
5657
"optional": ContainsDynamicDict({
57-
"item_0": (IO.BOOLEAN, {"_dynamic": "number"}),
58+
"item_0": (IO.BOOLEAN, {"_dynamic": "number", "widgetType": "STRING"}),
5859
})
5960
}
6061

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

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

6971

7072
class ListCreateFromFloat(ComfyNodeABC):
@@ -79,7 +81,7 @@ class ListCreateFromFloat(ComfyNodeABC):
7981
def INPUT_TYPES(cls):
8082
return {
8183
"optional": ContainsDynamicDict({
82-
"item_0": (IO.FLOAT, {"_dynamic": "number"}),
84+
"item_0": (IO.FLOAT, {"_dynamic": "number", "widgetType": "STRING"}),
8385
})
8486
}
8587

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

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

9497

9598
class ListCreateFromInt(ComfyNodeABC):
@@ -104,7 +107,7 @@ class ListCreateFromInt(ComfyNodeABC):
104107
def INPUT_TYPES(cls):
105108
return {
106109
"optional": ContainsDynamicDict({
107-
"item_0": (IO.INT, {"_dynamic": "number"}),
110+
"item_0": (IO.INT, {"_dynamic": "number", "widgetType": "STRING"}),
108111
})
109112
}
110113

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

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

119123

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

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

144149

145150
class ListAppend(ComfyNodeABC):

0 commit comments

Comments
 (0)