Files
2023-09-28 19:07:42 -04:00

173 lines
5.2 KiB
Python

import inspect
import textwrap
import nodes
class AnyType(str):
def __ne__(self, __value: object) -> bool:
return False
any_typ = AnyType("*")
class SrlConditionalInterrupt:
"""Interrupt processing if the boolean input is true. Pass through the other input."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"interrupt": ("BOOLEAN", {"forceInput": True}),
"inp": (any_typ,),
},
}
RETURN_TYPES = (any_typ,)
RETURN_NAMES = ("output",)
FUNCTION = "doit"
CATEGORY = "utils"
def doit(self, interrupt, inp):
if interrupt:
nodes.interrupt_processing()
return (inp,)
class SrlFormatString:
"""Use Python f-string syntax to generate a string using the inputs as the arguments."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"format": ("STRING", {
"multiline": False,
"default": "first input via str(): {}, second input via repr(): {!r}, third input by index: {2}, fifth input by name: {in4}",
}),
},
"optional": {
"in0": (any_typ,),
"in1": (any_typ,),
"in2": (any_typ,),
"in3": (any_typ,),
"in4": (any_typ,),
},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "doit"
CATEGORY = "utils"
def doit(self, format, **kwargs):
# Allow referencing arguments both by name and index.
return (format.format(*kwargs.values(), **kwargs),)
class SrlEval:
"""Evaluate any Python code as a function with the given inputs."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"parameters": ("STRING", {
"multiline": False,
"default": "a, b=None, c=\"foo\", *rest",
"dynamicPrompts": False,
}),
"code": ("STRING", {
"multiline": True,
"default": "code goes here\nreturn a + b",
"dynamicPrompts": False,
}),
},
"optional": {
"arg0": (any_typ,),
"arg1": (any_typ,),
"arg2": (any_typ,),
"arg3": (any_typ,),
"arg4": (any_typ,),
}
}
RETURN_TYPES = (any_typ,)
FUNCTION = "doit"
CATEGORY = "utils"
def doit(self, parameters, code, **kw):
# Indent the code for the main body of the function
func_code = textwrap.indent(code, " ")
source = f"def func({parameters}):\n{func_code}"
# The provided code can mutate globals or really do anything, but ComfyUI isn't secure to begin with.
loc = {}
exec(source, globals(), loc)
func = loc["func"]
argspec = inspect.getfullargspec(func)
# We don't allow variable keyword arguments or keyword only arguments, but we do allow varargs
assert argspec.varkw is None
assert not argspec.kwonlyargs
input_names = list(self.INPUT_TYPES()["optional"].keys())
parameter_names = argspec.args
# Convert the list of defaults into a dictionary to make it easier to use
default_list = argspec.defaults if argspec.defaults is not None else []
defaults = {parameter_name: default for parameter_name, default in zip(parameter_names[-len(default_list):], default_list)}
# We handle substituting default values ourselves in order to support *args
args = [kw[input_name] if input_name in kw else defaults[parameter_name] for parameter_name, input_name in zip(parameter_names, input_names)]
# Support *args
if argspec.varargs is not None:
unnamed_inputs = input_names[len(argspec.args):]
# I considered requiring the remaining inputs to be contiguous, but I don't think it's helpful.
args += [kw[input_name] for input_name in unnamed_inputs if input_name in kw]
ret = func(*args)
return (ret,)
class SrlFilterImageList:
"""Filter an image list based on a list of bools"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"keep": ("BOOLEAN", {"forceInput": True}),
}
}
RETURN_TYPES = ("IMAGE",)
INPUT_IS_LIST = True
OUTPUT_IS_LIST = (True,)
FUNCTION = "doit"
def doit(self, images, keep):
return ([im for im, k in zip(images, keep) if k],)
# A dictionary that contains all nodes you want to export with their names
# NOTE: names should be globally unique
NODE_CLASS_MAPPINGS = {
"SRL Conditional Interrrupt": SrlConditionalInterrupt,
"SRL Format String": SrlFormatString,
"SRL Eval": SrlEval,
"SRL Filter Image List": SrlFilterImageList,
}
# A dictionary that contains the friendly/humanly readable titles for the nodes
NODE_DISPLAY_NAME_MAPPINGS = {
"SrlConditionalInterrupt": "SRL Conditional Interrupt",
"SrlFormatString": "SRL Format String",
"SrlEval": "SRL Eval",
"SrlFilterImageList": "SRL Filter Image List",
}