Bum version to 0.2.0 as most nodes should be stable now.

Consolidate all nodes.
This commit is contained in:
StableLlama
2025-05-11 21:52:29 +02:00
parent 2e4dadaa80
commit 7fe4478f3e
12 changed files with 905 additions and 664 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "basic_data_handling"
version = "0.1.0"
version = "0.2.0"
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.
-54
View File
@@ -116,31 +116,6 @@ class CastToList(ComfyNodeABC):
return ([input],)
class CastDataListToList(ComfyNodeABC):
"""
Converts a ComfyUI data list into a LIST object.
This node takes a data list input (which is typically a list of items with the same type)
and converts it to a LIST object (a Python list as a single variable).
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": (IO.ANY, {}),
}
}
RETURN_TYPES = ("LIST",)
CATEGORY = "Basic/cast"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
INPUT_IS_LIST = True
def convert(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return (kwargs.get('list', []).copy(),)
class CastToSet(ComfyNodeABC):
"""
Converts any input to a SET. Non-set inputs are converted into a set. If input is a ComfyUI data list,
@@ -165,31 +140,6 @@ class CastToSet(ComfyNodeABC):
return ({input,} if not isinstance(input, list) else set(input),)
class CastDataListToSet(ComfyNodeABC):
"""
Converts a ComfyUI data list into a LIST object.
This node takes a data list input (which is typically a list of items with the same type)
and converts it to a LIST object (a Python list as a single variable).
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": (IO.ANY, {}),
}
}
RETURN_TYPES = ("SET",)
CATEGORY = "Basic/cast"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
INPUT_IS_LIST = True
def convert(self, **kwargs: list[Any]) -> tuple[set[Any]]:
return (set(kwargs.get('list', [])),)
class CastToDict(ComfyNodeABC):
"""
Converts compatible inputs to a DICT. Input must be a mapping or a list of key-value pairs.
@@ -220,9 +170,7 @@ NODE_CLASS_MAPPINGS = {
"Basic data handling: CastToFloat": CastToFloat,
"Basic data handling: CastToBoolean": CastToBoolean,
"Basic data handling: CastToList": CastToList,
"Basic data handling: CastDataListToList": CastDataListToList,
"Basic data handling: CastToSet": CastToSet,
"Basic data handling: CastDataListToSet": CastDataListToSet,
"Basic data handling: CastToDict": CastToDict,
}
@@ -232,8 +180,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: CastToFloat": "to FLOAT",
"Basic data handling: CastToBoolean": "to BOOLEAN",
"Basic data handling: CastToList": "to LIST",
"Basic data handling: CastDataListToList": "data list to LIST",
"Basic data handling: CastToSet": "to SET",
"Basic data handling: CastDataListToSet": "data list to SET",
"Basic data handling: CastToDict": "to DICT",
}
+59 -5
View File
@@ -2,6 +2,8 @@ from typing import Any
from inspect import cleandoc
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
INT_MAX = 2**15-1 # the computer can do more but be nice to the eyes
class DataListAppend(ComfyNodeABC):
"""
Adds an item to the end of a list.
@@ -337,7 +339,7 @@ class DataListSlice(ComfyNodeABC):
},
"optional": {
"start": (IO.INT, {"default": 0}),
"stop": (IO.INT, {"default": -1}),
"stop": (IO.INT, {"default": INT_MAX}),
"step": (IO.INT, {"default": 1}),
}
}
@@ -353,11 +355,9 @@ class DataListSlice(ComfyNodeABC):
def slice(self, **kwargs: list[Any]) -> tuple[list[Any]]:
input_list = kwargs.get('list', [])
start = kwargs.get('start', [0])[0]
stop = kwargs.get('stop', [-1])[0]
stop = kwargs.get('stop', [INT_MAX])[0]
step = kwargs.get('step', [1])[0]
if stop == -1:
stop = len(input_list)
print(f"start: {start}, stop: {stop}, step: {step}; input_list: {input_list}")
return (input_list[start:stop:step],)
@@ -635,6 +635,56 @@ class DataListMax(ComfyNodeABC):
return (None,)
class DataListToList(ComfyNodeABC):
"""
Converts a ComfyUI data list into a LIST object.
This node takes a data list input (which is typically a list of items with the same type)
and converts it to a LIST object (a Python list as a single variable).
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": (IO.ANY, {}),
}
}
RETURN_TYPES = ("LIST",)
CATEGORY = "Basic/data list"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
INPUT_IS_LIST = True
def convert(self, **kwargs: list[Any]) -> tuple[list[Any]]:
return (kwargs.get('list', []).copy(),)
class DataListToSet(ComfyNodeABC):
"""
Converts a ComfyUI data list into a LIST object.
This node takes a data list input (which is typically a list of items with the same type)
and converts it to a LIST object (a Python list as a single variable).
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": (IO.ANY, {}),
}
}
RETURN_TYPES = ("SET",)
CATEGORY = "Basic/data list"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
INPUT_IS_LIST = True
def convert(self, **kwargs: list[Any]) -> tuple[set[Any]]:
return (set(kwargs.get('list', [])),)
NODE_CLASS_MAPPINGS = {
"Basic data handling: DataListAppend": DataListAppend,
"Basic data handling: DataListExtend": DataListExtend,
@@ -655,6 +705,8 @@ NODE_CLASS_MAPPINGS = {
"Basic data handling: DataListFilter": DataListFilter,
"Basic data handling: DataListMin": DataListMin,
"Basic data handling: DataListMax": DataListMax,
"Basic data handling: DataListToList": DataListToList,
"Basic data handling: DataListToSet": DataListToSet,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -677,4 +729,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: DataListFilter": "filter",
"Basic data handling: DataListMin": "min",
"Basic data handling: DataListMax": "max",
"Basic data handling: DataListToList": "convert to LIST",
"Basic data handling: DataListToSet": "convert to SET",
}
+65 -35
View File
@@ -1,6 +1,7 @@
from inspect import cleandoc
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class FloatAdd:
class FloatAdd(ComfyNodeABC):
"""
Adds two floating-point numbers.
@@ -10,12 +11,12 @@ class FloatAdd:
def INPUT_TYPES(cls):
return {
"required": {
"float1": ("FLOAT", {"default": 0.0}),
"float2": ("FLOAT", {"default": 0.0}),
"float1": (IO.FLOAT, {"default": 0.0}),
"float2": (IO.FLOAT, {"default": 0.0}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "add"
@@ -24,7 +25,7 @@ class FloatAdd:
return (float1 + float2,)
class FloatSubtract:
class FloatSubtract(ComfyNodeABC):
"""
Subtracts one floating-point number from another.
@@ -35,12 +36,12 @@ class FloatSubtract:
def INPUT_TYPES(cls):
return {
"required": {
"float1": ("FLOAT", {"default": 0.0}),
"float2": ("FLOAT", {"default": 0.0}),
"float1": (IO.FLOAT, {"default": 0.0}),
"float2": (IO.FLOAT, {"default": 0.0}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "subtract"
@@ -49,7 +50,7 @@ class FloatSubtract:
return (float1 - float2,)
class FloatMultiply:
class FloatMultiply(ComfyNodeABC):
"""
Multiplies two floating-point numbers.
@@ -59,12 +60,12 @@ class FloatMultiply:
def INPUT_TYPES(cls):
return {
"required": {
"float1": ("FLOAT", {"default": 1.0}),
"float2": ("FLOAT", {"default": 1.0}),
"float1": (IO.FLOAT, {"default": 1.0}),
"float2": (IO.FLOAT, {"default": 1.0}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "multiply"
@@ -73,7 +74,7 @@ class FloatMultiply:
return (float1 * float2,)
class FloatDivide:
class FloatDivide(ComfyNodeABC):
"""
Divides one floating-point number by another.
@@ -84,12 +85,12 @@ class FloatDivide:
def INPUT_TYPES(cls):
return {
"required": {
"float1": ("FLOAT", {"default": 1.0}),
"float2": ("FLOAT", {"default": 1.0}),
"float1": (IO.FLOAT, {"default": 1.0}),
"float2": (IO.FLOAT, {"default": 1.0}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "divide"
@@ -100,7 +101,34 @@ class FloatDivide:
return (float1 / float2,)
class FloatPower:
class FloatDivideSafe(ComfyNodeABC):
"""
Divides one floating-point number by another.
This node takes two floats as input and returns the result of the division.
It returns positive or negative infinity if the divisor is 0 (assumed to be +0.0).
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"float1": (IO.FLOAT, {"default": 1.0}),
"float2": (IO.FLOAT, {"default": 1.0}),
}
}
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "divide"
def divide(self, float1: float, float2: float) -> tuple[float]:
if float2 == 0.0:
return (float('inf') if float1 > 0 else float('-inf'),)
return (float1 / float2,)
class FloatPower(ComfyNodeABC):
"""
Raises one floating-point number to the power of another.
@@ -111,12 +139,12 @@ class FloatPower:
def INPUT_TYPES(cls):
return {
"required": {
"base": ("FLOAT", {"default": 1.0}),
"exponent": ("FLOAT", {"default": 1.0}),
"base": (IO.FLOAT, {"default": 1.0}),
"exponent": (IO.FLOAT, {"default": 1.0}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "power"
@@ -125,7 +153,7 @@ class FloatPower:
return (base ** exponent,)
class FloatRound:
class FloatRound(ComfyNodeABC):
"""
Rounds a floating-point number to the specified number of decimal places.
@@ -136,12 +164,12 @@ class FloatRound:
def INPUT_TYPES(cls):
return {
"required": {
"float_value": ("FLOAT", {"default": 0.0}),
"decimal_places": ("INT", {"default": 2, "min": 0}),
"float_value": (IO.FLOAT, {"default": 0.0}),
"decimal_places": (IO.INT, {"default": 2, "min": 0}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "round"
@@ -150,7 +178,7 @@ class FloatRound:
return (round(float_value, decimal_places),)
class FloatIsInteger:
class FloatIsInteger(ComfyNodeABC):
"""
Checks if a floating-point number is an integer.
@@ -161,7 +189,7 @@ class FloatIsInteger:
def INPUT_TYPES(cls):
return {
"required": {
"float_value": ("FLOAT", {"default": 0.0}),
"float_value": (IO.FLOAT, {"default": 0.0}),
}
}
@@ -174,7 +202,7 @@ class FloatIsInteger:
return (float_value.is_integer(),)
class FloatAsIntegerRatio:
class FloatAsIntegerRatio(ComfyNodeABC):
"""
Returns the integer ratio of a floating-point number.
@@ -185,11 +213,11 @@ class FloatAsIntegerRatio:
def INPUT_TYPES(cls):
return {
"required": {
"float_value": ("FLOAT", {"default": 0.0}),
"float_value": (IO.FLOAT, {"default": 0.0}),
}
}
RETURN_TYPES = ("INT", "INT")
RETURN_TYPES = (IO.INT, IO.INT)
RETURN_NAMES = ("numerator", "denominator")
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -201,7 +229,7 @@ class FloatAsIntegerRatio:
return numerator, denominator
class FloatHex:
class FloatHex(ComfyNodeABC):
"""
Converts a floating-point number to its hexadecimal representation.
@@ -211,11 +239,11 @@ class FloatHex:
def INPUT_TYPES(cls):
return {
"required": {
"float_value": ("FLOAT", {"default": 0.0}),
"float_value": (IO.FLOAT, {"default": 0.0}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "to_hex"
@@ -224,7 +252,7 @@ class FloatHex:
return (float_value.hex(),)
class FloatFromHex:
class FloatFromHex(ComfyNodeABC):
"""
Converts a hexadecimal string to its corresponding floating-point number.
@@ -234,11 +262,11 @@ class FloatFromHex:
def INPUT_TYPES(cls):
return {
"required": {
"hex_value": ("STRING", {"default": "0x0.0p+0"}),
"hex_value": (IO.STRING, {"default": "0x0.0p+0"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/FLOAT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "from_hex"
@@ -252,6 +280,7 @@ NODE_CLASS_MAPPINGS = {
"Basic data handling: FloatSubtract": FloatSubtract,
"Basic data handling: FloatMultiply": FloatMultiply,
"Basic data handling: FloatDivide": FloatDivide,
"Basic data handling: FloatDivideSafe": FloatDivideSafe,
"Basic data handling: FloatPower": FloatPower,
"Basic data handling: FloatRound": FloatRound,
"Basic data handling: FloatIsInteger": FloatIsInteger,
@@ -265,6 +294,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: FloatSubtract": "subtract",
"Basic data handling: FloatMultiply": "multiply",
"Basic data handling: FloatDivide": "divide",
"Basic data handling: FloatDivideSafe": "divide (division by zero safe)",
"Basic data handling: FloatPower": "power",
"Basic data handling: FloatRound": "round",
"Basic data handling: FloatIsInteger": "is_integer",
+70 -40
View File
@@ -1,8 +1,8 @@
from inspect import cleandoc
from typing import Literal
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class IntAdd:
class IntAdd(ComfyNodeABC):
"""
Adds two integers.
@@ -12,12 +12,12 @@ class IntAdd:
def INPUT_TYPES(cls):
return {
"required": {
"int1": ("INT", {"default": 0}),
"int2": ("INT", {"default": 0}),
"int1": (IO.INT, {"default": 0}),
"int2": (IO.INT, {"default": 0}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "add"
@@ -26,7 +26,7 @@ class IntAdd:
return (int1 + int2,)
class IntSubtract:
class IntSubtract(ComfyNodeABC):
"""
Subtracts one integer from another.
@@ -37,12 +37,12 @@ class IntSubtract:
def INPUT_TYPES(cls):
return {
"required": {
"int1": ("INT", {"default": 0}),
"int2": ("INT", {"default": 0}),
"int1": (IO.INT, {"default": 0}),
"int2": (IO.INT, {"default": 0}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "subtract"
@@ -51,7 +51,7 @@ class IntSubtract:
return (int1 - int2,)
class IntMultiply:
class IntMultiply(ComfyNodeABC):
"""
Multiplies two integers.
@@ -61,12 +61,12 @@ class IntMultiply:
def INPUT_TYPES(cls):
return {
"required": {
"int1": ("INT", {"default": 1}),
"int2": ("INT", {"default": 1}),
"int1": (IO.INT, {"default": 1}),
"int2": (IO.INT, {"default": 1}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "multiply"
@@ -75,7 +75,7 @@ class IntMultiply:
return (int1 * int2,)
class IntDivide:
class IntDivide(ComfyNodeABC):
"""
Divides one integer by another.
@@ -86,12 +86,12 @@ class IntDivide:
def INPUT_TYPES(cls):
return {
"required": {
"int1": ("INT", {"default": 1}),
"int2": ("INT", {"default": 1}),
"int1": (IO.INT, {"default": 1}),
"int2": (IO.INT, {"default": 1}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "divide"
@@ -102,7 +102,35 @@ class IntDivide:
return (int1 // int2,)
class IntModulus:
class IntDivideSafe(ComfyNodeABC):
"""
Divides one integer by another.
This node takes two integers as input and returns the result of the integer
division. It returns the positive or negative infinity value if the divisor is 0.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"int1": (IO.INT, {"default": 1}),
"int2": (IO.INT, {"default": 1}),
"infinity": (IO.INT, {"default": 9223372036854775807}), # 2**63 - 1
}
}
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "divide"
def divide(self, int1: int, int2: int, infinity: int) -> tuple[int]:
if int2 == 0:
return (infinity if int1 > 0 else -infinity,)
return (int1 // int2,)
class IntModulus(ComfyNodeABC):
"""
Returns the modulus of two integers.
@@ -113,12 +141,12 @@ class IntModulus:
def INPUT_TYPES(cls):
return {
"required": {
"int1": ("INT", {"default": 0}),
"int2": ("INT", {"default": 1}),
"int1": (IO.INT, {"default": 0}),
"int2": (IO.INT, {"default": 1}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "modulus"
@@ -129,7 +157,7 @@ class IntModulus:
return (int1 % int2,)
class IntPower:
class IntPower(ComfyNodeABC):
"""
Raises one integer to the power of another.
@@ -140,12 +168,12 @@ class IntPower:
def INPUT_TYPES(cls):
return {
"required": {
"base": ("INT", {"default": 1}),
"exponent": ("INT", {"default": 0}),
"base": (IO.INT, {"default": 1}),
"exponent": (IO.INT, {"default": 0}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "power"
@@ -154,7 +182,7 @@ class IntPower:
return (base**exponent,)
class IntBitLength:
class IntBitLength(ComfyNodeABC):
"""
Returns the number of bits required to represent an integer in binary.
@@ -165,12 +193,12 @@ class IntBitLength:
def INPUT_TYPES(cls):
return {
"required": {
"int_value": ("INT", {"default": 0}),
"int_value": (IO.INT, {"default": 0}),
}
}
RETURN_TYPES = ("INT",)
CATEGORY = "Additional Methods/INT"
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "bit_length"
@@ -178,7 +206,7 @@ class IntBitLength:
return (int_value.bit_length(),)
class IntToBytes:
class IntToBytes(ComfyNodeABC):
"""
Converts an integer to its byte representation.
@@ -189,15 +217,15 @@ class IntToBytes:
def INPUT_TYPES(cls):
return {
"required": {
"int_value": ("INT", {"default": 0}),
"length": ("INT", {"default": 4, "min": 1}),
"int_value": (IO.INT, {"default": 0}),
"length": (IO.INT, {"default": 4, "min": 1}),
"byteorder": (["big", "little"], {"default": "big"}),
"signed": (["True", "False"], {"default": "False"}),
}
}
RETURN_TYPES = ("BYTES",)
CATEGORY = "Additional Methods/INT"
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "to_bytes"
@@ -206,7 +234,7 @@ class IntToBytes:
return (int_value.to_bytes(length, byteorder=byteorder, signed=signed_bool),)
class IntFromBytes:
class IntFromBytes(ComfyNodeABC):
"""
Converts a bytes object to an integer.
@@ -223,8 +251,8 @@ class IntFromBytes:
}
}
RETURN_TYPES = ("INT",)
CATEGORY = "Additional Methods/INT"
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "from_bytes"
@@ -233,7 +261,7 @@ class IntFromBytes:
return (int.from_bytes(bytes_value, byteorder=byteorder, signed=signed_bool),)
class IntBitCount:
class IntBitCount(ComfyNodeABC):
"""
Returns the number of 1 bits in the binary representation of an integer.
@@ -243,12 +271,12 @@ class IntBitCount:
def INPUT_TYPES(cls):
return {
"required": {
"int_value": ("INT", {"default": 0}),
"int_value": (IO.INT, {"default": 0}),
}
}
RETURN_TYPES = ("INT",)
CATEGORY = "Additional Methods/INT"
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/INT"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "bit_count"
@@ -262,6 +290,7 @@ NODE_CLASS_MAPPINGS = {
"Basic data handling: IntSubtract": IntSubtract,
"Basic data handling: IntMultiply": IntMultiply,
"Basic data handling: IntDivide": IntDivide,
"Basic data handling: IntDivideSafe": IntDivideSafe,
"Basic data handling: IntModulus": IntModulus,
"Basic data handling: IntPower": IntPower,
"Basic data handling: IntBitLength": IntBitLength,
@@ -275,6 +304,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: IntSubtract": "subtract",
"Basic data handling: IntMultiply": "multiply",
"Basic data handling: IntDivide": "divide",
"Basic data handling: IntDivideSafe": "divide (division by zero safe)",
"Basic data handling: IntModulus": "modulus",
"Basic data handling: IntPower": "power",
"Basic data handling: IntBitLength": "bit_length",
+57 -84
View File
@@ -1,7 +1,10 @@
from typing import Any
from inspect import cleandoc
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class ListAppend:
INT_MAX = 2**15-1 # the computer can do more but be nice to the eyes
class ListAppend(ComfyNodeABC):
"""
Adds an item to the end of a LIST.
@@ -13,7 +16,7 @@ class ListAppend:
return {
"required": {
"list": ("LIST", {}),
"item": ("*", {}),
"item": (IO.ANY, {}),
}
}
@@ -28,7 +31,26 @@ class ListAppend:
return (result,)
class ListExtend:
class ListEmpty(ComfyNodeABC):
"""
Create an empty LIST.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {}
}
RETURN_TYPES = ("LIST",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "create"
def create(self) -> tuple[list[Any]]:
return ([],)
class ListExtend(ComfyNodeABC):
"""
Extends a LIST by appending elements from another LIST.
@@ -55,7 +77,7 @@ class ListExtend:
return (result,)
class ListInsert:
class ListInsert(ComfyNodeABC):
"""
Inserts an item at a specified position in a LIST.
@@ -68,7 +90,7 @@ class ListInsert:
"required": {
"list": ("LIST", {}),
"index": ("INT", {"default": 0}),
"item": ("*", {}),
"item": (IO.ANY, {}),
}
}
@@ -83,7 +105,7 @@ class ListInsert:
return (result,)
class ListRemove:
class ListRemove(ComfyNodeABC):
"""
Removes the first occurrence of a specified value from a LIST.
@@ -96,7 +118,7 @@ class ListRemove:
return {
"required": {
"list": ("LIST", {}),
"value": ("*", {}),
"value": (IO.ANY, {}),
}
}
@@ -115,7 +137,7 @@ class ListRemove:
return result, False
class ListPop:
class ListPop(ComfyNodeABC):
"""
Removes and returns an item at a specified position in a LIST.
@@ -135,7 +157,7 @@ class ListPop:
}
}
RETURN_TYPES = ("LIST", "*")
RETURN_TYPES = ("LIST", IO.ANY)
RETURN_NAMES = ("list", "item")
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -150,30 +172,7 @@ class ListPop:
return result, None
class ListClear:
"""
Removes all items from a LIST.
This node takes a LIST as input and returns a new empty LIST.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": ("LIST", {}),
}
}
RETURN_TYPES = ("LIST",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "clear"
def clear(self, list: list[Any]) -> tuple[list[Any]]:
return ([],)
class ListIndex:
class ListIndex(ComfyNodeABC):
"""
Returns the index of the first occurrence of a value in a LIST.
@@ -186,7 +185,7 @@ class ListIndex:
return {
"required": {
"list": ("LIST", {}),
"value": ("*", {}),
"value": (IO.ANY, {}),
},
"optional": {
"start": ("INT", {"default": 0}),
@@ -210,7 +209,7 @@ class ListIndex:
return (-1,)
class ListCount:
class ListCount(ComfyNodeABC):
"""
Counts the number of occurrences of a value in a LIST.
@@ -222,7 +221,7 @@ class ListCount:
return {
"required": {
"list": ("LIST", {}),
"value": ("*", {}),
"value": (IO.ANY, {}),
}
}
@@ -236,7 +235,7 @@ class ListCount:
return (list.count(value),)
class ListSort:
class ListSort(ComfyNodeABC):
"""
Sorts the items in a LIST.
@@ -272,7 +271,7 @@ class ListSort:
return (list.copy(),)
class ListReverse:
class ListReverse(ComfyNodeABC):
"""
Reverses the order of items in a LIST.
@@ -297,7 +296,7 @@ class ListReverse:
return (result,)
class ListLength:
class ListLength(ComfyNodeABC):
"""
Returns the number of items in a LIST.
@@ -321,7 +320,7 @@ class ListLength:
return (len(list),)
class ListSlice:
class ListSlice(ComfyNodeABC):
"""
Creates a slice of a LIST.
@@ -336,7 +335,7 @@ class ListSlice:
},
"optional": {
"start": ("INT", {"default": 0}),
"stop": ("INT", {"default": -1}),
"stop": ("INT", {"default": INT_MAX}),
"step": ("INT", {"default": 1}),
}
}
@@ -346,11 +345,12 @@ class ListSlice:
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "slice"
def slice(self, list: list[Any], start: int = 0, stop: int = -1, step: int = 1) -> tuple[list[Any]]:
def slice(self, list: list[Any], start: int = 0, stop: int = INT_MAX,
step: int = 1) -> tuple[list[Any]]:
return (list[start:stop:step],)
class ListGetItem:
class ListGetItem(ComfyNodeABC):
"""
Retrieves an item at a specified position in a LIST.
@@ -367,7 +367,7 @@ class ListGetItem:
}
}
RETURN_TYPES = ("*",)
RETURN_TYPES = (IO.ANY,)
RETURN_NAMES = ("item",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -380,7 +380,7 @@ class ListGetItem:
return (None,)
class ListSetItem:
class ListSetItem(ComfyNodeABC):
"""
Sets an item at a specified position in a LIST.
@@ -393,7 +393,7 @@ class ListSetItem:
"required": {
"list": ("LIST", {}),
"index": ("INT", {"default": 0}),
"value": ("*", {}),
"value": (IO.ANY, {}),
}
}
@@ -411,7 +411,7 @@ class ListSetItem:
raise IndexError(f"Index {index} out of range for LIST of length {len(list)}")
class ListContains:
class ListContains(ComfyNodeABC):
"""
Checks if a LIST contains a specified value.
@@ -423,7 +423,7 @@ class ListContains:
return {
"required": {
"list": ("LIST", {}),
"value": ("*", {}),
"value": (IO.ANY, {}),
}
}
@@ -437,7 +437,7 @@ class ListContains:
return (value in list,)
class ListToDataList:
class ListToDataList(ComfyNodeABC):
"""
Converts a LIST object into a ComfyUI data list.
@@ -453,7 +453,7 @@ class ListToDataList:
}
}
RETURN_TYPES = ("*",)
RETURN_TYPES = (IO.ANY,)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
@@ -463,7 +463,7 @@ class ListToDataList:
return (list,)
class ListToSet:
class ListToSet(ComfyNodeABC):
"""
Converts a LIST into a SET.
@@ -487,32 +487,7 @@ class ListToSet:
return (set(list),)
class AnyToList:
"""
Converts any input datatype into a LIST.
This node takes any input value and wraps it in a LIST object,
allowing it to be processed by nodes that expect LIST inputs.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"input": ("*", {}),
}
}
RETURN_TYPES = ("LIST",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
def convert(self, input: Any) -> tuple[list[Any]]:
# Create a new list containing the input value
return ([input],)
class ListMin:
class ListMin(ComfyNodeABC):
"""
Returns the minimum value in a LIST.
@@ -527,7 +502,7 @@ class ListMin:
}
}
RETURN_TYPES = ("*",)
RETURN_TYPES = (IO.ANY,)
RETURN_NAMES = ("min_value",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -544,7 +519,7 @@ class ListMin:
return (None,)
class ListMax:
class ListMax(ComfyNodeABC):
"""
Returns the maximum value in a LIST.
@@ -559,7 +534,7 @@ class ListMax:
}
}
RETURN_TYPES = ("*",)
RETURN_TYPES = (IO.ANY,)
RETURN_NAMES = ("max_value",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -578,11 +553,11 @@ class ListMax:
NODE_CLASS_MAPPINGS = {
"Basic data handling: ListAppend": ListAppend,
"Basic data handling: ListEmpty": ListEmpty,
"Basic data handling: ListExtend": ListExtend,
"Basic data handling: ListInsert": ListInsert,
"Basic data handling: ListRemove": ListRemove,
"Basic data handling: ListPop": ListPop,
"Basic data handling: ListClear": ListClear,
"Basic data handling: ListIndex": ListIndex,
"Basic data handling: ListCount": ListCount,
"Basic data handling: ListSort": ListSort,
@@ -594,18 +569,17 @@ NODE_CLASS_MAPPINGS = {
"Basic data handling: ListContains": ListContains,
"Basic data handling: ListToDataList": ListToDataList,
"Basic data handling: ListToSet": ListToSet,
"Basic data handling: AnyToList": AnyToList,
"Basic data handling: ListMin": ListMin,
"Basic data handling: ListMax": ListMax,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: ListAppend": "append",
"Basic data handling: ListEmpty": "empty",
"Basic data handling: ListExtend": "extend",
"Basic data handling: ListInsert": "insert",
"Basic data handling: ListRemove": "remove",
"Basic data handling: ListPop": "pop",
"Basic data handling: ListClear": "clear",
"Basic data handling: ListIndex": "index",
"Basic data handling: ListCount": "count",
"Basic data handling: ListSort": "sort",
@@ -617,7 +591,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: ListContains": "contains",
"Basic data handling: ListToDataList": "convert to data list",
"Basic data handling: ListToSet": "convert to SET",
"Basic data handling: AnyToList": "any to LIST",
"Basic data handling: ListMin": "min",
"Basic data handling: ListMax": "max",
}
+39 -24
View File
@@ -1,6 +1,7 @@
from inspect import cleandoc
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class MathFormula:
class MathFormula(ComfyNodeABC):
"""
A node that evaluates a mathematical formula provided as a string without using eval.
@@ -13,21 +14,23 @@ class MathFormula:
The calculation would be:
result = 2 + abs(-3 * 4 + 5) = 2 + abs(-7) = 2 + 7 = 9
"""
EXPERIMENTAL = True
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"formula": ("STRING", {"default": "a + b"}),
"a": ("FLOAT", {"default": 0.0}),
"formula": (IO.STRING, {"default": "a + b"}),
"a": (IO.NUMBER, {"default": 0.0}),
},
"optional": {
"b": ("FLOAT", {"default": 0.0}),
"c": ("FLOAT", {"default": 0.0}),
"d": ("FLOAT", {"default": 0.0}),
"b": (IO.NUMBER, {"default": 0.0}),
"c": (IO.NUMBER, {"default": 0.0}),
"d": (IO.NUMBER, {"default": 0.0}),
},
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.NUMBER,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "evaluate"
@@ -36,17 +39,6 @@ class MathFormula:
SUPPORTED_FUNCTIONS = {"abs", "floor", "ceil", "round"}
VALID_CHARS = set("0123456789.+-*/%(), ")
@classmethod
def VALIDATE_INPUTS(cls, input_types):
for input, value in input_types.items():
if input == "formula":
if value == "STRING":
continue
return f"input '{input}' must be a STRING type"
if value not in ("INT", "FLOAT"):
return f"input '{input}' must be an INT or FLOAT type"
return True
def evaluate(self, formula: str, a: float, b: float = 0.0, c: float = 0.0, d: float = 0.0) -> tuple[float]:
# Tokenize the formula without replacement
print(f'formula: "{formula}"')
@@ -137,34 +129,57 @@ class MathFormula:
postfix = [] # Output list
previous_token = None # Tracks the previous token to distinguish unary vs binary operators
# Track function-to-parenthesis relationships
function_stack = [] # Stack to track pending functions
for token in tokens:
if self.is_number(token): # Numbers
postfix.append(float(token))
elif token in self.SUPPORTED_FUNCTIONS: # Functions (e.g., abs)
# Push function onto stack - will be processed when matching parenthesis is found
function_stack.append(len(stack)) # Record stack depth for this function
stack.append(token)
elif token == "(": # Left parentheses
stack.append(token)
elif token == ")": # Right parentheses
# Pop operators until left parenthesis
while stack and stack[-1] != "(":
postfix.append(stack.pop())
if not stack:
raise ValueError("Mismatched parentheses in expression.")
stack.pop() # Pops the left parenthesis
stack.pop() # Discard the left parenthesis
# Check if this closing parenthesis matches a function call
if function_stack and len(stack) == function_stack[-1]:
# We've found our function, add it to postfix
if stack and stack[-1] in self.SUPPORTED_FUNCTIONS:
postfix.append(stack.pop())
function_stack.pop() # Remove the function marker
elif token in self.OPERATORS: # Operators (+, -, *, etc.)
# Check for unary negation
if token == "-" and (previous_token is None or previous_token in self.OPERATORS or previous_token == "("):
# Treat as unary minus
postfix.append(0.0)
stack.append(token)
# Handle negative numbers directly - place negative value in postfix
if tokens.index(token) + 1 < len(tokens) and self.is_number(tokens[tokens.index(token) + 1]):
next_token = tokens[tokens.index(token) + 1]
# Skip this token and the next number, add negative number to postfix
postfix.append(-float(next_token))
previous_token = next_token # Skip to after the number
continue
else:
# Traditional unary minus using 0 - operand
postfix.append(0.0)
stack.append(token)
else:
# Handle regular operators
while stack and precedence.get(stack[-1], 0) >= precedence[token]:
while stack and stack[-1] not in ["("] and precedence.get(stack[-1], 0) >= precedence[token]:
postfix.append(stack.pop())
stack.append(token)
else:
raise ValueError(f"Unexpected token in infix expression: {token}")
# Update previous token (e.g., to track variable, number, etc.)
# Update previous token
previous_token = token
# Pop any remaining operators from the stack
+68 -88
View File
@@ -1,9 +1,9 @@
import math
from inspect import cleandoc
from typing import Literal, Union
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class MathSin:
class MathSin(ComfyNodeABC):
"""
Calculates the sine of an angle in radians or degrees.
@@ -15,12 +15,12 @@ class MathSin:
def INPUT_TYPES(cls):
return {
"required": {
"angle": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"angle": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -32,7 +32,7 @@ class MathSin:
return (math.sin(angle),)
class MathCos:
class MathCos(ComfyNodeABC):
"""
Calculates the cosine of an angle in radians or degrees.
@@ -44,12 +44,12 @@ class MathCos:
def INPUT_TYPES(cls):
return {
"required": {
"angle": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"angle": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -61,7 +61,7 @@ class MathCos:
return (math.cos(angle),)
class MathTan:
class MathTan(ComfyNodeABC):
"""
Calculates the tangent of an angle in radians or degrees.
@@ -73,12 +73,12 @@ class MathTan:
def INPUT_TYPES(cls):
return {
"required": {
"angle": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"angle": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -95,7 +95,7 @@ class MathTan:
return (math.tan(angle),)
class MathAsin:
class MathAsin(ComfyNodeABC):
"""
Calculates the arc sine (inverse sine) of a value.
@@ -106,12 +106,12 @@ class MathAsin:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -123,7 +123,7 @@ class MathAsin:
return (result,)
class MathAcos:
class MathAcos(ComfyNodeABC):
"""
Calculates the arc cosine (inverse cosine) of a value.
@@ -134,12 +134,12 @@ class MathAcos:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 1.0, "min": -1.0, "max": 1.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -151,7 +151,7 @@ class MathAcos:
return (result,)
class MathAtan:
class MathAtan(ComfyNodeABC):
"""
Calculates the arc tangent (inverse tangent) of a value.
@@ -162,12 +162,12 @@ class MathAtan:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -179,7 +179,7 @@ class MathAtan:
return (result,)
class MathAtan2:
class MathAtan2(ComfyNodeABC):
"""
Calculates the arc tangent of y/x, considering the quadrant.
@@ -191,13 +191,13 @@ class MathAtan2:
def INPUT_TYPES(cls):
return {
"required": {
"y": ("FLOAT", {"default": 0.0}),
"x": ("FLOAT", {"default": 1.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
"y": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"x": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"unit": (["radians", "degrees"], {"default": "degrees"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -209,7 +209,7 @@ class MathAtan2:
return (result,)
class MathSqrt:
class MathSqrt(ComfyNodeABC):
"""
Calculates the square root of a non-negative number.
@@ -219,11 +219,11 @@ class MathSqrt:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0, "min": 0.0}),
"value": (IO.NUMBER, {"default": 0.0, "min": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -232,7 +232,7 @@ class MathSqrt:
return (math.sqrt(value),)
class MathExp:
class MathExp(ComfyNodeABC):
"""
Calculates the exponential of a number (e^x).
@@ -242,11 +242,11 @@ class MathExp:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -255,7 +255,7 @@ class MathExp:
return (math.exp(value),)
class MathLog:
class MathLog(ComfyNodeABC):
"""
Calculates the natural logarithm (base e) of a number.
@@ -266,14 +266,14 @@ class MathLog:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 1.0, "min": 0.0000001}),
"value": (IO.NUMBER, {"default": 1.0, "min": 0.0000001, "widgetType": "FLOAT"}),
},
"optional": {
"base": ("FLOAT", {"default": math.e, "min": 0.0000001}),
"base": (IO.NUMBER, {"default": math.e, "min": 0.0000001, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -285,7 +285,7 @@ class MathLog:
return (math.log(value, base),)
class MathLog10:
class MathLog10(ComfyNodeABC):
"""
Calculates the base-10 logarithm of a number.
@@ -295,11 +295,11 @@ class MathLog10:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 1.0, "min": 0.0000001}),
"value": (IO.NUMBER, {"default": 1.0, "min": 0.0000001, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -308,7 +308,7 @@ class MathLog10:
return (math.log10(value),)
class MathDegrees:
class MathDegrees(ComfyNodeABC):
"""
Converts an angle from radians to degrees.
@@ -318,11 +318,11 @@ class MathDegrees:
def INPUT_TYPES(cls):
return {
"required": {
"radians": ("FLOAT", {"default": 0.0}),
"radians": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -331,7 +331,7 @@ class MathDegrees:
return (math.degrees(radians),)
class MathRadians:
class MathRadians(ComfyNodeABC):
"""
Converts an angle from degrees to radians.
@@ -341,11 +341,11 @@ class MathRadians:
def INPUT_TYPES(cls):
return {
"required": {
"degrees": ("FLOAT", {"default": 0.0}),
"degrees": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -354,7 +354,7 @@ class MathRadians:
return (math.radians(degrees),)
class MathFloor:
class MathFloor(ComfyNodeABC):
"""
Returns the floor of a number.
@@ -364,11 +364,11 @@ class MathFloor:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -377,7 +377,7 @@ class MathFloor:
return (math.floor(value),)
class MathCeil:
class MathCeil(ComfyNodeABC):
"""
Returns the ceiling of a number.
@@ -387,11 +387,11 @@ class MathCeil:
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -400,7 +400,7 @@ class MathCeil:
return (math.ceil(value),)
class MathAbs:
class MathAbs(ComfyNodeABC):
"""
Returns the absolute value of a number.
@@ -410,26 +410,20 @@ class MathAbs:
def INPUT_TYPES(cls):
return {
"required": {
"value": (["FLOAT", "INT"], {}),
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
RETURN_TYPES = ("*",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@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"
return True
def calculate(self, value: Union[float, int]) -> tuple[Union[float, int]]:
return (abs(value),)
class MathPi:
class MathPi(ComfyNodeABC):
"""
Returns the mathematical constant π (pi).
@@ -439,7 +433,7 @@ class MathPi:
def INPUT_TYPES(cls):
return {"required": {}}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -448,7 +442,7 @@ class MathPi:
return (math.pi,)
class MathE:
class MathE(ComfyNodeABC):
"""
Returns the mathematical constant e.
@@ -458,7 +452,7 @@ class MathE:
def INPUT_TYPES(cls):
return {"required": {}}
RETURN_TYPES = ("FLOAT",)
RETURN_TYPES = (IO.FLOAT,)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@@ -467,7 +461,7 @@ class MathE:
return (math.e,)
class MathMin:
class MathMin(ComfyNodeABC):
"""
Returns the minimum value among the inputs.
@@ -478,8 +472,8 @@ class MathMin:
def INPUT_TYPES(cls):
return {
"required": {
"value1": (["FLOAT", "INT"], {"default": 0}),
"value2": (["FLOAT", "INT"], {"default": 0}),
"value1": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"value2": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
@@ -488,18 +482,11 @@ class MathMin:
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
for key, value in input_types.items():
if key.startswith("value") and value not in ("FLOAT", "INT"):
return f"{key} must be a FLOAT or INT type"
return True
def calculate(self, value1: Union[float, int], value2: Union[float, int]) -> tuple[Union[float, int]]:
return (min(value1, value2),)
class MathMax:
class MathMax(ComfyNodeABC):
"""
Returns the maximum value among the inputs.
@@ -510,8 +497,8 @@ class MathMax:
def INPUT_TYPES(cls):
return {
"required": {
"value1": (["FLOAT", "INT"], {"default": 0}),
"value2": (["FLOAT", "INT"], {"default": 0}),
"value1": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
"value2": (IO.NUMBER, {"default": 0.0, "widgetType": "FLOAT"}),
}
}
@@ -520,13 +507,6 @@ class MathMax:
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
for key, value in input_types.items():
if key.startswith("value") and value not in ("FLOAT", "INT"):
return f"{key} must be a FLOAT or INT type"
return True
def calculate(self, value1: Union[float, int], value2: Union[float, int]) -> tuple[Union[float, int]]:
return (max(value1, value2),)
+68 -72
View File
@@ -1,9 +1,10 @@
from inspect import cleandoc
import os
import glob
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class PathJoin:
class PathJoin(ComfyNodeABC):
"""
Joins multiple path components into a single path.
@@ -15,14 +16,14 @@ class PathJoin:
def INPUT_TYPES(cls):
return {
"required": {
"path1": ("STRING", {"default": ""}),
"path1": (IO.STRING, {"default": ""}),
},
"optional": {
"path2": ("STRING", {"default": ""}),
"path2": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("path",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -33,7 +34,7 @@ class PathJoin:
return (str(os.path.join(*paths)),)
class PathAbspath:
class PathAbspath(ComfyNodeABC):
"""
Returns the absolute path of a file or directory.
@@ -44,11 +45,11 @@ class PathAbspath:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("absolute_path",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -58,7 +59,7 @@ class PathAbspath:
return (os.path.abspath(path),)
class PathExists:
class PathExists(ComfyNodeABC):
"""
Checks if a path exists in the filesystem.
@@ -69,11 +70,11 @@ class PathExists:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("exists",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -83,7 +84,7 @@ class PathExists:
return (os.path.exists(path),)
class PathIsFile:
class PathIsFile(ComfyNodeABC):
"""
Checks if a path points to a file.
@@ -94,11 +95,11 @@ class PathIsFile:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("is_file",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -108,7 +109,7 @@ class PathIsFile:
return (os.path.isfile(path),)
class PathIsDir:
class PathIsDir(ComfyNodeABC):
"""
Checks if a path points to a directory.
@@ -119,11 +120,11 @@ class PathIsDir:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("is_dir",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -133,7 +134,7 @@ class PathIsDir:
return (os.path.isdir(path),)
class PathGetSize:
class PathGetSize(ComfyNodeABC):
"""
Returns the size of a file in bytes.
@@ -144,11 +145,11 @@ class PathGetSize:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
RETURN_NAMES = ("size_bytes",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -162,7 +163,7 @@ class PathGetSize:
return (os.path.getsize(path),)
class PathSplit:
class PathSplit(ComfyNodeABC):
"""
Splits a path into directory and filename components.
@@ -173,11 +174,11 @@ class PathSplit:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING", "STRING")
RETURN_TYPES = (IO.STRING, IO.STRING)
RETURN_NAMES = ("directory", "filename")
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -187,7 +188,7 @@ class PathSplit:
return os.path.split(path)
class PathSplitExt:
class PathSplitExt(ComfyNodeABC):
"""
Splits a path into name and extension components.
@@ -198,11 +199,11 @@ class PathSplitExt:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING", "STRING")
RETURN_TYPES = (IO.STRING, IO.STRING)
RETURN_NAMES = ("path_without_ext", "extension")
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -212,7 +213,7 @@ class PathSplitExt:
return os.path.splitext(path)
class PathBasename:
class PathBasename(ComfyNodeABC):
"""
Returns the base name of a path.
@@ -223,11 +224,11 @@ class PathBasename:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("basename",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -237,7 +238,7 @@ class PathBasename:
return (os.path.basename(path),)
class PathDirname:
class PathDirname(ComfyNodeABC):
"""
Returns the directory name of a path.
@@ -248,11 +249,11 @@ class PathDirname:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("dirname",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -262,7 +263,7 @@ class PathDirname:
return (os.path.dirname(path),)
class PathGetExtension:
class PathGetExtension(ComfyNodeABC):
"""
Returns the extension of a file.
@@ -273,11 +274,11 @@ class PathGetExtension:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("extension",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -287,7 +288,7 @@ class PathGetExtension:
return (os.path.splitext(path)[1],)
class PathNormalize:
class PathNormalize(ComfyNodeABC):
"""
Normalizes a path.
@@ -299,11 +300,11 @@ class PathNormalize:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("normalized_path",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -313,7 +314,7 @@ class PathNormalize:
return (os.path.normpath(path),)
class PathRelative:
class PathRelative(ComfyNodeABC):
"""
Returns a relative path.
@@ -324,14 +325,14 @@ class PathRelative:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
},
"optional": {
"start": ("STRING", {"default": ""}),
"start": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("relative_path",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -343,7 +344,7 @@ class PathRelative:
return (os.path.relpath(path, start),)
class PathGlob:
class PathGlob(ComfyNodeABC):
"""
Finds paths matching a pattern.
@@ -358,30 +359,25 @@ class PathGlob:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {"default": "*.txt"}),
"pattern": (IO.STRING, {"default": "*.txt"}),
},
"optional": {
"recursive": (["False", "True"], {"default": "False"}),
"recursive": (IO.BOOLEAN, {"default": False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("matching_paths",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "glob_paths"
OUTPUT_IS_LIST = (True,)
def glob_paths(self, pattern: str, recursive: str = "False") -> tuple[list[str]]:
is_recursive = (recursive == "True")
if is_recursive:
# If recursive, use ** pattern with glob.glob's recursive option
return (glob.glob(pattern, recursive=True),)
else:
return (glob.glob(pattern),)
def glob_paths(self, pattern: str, recursive: bool = False) -> tuple[list[str]]:
return (glob.glob(pattern, recursive=recursive),)
class PathExpandVars:
class PathExpandVars(ComfyNodeABC):
"""
Expands environment variables in a path.
@@ -392,11 +388,11 @@ class PathExpandVars:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("expanded_path",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -406,7 +402,7 @@ class PathExpandVars:
return (os.path.expandvars(path),)
class PathGetCwd:
class PathGetCwd(ComfyNodeABC):
"""
Returns the current working directory.
@@ -416,7 +412,7 @@ class PathGetCwd:
def INPUT_TYPES(cls):
return {"required": {}}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("current_directory",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -426,7 +422,7 @@ class PathGetCwd:
return (os.getcwd(),)
class PathListDir:
class PathListDir(ComfyNodeABC):
"""
Lists the contents of a directory.
@@ -439,22 +435,22 @@ class PathListDir:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
},
"optional": {
"files_only": (["False", "True"], {"default": "False"}),
"dirs_only": (["False", "True"], {"default": "False"}),
"files_only": (IO.BOOLEAN, {"default": False}),
"dirs_only": (IO.BOOLEAN, {"default": False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("entries",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "list_directory"
OUTPUT_IS_LIST = (True,)
def list_directory(self, path: str, files_only: str = "False", dirs_only: str = "False") -> tuple[list[str]]:
def list_directory(self, path: str, files_only: str = False, dirs_only: str = False) -> tuple[list[str]]:
if not path:
path = os.getcwd()
@@ -465,15 +461,15 @@ class PathListDir:
entries = os.listdir(path)
if files_only == "True":
if files_only:
entries = [e for e in entries if os.path.isfile(os.path.join(path, e))]
elif dirs_only == "True":
elif dirs_only:
entries = [e for e in entries if os.path.isdir(os.path.join(path, e))]
return (entries,)
class PathIsAbsolute:
class PathIsAbsolute(ComfyNodeABC):
"""
Checks if a path is absolute.
@@ -484,11 +480,11 @@ class PathIsAbsolute:
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {"default": ""}),
"path": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("is_absolute",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -498,7 +494,7 @@ class PathIsAbsolute:
return (os.path.isabs(path),)
class PathCommonPrefix:
class PathCommonPrefix(ComfyNodeABC):
"""
Finds the common prefix of multiple paths.
@@ -508,14 +504,14 @@ class PathCommonPrefix:
def INPUT_TYPES(cls):
return {
"required": {
"path1": ("STRING", {"default": ""}),
"path1": (IO.STRING, {"default": ""}),
},
"optional": {
"path2": ("STRING", {"default": ""}),
"path2": (IO.STRING, {"default": ""}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
RETURN_NAMES = ("common_prefix",)
CATEGORY = "Basic/path"
DESCRIPTION = cleandoc(__doc__ or "")
+106 -26
View File
@@ -1,7 +1,8 @@
from inspect import cleandoc
import re
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class RegexSearchGroups:
class RegexSearchGroupsDataList(ComfyNodeABC):
"""
Searches the string for a match to the pattern and returns a LIST of match groups.
If no match is found, it returns an empty LIST.
@@ -10,8 +11,35 @@ class RegexSearchGroups:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {}),
"string": ("STRING", {}),
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
RETURN_TYPES = (IO.STRING,)
CATEGORY = "Basic/STRING/regex"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "search_groups"
OUTPUT_IS_LIST = (True,)
def search_groups(self, pattern: str, string: str) -> tuple[list[str]]:
match = re.search(pattern, string)
if match:
return (list(match.groups()),)
return ([],)
class RegexSearchGroupsList(ComfyNodeABC):
"""
Searches the string for a match to the pattern and returns a data list of match groups.
If no match is found, it returns an empty data list.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
@@ -27,7 +55,7 @@ class RegexSearchGroups:
return ([],)
class RegexGroupDict:
class RegexGroupDict(ComfyNodeABC):
"""
Searches the string with the given pattern and returns a DICT of named groups.
If no match is found, it returns an empty DICT.
@@ -36,8 +64,8 @@ class RegexGroupDict:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {}),
"string": ("STRING", {}),
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
@@ -53,7 +81,7 @@ class RegexGroupDict:
return ({},)
class RegexFindall:
class RegexFindallDataList(ComfyNodeABC):
"""
Returns all non-overlapping matches of a pattern in the string as a list of strings.
"""
@@ -61,8 +89,31 @@ class RegexFindall:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {}),
"string": ("STRING", {}),
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
RETURN_TYPES = (IO.STRING,)
CATEGORY = "Basic/STRING/regex"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "findall"
OUTPUT_IS_LIST = (True,)
def findall(self, pattern: str, string: str) -> tuple[list[str]]:
return (re.findall(pattern, string),)
class RegexFindallList(ComfyNodeABC):
"""
Returns all non-overlapping matches of a pattern in the string as a list of strings.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
@@ -75,7 +126,7 @@ class RegexFindall:
return (re.findall(pattern, string),)
class RegexSplit:
class RegexSplitDataList(ComfyNodeABC):
"""
Splits the string at each match of the pattern and returns a list of substrings.
"""
@@ -83,8 +134,31 @@ class RegexSplit:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {}),
"string": ("STRING", {}),
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
RETURN_TYPES = (IO.STRING,)
CATEGORY = "Basic/STRING/regex"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "split"
OUTPUT_IS_LIST = (True,)
def split(self, pattern: str, string: str) -> tuple[list[str]]:
return (re.split(pattern, string),)
class RegexSplitList(ComfyNodeABC):
"""
Splits the string at each match of the pattern and returns a list of substrings.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
@@ -97,7 +171,7 @@ class RegexSplit:
return (re.split(pattern, string),)
class RegexSub:
class RegexSub(ComfyNodeABC):
"""
Substitutes matches of the pattern in the string with a replacement string.
"""
@@ -105,14 +179,14 @@ class RegexSub:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {}),
"repl": ("STRING", {}),
"string": ("STRING", {}),
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
"repl": (IO.STRING, {}),
"count": ("INT", {"default": 0}), # 0 means replace all occurrences
}
}
RETURN_TYPES = ("STRING",)
RETURN_TYPES = (IO.STRING,)
CATEGORY = "Basic/STRING/regex"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "sub"
@@ -121,7 +195,7 @@ class RegexSub:
return (re.sub(pattern, repl, string, count),)
class RegexTest:
class RegexTest(ComfyNodeABC):
"""
Tests whether a given regex pattern matches any part of the input string.
Returns True if a match is found, otherwise False.
@@ -130,8 +204,8 @@ class RegexTest:
def INPUT_TYPES(cls):
return {
"required": {
"pattern": ("STRING", {}),
"string": ("STRING", {}),
"string": (IO.STRING, {}),
"pattern": (IO.STRING, {}),
}
}
@@ -146,19 +220,25 @@ class RegexTest:
NODE_CLASS_MAPPINGS = {
"Basic data handling: RegexSearchGroups": RegexSearchGroups,
"Basic data handling: RegexSearchGroupsDataList": RegexSearchGroupsDataList,
"Basic data handling: RegexSearchGroupsList": RegexSearchGroupsList,
"Basic data handling: RegexGroupDict": RegexGroupDict,
"Basic data handling: RegexFindall": RegexFindall,
"Basic data handling: RegexSplit": RegexSplit,
"Basic data handling: RegexFindallDataList": RegexFindallDataList,
"Basic data handling: RegexFindallList": RegexFindallList,
"Basic data handling: RegexSplitDataList": RegexSplitDataList,
"Basic data handling: RegexSplitList": RegexSplitList,
"Basic data handling: RegexSub": RegexSub,
"Basic data handling: RegexTest": RegexTest,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: RegexSearchGroups": "search groups",
"Basic data handling: RegexSearchGroupsDataList": "search groups (data list)",
"Basic data handling: RegexSearchGroupsList": "search groups (LIST)",
"Basic data handling: RegexGroupDict": "search named groups",
"Basic data handling: RegexFindall": "find all",
"Basic data handling: RegexSplit": "split",
"Basic data handling: RegexFindallDataList": "find all (data list)",
"Basic data handling: RegexFindallList": "find all (LIST)",
"Basic data handling: RegexSplitDataList": "split (data list)",
"Basic data handling: RegexSplitList": "split (LIST)",
"Basic data handling: RegexSub": "substitute",
"Basic data handling: RegexTest": "test",
}
+29 -53
View File
@@ -1,7 +1,8 @@
from typing import Any
from inspect import cleandoc
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
class SetAdd:
class SetAdd(ComfyNodeABC):
"""
Adds an item to a SET.
@@ -13,7 +14,7 @@ class SetAdd:
return {
"required": {
"set": ("SET", {}),
"item": ("*", {}),
"item": (IO.ANY, {}),
}
}
@@ -28,7 +29,7 @@ class SetAdd:
return (result,)
class SetRemove:
class SetRemove(ComfyNodeABC):
"""
Removes an item from a SET.
@@ -41,11 +42,11 @@ class SetRemove:
return {
"required": {
"set": ("SET", {}),
"item": ("*", {}),
"item": (IO.ANY, {}),
}
}
RETURN_TYPES = ("SET", "BOOLEAN")
RETURN_TYPES = ("SET", IO.BOOLEAN)
RETURN_NAMES = ("set", "success")
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -60,7 +61,7 @@ class SetRemove:
return result, False
class SetDiscard:
class SetDiscard(ComfyNodeABC):
"""
Removes an item from a SET if it is present.
@@ -72,7 +73,7 @@ class SetDiscard:
return {
"required": {
"set": ("SET", {}),
"item": ("*", {}),
"item": (IO.ANY, {}),
}
}
@@ -87,7 +88,7 @@ class SetDiscard:
return (result,)
class SetPop:
class SetPop(ComfyNodeABC):
"""
Removes and returns an arbitrary item from a SET.
@@ -103,7 +104,7 @@ class SetPop:
}
}
RETURN_TYPES = ("SET", "*")
RETURN_TYPES = ("SET", IO.ANY)
RETURN_NAMES = ("set", "item")
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -118,30 +119,7 @@ class SetPop:
return result, None
class SetClear:
"""
Removes all items from a SET.
This node takes a SET as input and returns a new empty SET.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"set": ("SET", {}),
}
}
RETURN_TYPES = ("SET",)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "clear"
def clear(self, set: set[Any]) -> tuple[set[Any]]:
return (set.__class__(),)
class SetUnion:
class SetUnion(ComfyNodeABC):
"""
Returns the union of two or more SETs.
@@ -179,7 +157,7 @@ class SetUnion:
return (result,)
class SetIntersection:
class SetIntersection(ComfyNodeABC):
"""
Returns the intersection of two or more SETs.
@@ -217,7 +195,7 @@ class SetIntersection:
return (result,)
class SetDifference:
class SetDifference(ComfyNodeABC):
"""
Returns the difference between two SETs.
@@ -244,7 +222,7 @@ class SetDifference:
return (result,)
class SetSymmetricDifference:
class SetSymmetricDifference(ComfyNodeABC):
"""
Returns the symmetric difference between two SETs.
@@ -271,7 +249,7 @@ class SetSymmetricDifference:
return (result,)
class SetIsSubset:
class SetIsSubset(ComfyNodeABC):
"""
Checks if set1 is a subset of set2.
@@ -287,7 +265,7 @@ class SetIsSubset:
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("is_subset",)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -297,7 +275,7 @@ class SetIsSubset:
return (set1.issubset(set2),)
class SetIsSuperset:
class SetIsSuperset(ComfyNodeABC):
"""
Checks if set1 is a superset of set2.
@@ -313,7 +291,7 @@ class SetIsSuperset:
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("is_superset",)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -323,7 +301,7 @@ class SetIsSuperset:
return (set1.issuperset(set2),)
class SetIsDisjoint:
class SetIsDisjoint(ComfyNodeABC):
"""
Checks if two SETs have no elements in common.
@@ -338,7 +316,7 @@ class SetIsDisjoint:
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("is_disjoint",)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -348,7 +326,7 @@ class SetIsDisjoint:
return (set1.isdisjoint(set2),)
class SetContains:
class SetContains(ComfyNodeABC):
"""
Checks if a SET contains a specified value.
@@ -360,11 +338,11 @@ class SetContains:
return {
"required": {
"set": ("SET", {}),
"value": ("*", {}),
"value": (IO.ANY, {}),
}
}
RETURN_TYPES = ("BOOLEAN",)
RETURN_TYPES = (IO.BOOLEAN,)
RETURN_NAMES = ("contains",)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -374,7 +352,7 @@ class SetContains:
return (value in set,)
class SetLength:
class SetLength(ComfyNodeABC):
"""
Returns the number of items in a SET.
@@ -388,7 +366,7 @@ class SetLength:
}
}
RETURN_TYPES = ("INT",)
RETURN_TYPES = (IO.INT,)
RETURN_NAMES = ("length",)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
@@ -398,7 +376,7 @@ class SetLength:
return (len(set),)
class ListToSet:
class ListToSet(ComfyNodeABC):
"""
Converts a LIST into a SET.
@@ -422,7 +400,7 @@ class ListToSet:
return (set(list),)
class SetToDataList:
class SetToDataList(ComfyNodeABC):
"""
Converts a SET object into a ComfyUI data list.
@@ -438,7 +416,7 @@ class SetToDataList:
}
}
RETURN_TYPES = ("*",)
RETURN_TYPES = (IO.ANY,)
CATEGORY = "Basic/SET"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "convert"
@@ -448,7 +426,7 @@ class SetToDataList:
return (list(set),)
class SetToList:
class SetToList(ComfyNodeABC):
"""
Converts a SET into a LIST.
@@ -478,7 +456,6 @@ NODE_CLASS_MAPPINGS = {
"Basic data handling: SetRemove": SetRemove,
"Basic data handling: SetDiscard": SetDiscard,
"Basic data handling: SetPop": SetPop,
"Basic data handling: SetClear": SetClear,
"Basic data handling: SetUnion": SetUnion,
"Basic data handling: SetIntersection": SetIntersection,
"Basic data handling: SetDifference": SetDifference,
@@ -497,7 +474,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Basic data handling: SetRemove": "remove",
"Basic data handling: SetDiscard": "discard",
"Basic data handling: SetPop": "pop",
"Basic data handling: SetClear": "clear",
"Basic data handling: SetUnion": "union",
"Basic data handling: SetIntersection": "intersection",
"Basic data handling: SetDifference": "difference",
File diff suppressed because it is too large Load Diff