From 139025f0fd71da81f9a374cba1ad736c8f423289 Mon Sep 17 00:00:00 2001 From: "kosinkadink1@gmail.com" Date: Mon, 14 Jul 2025 01:03:21 -0500 Subject: [PATCH] Create ComfyTypeI that only has as an input, improved hints on Boolean, Int, and Combos --- comfy_api/v3/io.py | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/comfy_api/v3/io.py b/comfy_api/v3/io.py index 135d9bb8c..8919dcd33 100644 --- a/comfy_api/v3/io.py +++ b/comfy_api/v3/io.py @@ -98,11 +98,9 @@ class NumberDisplay(str, Enum): slider = "slider" -class ComfyType: +class ComfyType(ABC): Type = Any io_type: str = None - Input: type[InputV3] = None - Output: type[OutputV3] = None # NOTE: this is a workaround to make the decorator return the correct type T = TypeVar("T", bound=type) @@ -119,8 +117,10 @@ def comfytype(io_type: str, **kwargs): if isinstance(cls, ComfyType) or issubclass(cls, ComfyType): # clone Input and Output classes to avoid modifying the original class new_cls = cls - new_cls.Input = copy_class(new_cls.Input) - new_cls.Output = copy_class(new_cls.Output) + if hasattr(new_cls, "Input"): + new_cls.Input = copy_class(new_cls.Input) + if hasattr(new_cls, "Output"): + new_cls.Output = copy_class(new_cls.Output) else: # copy class attributes except for special ones that shouldn't be in type() cls_dict = { @@ -128,9 +128,9 @@ def comfytype(io_type: str, **kwargs): if k not in ('__dict__', '__weakref__', '__module__', '__doc__') } # new class - new_cls: ComfyType = type( + new_cls: ComfyTypeIO = type( cls.__name__, - (cls, ComfyType), + (cls, ComfyTypeIO), cls_dict ) # metadata preservation @@ -139,14 +139,14 @@ def comfytype(io_type: str, **kwargs): # assign ComfyType attributes, if needed # NOTE: do we need __ne__ trick for io_type? (see node_typing.IO.__ne__ for details) new_cls.io_type = io_type - if new_cls.Input is not None: + if hasattr(new_cls, "Input") and new_cls.Input is not None: new_cls.Input.Parent = new_cls - if new_cls.Output is not None: + if hasattr(new_cls, "Output") and new_cls.Output is not None: new_cls.Output.Parent = new_cls return new_cls return decorator -def Custom(io_type: str) -> type[ComfyType]: +def Custom(io_type: str) -> type[ComfyTypeIO]: '''Create a ComfyType for a custom io_type.''' @comfytype(io_type=io_type) class CustomComfyType(ComfyTypeIO): @@ -227,10 +227,13 @@ class OutputV3(IO_V3): self.is_output_list = is_output_list -class ComfyTypeIO(ComfyType): - '''ComfyType subclass that has default Input and Output classes; useful for basic Inputs and Outputs.''' +class ComfyTypeI(ComfyType): + '''ComfyType subclass that only has a default Input class - intended for types that only have Inputs.''' class Input(InputV3): ... + +class ComfyTypeIO(ComfyTypeI): + '''ComfyType subclass that has default Input and Output classes; useful for types with both Inputs and Outputs.''' class Output(OutputV3): ... @@ -297,7 +300,7 @@ class NodeStateLocal(NodeState): @comfytype(io_type="BOOLEAN") -class Boolean: +class Boolean(ComfyTypeIO): Type = bool class Input(WidgetInputV3): @@ -316,11 +319,8 @@ class Boolean: "label_off": self.label_off, }) - class Output(OutputV3): - ... - @comfytype(io_type="INT") -class Int: +class Int(ComfyTypeIO): Type = int class Input(WidgetInputV3): @@ -345,9 +345,6 @@ class Int: "display": self.display_mode, }) - class Output(OutputV3): - ... - @comfytype(io_type="FLOAT") class Float(ComfyTypeIO): Type = float @@ -395,7 +392,7 @@ class String(ComfyTypeIO): }) @comfytype(io_type="COMBO") -class Combo(ComfyType): +class Combo(ComfyTypeI): Type = str class Input(WidgetInputV3): """Combo input (dropdown).""" @@ -426,7 +423,7 @@ class Combo(ComfyType): @comfytype(io_type="COMBO") -class MultiCombo(ComfyType): +class MultiCombo(ComfyTypeI): '''Multiselect Combo input (dropdown for selecting potentially more than one value).''' # TODO: something is wrong with the serialization, frontend does not recognize it as multiselect Type = list[str]