Bum version to 0.2.0 as most nodes should be stable now.
Consolidate all nodes.
This commit is contained in:
+1
-1
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),)
|
||||
|
||||
|
||||
@@ -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 "")
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user