Version 0.0.6
Add data list filtering, control flow and comparison.
This commit is contained in:
@@ -41,7 +41,7 @@ These nodes are very lightweight and require no additional dependencies.
|
||||
- **data list**: ComfyUI list manipulation nodes (for processing individual items)
|
||||
- Conversion: convert to LIST
|
||||
- Creation: create_empty
|
||||
- Modification: append, extend, insert, remove, pop, clear, set_item
|
||||
- Modification: append, filter, extend, insert, remove, pop, clear, set_item
|
||||
- Access: get_item, slice, index, contains
|
||||
- Information: length, count
|
||||
- Operations: sort, reverse, copy, zip
|
||||
@@ -66,6 +66,16 @@ These nodes are very lightweight and require no additional dependencies.
|
||||
- **BOOLEAN**: Boolean logic nodes
|
||||
- Logic operations: and, or, not, xor, nand, nor
|
||||
|
||||
- **Comparison**: Value comparison nodes
|
||||
- Basic comparisons: equal (==), not equal (!=), greater than (>), less than (<), etc.
|
||||
- String comparison: case-sensitive/insensitive string comparison with various operators
|
||||
- Special comparisons: number in range, is null, compare length
|
||||
- Container operations: length comparison for strings, lists, and other containers
|
||||
|
||||
- **Flow Control**: Workflow control nodes
|
||||
- Conditional: if/else for branching logic based on conditions
|
||||
- Selection: switch/case for selecting from multiple options based on an index
|
||||
|
||||
## Understanding LIST vs. data list vs. SET
|
||||
|
||||
ComfyUI has different data types that serve different purposes:
|
||||
|
||||
+3
-2
@@ -4,10 +4,11 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "basic_data_handling"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
description = """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."""
|
||||
Additionally supported Python data types as custom data types: DICT, LIST.
|
||||
Data handling is supported with comparisons and control flow operations."""
|
||||
authors = [
|
||||
{name = "Basic data handling"}
|
||||
]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from . import (boolean_nodes, data_list_nodes, dict_nodes, float_nodes, int_nodes,
|
||||
list_nodes, set_nodes, string_nodes)
|
||||
from . import (boolean_nodes, comparison_nodes, control_flow, data_list_nodes, dict_nodes,
|
||||
float_nodes, int_nodes, list_nodes, set_nodes, string_nodes)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
NODE_CLASS_MAPPINGS.update(boolean_nodes.NODE_CLASS_MAPPINGS)
|
||||
NODE_CLASS_MAPPINGS.update(comparison_nodes.NODE_CLASS_MAPPINGS)
|
||||
NODE_CLASS_MAPPINGS.update(control_flow.NODE_CLASS_MAPPINGS)
|
||||
NODE_CLASS_MAPPINGS.update(data_list_nodes.NODE_CLASS_MAPPINGS)
|
||||
NODE_CLASS_MAPPINGS.update(dict_nodes.NODE_CLASS_MAPPINGS)
|
||||
NODE_CLASS_MAPPINGS.update(float_nodes.NODE_CLASS_MAPPINGS)
|
||||
@@ -13,6 +15,8 @@ NODE_CLASS_MAPPINGS.update(string_nodes.NODE_CLASS_MAPPINGS)
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {}
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(boolean_nodes.NODE_DISPLAY_NAME_MAPPINGS)
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(comparison_nodes.NODE_DISPLAY_NAME_MAPPINGS)
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(control_flow.NODE_DISPLAY_NAME_MAPPINGS)
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(data_list_nodes.NODE_DISPLAY_NAME_MAPPINGS)
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(dict_nodes.NODE_DISPLAY_NAME_MAPPINGS)
|
||||
NODE_DISPLAY_NAME_MAPPINGS.update(float_nodes.NODE_DISPLAY_NAME_MAPPINGS)
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
from typing import Any
|
||||
from inspect import cleandoc
|
||||
|
||||
class Equal:
|
||||
"""
|
||||
Checks if two values are equal.
|
||||
|
||||
This node takes two inputs of any type and returns True if they are equal,
|
||||
and False otherwise. For complex objects, structural equality is tested.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value1": ("*", {}),
|
||||
"value2": ("*", {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool:
|
||||
return True
|
||||
|
||||
def compare(self, value1: Any, value2: Any) -> tuple[bool]:
|
||||
return (value1 == value2,)
|
||||
|
||||
|
||||
class NotEqual:
|
||||
"""
|
||||
Checks if two values are not equal.
|
||||
|
||||
This node takes two inputs of any type and returns True if they are not equal,
|
||||
and False otherwise. For complex objects, structural inequality is tested.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value1": ("*", {}),
|
||||
"value2": ("*", {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool:
|
||||
return True
|
||||
|
||||
def compare(self, value1: Any, value2: Any) -> tuple[bool]:
|
||||
return (value1 != value2,)
|
||||
|
||||
|
||||
class GreaterThan:
|
||||
"""
|
||||
Checks if the first value is greater than the second.
|
||||
|
||||
This node takes two numerical inputs and returns True if the first value
|
||||
is greater than the second value, and False otherwise.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value1": (["FLOAT", "INT"], {}),
|
||||
"value2": (["FLOAT", "INT"], {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["value1"] not in ("FLOAT", "INT"):
|
||||
return "value1 must be a FLOAT or INT type"
|
||||
if input_types["value2"] not in ("FLOAT", "INT"):
|
||||
return "value2 must be a FLOAT or INT type"
|
||||
return True
|
||||
|
||||
def compare(self, value1: float, value2: float) -> tuple[bool]:
|
||||
return (value1 > value2,)
|
||||
|
||||
|
||||
class LessThan:
|
||||
"""
|
||||
Checks if the first value is less than the second.
|
||||
|
||||
This node takes two numerical inputs and returns True if the first value
|
||||
is less than the second value, and False otherwise.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value1": (["FLOAT", "INT"], {}),
|
||||
"value2": (["FLOAT", "INT"], {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["value1"] not in ("FLOAT", "INT"):
|
||||
return "value1 must be a FLOAT or INT type"
|
||||
if input_types["value2"] not in ("FLOAT", "INT"):
|
||||
return "value2 must be a FLOAT or INT type"
|
||||
return True
|
||||
|
||||
def compare(self, value1: float, value2: float) -> tuple[bool]:
|
||||
return (value1 < value2,)
|
||||
|
||||
|
||||
class GreaterThanOrEqual:
|
||||
"""
|
||||
Checks if the first value is greater than or equal to the second.
|
||||
|
||||
This node takes two numerical inputs and returns True if the first value
|
||||
is greater than or equal to the second value, and False otherwise.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value1": (["FLOAT", "INT"], {}),
|
||||
"value2": (["FLOAT", "INT"], {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["value1"] not in ("FLOAT", "INT"):
|
||||
return "value1 must be a FLOAT or INT type"
|
||||
if input_types["value2"] not in ("FLOAT", "INT"):
|
||||
return "value2 must be a FLOAT or INT type"
|
||||
return True
|
||||
|
||||
def compare(self, value1: float, value2: float) -> tuple[bool]:
|
||||
return (value1 >= value2,)
|
||||
|
||||
|
||||
class LessThanOrEqual:
|
||||
"""
|
||||
Checks if the first value is less than or equal to the second.
|
||||
|
||||
This node takes two numerical inputs and returns True if the first value
|
||||
is less than or equal to the second value, and False otherwise.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value1": (["FLOAT", "INT"], {}),
|
||||
"value2": (["FLOAT", "INT"], {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["value1"] not in ("FLOAT", "INT"):
|
||||
return "value1 must be a FLOAT or INT type"
|
||||
if input_types["value2"] not in ("FLOAT", "INT"):
|
||||
return "value2 must be a FLOAT or INT type"
|
||||
return True
|
||||
|
||||
def compare(self, value1: float, value2: float) -> tuple[bool]:
|
||||
return (value1 <= value2,)
|
||||
|
||||
|
||||
class StringComparison:
|
||||
"""
|
||||
Compares two strings using a selected comparison operator.
|
||||
|
||||
This node takes two string inputs and a comparison operator, and returns
|
||||
a boolean result based on the selected comparison.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"string1": ("STRING", {"default": ""}),
|
||||
"string2": ("STRING", {"default": ""}),
|
||||
"operator": (["==", "!=", ">", "<", ">=", "<="], {"default": "=="}),
|
||||
"case_sensitive": (["True", "False"], {"default": "True"}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["string1"] != "STRING":
|
||||
return "string1 must be a STRING type"
|
||||
if input_types["string2"] != "STRING":
|
||||
return "string2 must be a STRING type"
|
||||
return True
|
||||
|
||||
def compare(self, string1: str, string2: str, operator: str, case_sensitive: str) -> tuple[bool]:
|
||||
if case_sensitive == "False":
|
||||
string1 = string1.lower()
|
||||
string2 = string2.lower()
|
||||
|
||||
if operator == "==":
|
||||
return (string1 == string2,)
|
||||
elif operator == "!=":
|
||||
return (string1 != string2,)
|
||||
elif operator == ">":
|
||||
return (string1 > string2,)
|
||||
elif operator == "<":
|
||||
return (string1 < string2,)
|
||||
elif operator == ">=":
|
||||
return (string1 >= string2,)
|
||||
elif operator == "<=":
|
||||
return (string1 <= string2,)
|
||||
else:
|
||||
raise ValueError(f"Unknown operator: {operator}")
|
||||
|
||||
|
||||
class NumberInRange:
|
||||
"""
|
||||
Checks if a number is within a specified range.
|
||||
|
||||
This node takes a number and range bounds, and returns True if the number
|
||||
is within the specified range, and False otherwise. The user can specify
|
||||
whether the bounds are inclusive or exclusive.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value": (["FLOAT", "INT"], {}),
|
||||
"min_value": (["FLOAT", "INT"], {"default": 0}),
|
||||
"max_value": (["FLOAT", "INT"], {"default": 100}),
|
||||
},
|
||||
"optional": {
|
||||
"include_min": (["True", "False"], {"default": "True"}),
|
||||
"include_max": (["True", "False"], {"default": "True"}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("in_range",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "check_range"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["value"] not in ("FLOAT", "INT"):
|
||||
return "value must be a FLOAT or INT type"
|
||||
if input_types["min_value"] not in ("FLOAT", "INT"):
|
||||
return "min_value must be a FLOAT or INT type"
|
||||
if input_types["max_value"] not in ("FLOAT", "INT"):
|
||||
return "max_value must be a FLOAT or INT type"
|
||||
return True
|
||||
|
||||
def check_range(self, value: float, min_value: float, max_value: float,
|
||||
include_min: str = "True", include_max: str = "True") -> tuple[bool]:
|
||||
min_check = value >= min_value if include_min == "True" else value > min_value
|
||||
max_check = value <= max_value if include_max == "True" else value < max_value
|
||||
|
||||
return (min_check and max_check,)
|
||||
|
||||
|
||||
class IsNull:
|
||||
"""
|
||||
Checks if a value is None/null.
|
||||
|
||||
This node takes any input value and returns True if the value is None,
|
||||
and False otherwise.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value": ("*", {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
RETURN_NAMES = ("is_null",)
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "check_null"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool:
|
||||
return True
|
||||
|
||||
def check_null(self, value: Any) -> tuple[bool]:
|
||||
return (value is None,)
|
||||
|
||||
|
||||
class CompareLength:
|
||||
"""
|
||||
Compares the length of a container (string, list, etc) with a value.
|
||||
|
||||
This node takes a container and a comparison value, and returns a boolean
|
||||
result based on the comparison of the container's length with the value.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"container": ("*", {}),
|
||||
"operator": (["==", "!=", ">", "<", ">=", "<="], {"default": "=="}),
|
||||
"length": ("INT", {"default": 0, "min": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN", "INT")
|
||||
RETURN_NAMES = ("result", "actual_length")
|
||||
CATEGORY = "Basic/comparison"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "compare_length"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["length"] != "INT":
|
||||
return "length must be an INT type"
|
||||
return True
|
||||
|
||||
def compare_length(self, container: Any, operator: str, length: int) -> tuple[bool, int]:
|
||||
try:
|
||||
actual_length = len(container)
|
||||
except (TypeError, AttributeError):
|
||||
# If the object doesn't have a length, return False and -1
|
||||
return False, -1
|
||||
|
||||
if operator == "==":
|
||||
return (actual_length == length, actual_length)
|
||||
elif operator == "!=":
|
||||
return (actual_length != length, actual_length)
|
||||
elif operator == ">":
|
||||
return (actual_length > length, actual_length)
|
||||
elif operator == "<":
|
||||
return (actual_length < length, actual_length)
|
||||
elif operator == ">=":
|
||||
return (actual_length >= length, actual_length)
|
||||
elif operator == "<=":
|
||||
return (actual_length <= length, actual_length)
|
||||
else:
|
||||
raise ValueError(f"Unknown operator: {operator}")
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"Equal": Equal,
|
||||
"NotEqual": NotEqual,
|
||||
"GreaterThan": GreaterThan,
|
||||
"LessThan": LessThan,
|
||||
"GreaterThanOrEqual": GreaterThanOrEqual,
|
||||
"LessThanOrEqual": LessThanOrEqual,
|
||||
"StringComparison": StringComparison,
|
||||
"NumberInRange": NumberInRange,
|
||||
"IsNull": IsNull,
|
||||
"CompareLength": CompareLength,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"Equal": "==",
|
||||
"NotEqual": "!=",
|
||||
"GreaterThan": ">",
|
||||
"LessThan": "<",
|
||||
"GreaterThanOrEqual": ">=",
|
||||
"LessThanOrEqual": "<=",
|
||||
"StringComparison": "string compare",
|
||||
"NumberInRange": "in range",
|
||||
"IsNull": "is null",
|
||||
"CompareLength": "compare length",
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
from typing import Any, Dict, List, Union
|
||||
from inspect import cleandoc
|
||||
|
||||
class IfElse:
|
||||
"""
|
||||
Implements a conditional branch (if/else) in the workflow.
|
||||
|
||||
This node takes a condition input and two value inputs. If the condition
|
||||
evaluates to True, the first value is returned; otherwise, the second value
|
||||
is returned. This allows conditional data flow in ComfyUI workflows.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"condition": ("BOOLEAN", {}),
|
||||
"if_true": ("*", {"lazy": True}),
|
||||
"if_false": ("*", {"lazy": True}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("*",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/ ⎇ Flow Control"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "execute"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["condition"] not in ("BOOLEAN"):
|
||||
return "condition must be a BOOLEAN type"
|
||||
return True
|
||||
|
||||
def check_lazy_status(self, condition: bool, if_true: Any, if_false: Any) -> list[str]:
|
||||
needed = []
|
||||
if if_true is None and condition is True:
|
||||
needed.append("if_true")
|
||||
if if_false is None and condition is False:
|
||||
needed.append("if_false")
|
||||
return needed
|
||||
|
||||
def execute(self, condition: bool, if_true: Any, if_false: Any) -> tuple[Any]:
|
||||
"""Execute the if/else statement and return the appropriate value."""
|
||||
return (if_true if condition else if_false,)
|
||||
|
||||
|
||||
class SwitchCase:
|
||||
"""
|
||||
Implements a switch/case selection in the workflow.
|
||||
|
||||
This node takes a selector input (an integer) and multiple case value inputs.
|
||||
It returns the value corresponding to the provided index. If the index is out
|
||||
of range, the default value is returned. This allows for selection from multiple
|
||||
options based on a computed index.
|
||||
|
||||
NOTE: This version of the node will most likely be deprecated in the future.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"selector": ("INT", {"default": 0, "min": 0}),
|
||||
"case_0": ("*", {"lazy": True}),
|
||||
"case_1": ("*", {"lazy": True}),
|
||||
},
|
||||
"optional": {
|
||||
"case_2": ("*", {"lazy": True}),
|
||||
"case_3": ("*", {"lazy": True}),
|
||||
"case_4": ("*", {"lazy": True}),
|
||||
"default": ("*", {"lazy": True}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("*",)
|
||||
RETURN_NAMES = ("result",)
|
||||
CATEGORY = "Basic/ ⎇ Flow Control"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "execute"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["selector"] not in ("INT"):
|
||||
return "selector must be a INT type"
|
||||
return True
|
||||
|
||||
def check_lazy_status(self, condition: int, case_0: Any, case_1: Any,
|
||||
case_2: Any, case_3: Any, case_4: Any, default: Any) -> list[str]:
|
||||
needed = []
|
||||
if case_0 is None and condition == 0:
|
||||
needed.append("case_0")
|
||||
if case_1 is None and condition == 1:
|
||||
needed.append("case_1")
|
||||
if case_2 is None and condition == 2:
|
||||
needed.append("case_2")
|
||||
if case_3 is None and condition == 3:
|
||||
needed.append("case_3")
|
||||
if case_4 is None and condition == 4:
|
||||
needed.append("case_4")
|
||||
if default is None and not 0 <= condition <= 4:
|
||||
needed.append("default")
|
||||
return needed
|
||||
|
||||
def execute(self, selector: int, case_0: Any, case_1: Any,
|
||||
case_2: Any = None, case_3: Any = None,
|
||||
case_4: Any = None, default: Any = None) -> tuple[Any]:
|
||||
"""Execute the switch/case statement and return the appropriate value."""
|
||||
cases = [case_0, case_1, case_2, case_3, case_4]
|
||||
|
||||
if 0 <= selector < len(cases) and cases[selector] is not None:
|
||||
return (cases[selector],)
|
||||
|
||||
# If selector is out of range or the selected case is None, return default
|
||||
return (default,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"IfElse": IfElse,
|
||||
"SwitchCase": SwitchCase,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"IfElse": "if/else",
|
||||
"SwitchCase": "switch/case",
|
||||
}
|
||||
@@ -173,7 +173,7 @@ class DataListPop:
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types["index"] not in ("INT"):
|
||||
if input_types[0].get("index", "INT") not in ("INT"):
|
||||
return "index must be an INT type"
|
||||
return True
|
||||
|
||||
@@ -648,6 +648,50 @@ class DataListZip:
|
||||
return (result,)
|
||||
|
||||
|
||||
class DataListFilter:
|
||||
"""
|
||||
Filters a data list using boolean values.
|
||||
|
||||
This node takes a value data list and a filter data list (containing only boolean values).
|
||||
It returns a new data list containing only the elements from the value list where the
|
||||
corresponding element in the filter list is False.
|
||||
|
||||
If the lists have different lengths, the last element of the shorter list is repeated
|
||||
till the lengths are matching.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"value": ("*", {}),
|
||||
"filter": ("BOOLEAN", {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("*",)
|
||||
RETURN_NAMES = ("filtered_list",)
|
||||
CATEGORY = "Basic/data list"
|
||||
DESCRIPTION = cleandoc(__doc__ or "")
|
||||
FUNCTION = "filter_data"
|
||||
INPUT_IS_LIST = True
|
||||
OUTPUT_IS_LIST = (True,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
|
||||
if input_types[0]["filter"] not in ("BOOLEAN"):
|
||||
return "filter must be a BOOLEAN type"
|
||||
return True
|
||||
|
||||
def filter_data(self, **kwargs: dict[str, list]) -> tuple[list[Any]]:
|
||||
values = kwargs.get('value', [])
|
||||
filters = kwargs.get('filter', [])
|
||||
|
||||
# Create a new list with only items where the filter is False
|
||||
result = [_val for _val, _filter in zip(values, filters) if not _filter]
|
||||
|
||||
return (result,)
|
||||
|
||||
|
||||
class DataListToList:
|
||||
"""
|
||||
Converts a ComfyUI data list into a LIST object.
|
||||
@@ -696,6 +740,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"DataListContains": DataListContains,
|
||||
"DataListCreateEmpty": DataListCreateEmpty,
|
||||
"DataListZip": DataListZip,
|
||||
"DataListFilter": DataListFilter,
|
||||
"DataListToList": DataListToList,
|
||||
}
|
||||
|
||||
@@ -718,5 +763,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"DataListContains": "contains",
|
||||
"DataListCreateEmpty": "create_empty",
|
||||
"DataListZip": "zip",
|
||||
"DataListFilter": "filter",
|
||||
"DataListToList": "convert to LIST",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user