Files
TashaSkyUp-EternalKernelPyt…/basic.py
T
Tasha Upchurch 35b3ec4f66 Add nodes for flexible typing and conversion to Any
This commit adds several new nodes to enable flexible typing and conversion between types:

- ValueToAny - Converts primitive values like ints, floats, strings, bools to Any type
- IterableToAny - Converts iterable values like lists, dicts to Any
- CallableToAny - Converts callables like functions to Any
- ObjectToAny - Converts tensor objects like images, latents etc to Any

The motivation is to allow passing different types flexibly into functions using Any typing. This enables writing functions in a more generic way by accepting Any instead of specific types.

The nodes convert the input values to Any and return debug info on what was converted. This allows tracing what types entered a function even if the function uses generic Any types.

No breaking changes, new nodes added:
- ValueToAny
- IterableToAny
- CallableToAny
- ObjectToAny

These provide building blocks for more flexible typing, opening up possibilities like:

- Writing utility and processing functions accepting Any instead of specific types
- Calling functions dynamically with values of different types
- Tracing and logging what types passed through a function

Next steps could include AnyToValue nodes, more specialized Any converters, and exploring uses for generic functions.
2023-09-18 17:18:35 -04:00

309 lines
8.3 KiB
Python

class MultilineStringNode:
"""Noe that displays multiline text box"""
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"Text": ("STRING", {
"default": "",
"multiline": True,
}),
}
}
RETURN_TYPES = ("STRING", "INT", "FLOAT", "LIST")
FUNCTION = "get_value"
CATEGORY = "text"
def get_value(self, Text):
return (Text,)
class StrBreakout:
""" node that breaks out a string into a:
- Boolean
- int
- float
- [string]
- splitlines()
- split(",")
the first value is a description of the transformations tried
"""
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"Text": ("STRING", {
"default": "",
}),
}
}
RETURN_TYPES = ("STRING", "BOOL", "INT", "FLOAT", "LIST", "LIST", "LIST",)
FUNCTION = "get_value"
CATEGORY = "text"
def get_value(self, Text):
out_bool = False
out_int = 0
out_float = 0.0
out_list = []
out_lines = []
out_comma = []
notes = []
try:
out_bool = bool(Text)
notes.append(f"bool worked")
except Exception as e:
notes.append(f"bool failed: {e}")
try:
out_int = int(Text)
notes.append(f"int worked")
except Exception as e:
notes.append(f"int failed: {e}")
pass
try:
out_float = float(Text)
notes.append(f"float worked")
except Exception as e:
pass
try:
out_list = list(Text)
notes.append(f"list worked")
except Exception as e:
notes.append(f"list failed: {e}")
pass
try:
out_lines = Text.splitlines()
notes.append(f"splitlines worked")
except Exception as e:
notes.append(f"splitlines failed: {e}")
pass
try:
out_comma = Text.split(",")
notes.append(f"split(',') worked")
except Exception as e:
notes.append(f"split(',') failed: {e}")
pass
return ("\n".join(notes), out_bool, out_int, out_float, out_list, out_lines, out_comma,)
class IntBreakout:
""" node that breaks out an int into a:
- Boolean
- str(int)
- float
- [int]
- list(range(int))
- [None] * int
the first value is a description of the transformations tried
"""
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"Int": ("INT", {
"default": 0,
}),
}
}
RETURN_TYPES = ("STRING", "BOOL", "STRING", "FLOAT", "LIST", "LIST", "LIST",)
FUNCTION = "get_value"
CATEGORY = "text"
def get_value(self, Int):
out_bool = False
out_str = ""
out_float = 0.0
out_list = []
out_range = []
out_none = []
notes = []
try:
out_bool = bool(Int)
notes.append(f"bool worked")
except Exception as e:
notes.append(f"bool failed: {e}")
try:
out_str = str(Int)
notes.append(f"str worked")
except Exception as e:
notes.append(f"str failed: {e}")
pass
try:
out_float = float(Int)
notes.append(f"float worked")
except Exception as e:
pass
try:
out_list = list(Int)
notes.append(f"list worked")
except Exception as e:
notes.append(f"list failed: {e}")
pass
try:
out_range = list(range(Int))
notes.append(f"range worked")
except Exception as e:
notes.append(f"range failed: {e}")
pass
try:
out_none = [None] * Int
notes.append(f"[None] * worked")
except Exception as e:
notes.append(f"[None] * failed: {e}")
pass
return ("\n".join(notes), out_bool, out_str, out_float, out_list, out_range, out_none,)
class ValueToAny:
"""takes INT,STRING,FLOAT,BOOL, and returns the value coded as *"""
@classmethod
def INPUT_TYPES(cls):
return {
"optional": {
"INT": ("INT", {"default": None, }),
"FLOAT": ("FLOAT", {"default": None, }),
"STRING": ("STRING", {"default": None, }),
"BOOL": ("BOOL", {"default": None, }),
}
}
RETURN_TYPES = ("*", "STRING",)
RETURN_NAMES = ("*", "debug info",)
FUNCTION = "get_value"
CATEGORY = "conversion"
def get_value(self, INT=None, FLOAT=None, STRING=None, BOOL=None):
if INT:
dbg = f"found INT: {INT}"
return (INT, dbg,)
if FLOAT:
dbg = f"found FLOAT: {FLOAT}"
return (FLOAT, dbg,)
if STRING:
dbg = f"found STRING: {STRING}"
return (STRING, dbg,)
if BOOL:
dbg = f"found BOOL: {BOOL}"
return (BOOL, dbg,)
dbg = f"found nothing, will return the first value that is not None; from INT,FLOAT,STRING,BOOL"
return (None, dbg)
class IterableToAny:
"""takes LIST,DICT, and returns the value coded as *"""
@classmethod
def INPUT_TYPES(cls):
return {
"optional": {
"LIST": ("LIST", {"default": None, }),
"DICT": ("DICT", {"default": None, }),
}
}
RETURN_TYPES = ("*", "STRING",)
RETURN_NAMES = ("*", "debug info",)
FUNCTION = "get_value"
CATEGORY = "conversion"
def get_value(self, LIST=None, DICT=None):
if LIST:
dbg = f"found LIST: {LIST}"
return (LIST, dbg,)
if DICT:
dbg = f"found DICT: {DICT}"
return (DICT, dbg,)
dbg = f"found nothing, will return the first value that is not None; from LIST,DICT"
return (None, dbg)
class CallableToAny:
"""takes FUNC, (others soon) and returns the value coded as *"""
@classmethod
def INPUT_TYPES(cls):
return {
"optional": {
"FUNC": ("FUNC", {"default": None, }),
}
}
RETURN_TYPES = ("*", "STRING",)
RETURN_NAMES = ("*", "debug info",)
FUNCTION = "get_value"
CATEGORY = "conversion"
def get_value(self, FUNC=None):
if FUNC:
dbg = f"found FUNC: {FUNC}"
return (FUNC, dbg,)
dbg = f"found nothing, will return the first value that is not None; from FUNC"
return (None, dbg)
class ObjectToAny:
""" takes non-primitive objects like TENSORS and returns the value coded as *"""
@classmethod
def INPUT_TYPES(cls):
return {
"optional": {
"LATENT": ("LATENT", {"default": None, }),
"CONDITIONING": ("CONDITIONING", {"default": None, }),
"IMAGE": ("IMAGE", {"default": None, }),
"MASK": ("MASK", {"default": None, }),
}
}
RETURN_TYPES = ("*", "STRING",)
RETURN_NAMES = ("*", "debug info",)
FUNCTION = "get_value"
CATEGORY = "conversion"
def get_value(self, LATENT=None, CONDITIONING=None, IMAGE=None, MASK=None):
if LATENT:
dbg = f"found LATENT: {LATENT}"
return (LATENT, dbg,)
if CONDITIONING:
dbg = f"found CONDITIONING: {CONDITIONING}"
return (CONDITIONING, dbg,)
if IMAGE:
dbg = f"found IMAGE: {IMAGE}"
return (IMAGE, dbg,)
if MASK:
dbg = f"found MASK: {MASK}"
return (MASK, dbg,)
dbg = f"found nothing, will return the first value that is not None; from LATENT,CONDITIONING,IMAGE,MASK"
return (None, dbg)
NODE_CLASS_MAPPINGS = {}
NODE_CLASS_MAPPINGS["MultilineStringNode"] = MultilineStringNode
NODE_CLASS_MAPPINGS["StrBreakout"] = StrBreakout
NODE_CLASS_MAPPINGS["IntBreakout"] = IntBreakout
NODE_CLASS_MAPPINGS["ValueToAny"] = ValueToAny
NODE_CLASS_MAPPINGS["IterableToAny"] = IterableToAny
NODE_CLASS_MAPPINGS["CallableToAny"] = CallableToAny
NODE_CLASS_MAPPINGS["ObjectToAny"] = ObjectToAny