Merge pull request #9124 from comfyanonymous/v3-definition-wip

V3 update - fixed ComfyExtension, removed v3/v1 test nodes from loading
This commit is contained in:
Jedrzej Kosinski
2025-07-30 19:46:33 -07:00
committed by GitHub
4 changed files with 7 additions and 110 deletions

View File

@@ -6,7 +6,7 @@ from comfy_api.latest import (
)
from typing import Type, TYPE_CHECKING
from comfy_api.internal.async_to_sync import create_sync_class
from comfy_api.latest import io, ui #noqa: F401
from comfy_api.latest import io, ui, ComfyExtension #noqa: F401
class ComfyAPIAdapter_v0_0_2(ComfyAPI_latest):
@@ -41,4 +41,5 @@ __all__ = [
"Input",
"InputImpl",
"Types",
"ComfyExtension",
]

View File

@@ -1,77 +0,0 @@
import torch
from comfy.comfy_types.node_typing import ComfyNodeABC, IO
import asyncio
from comfy.utils import ProgressBar
import time
class TestNode(ComfyNodeABC):
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": (IO.IMAGE,),
"some_int": (IO.INT, {"display_name": "new_name",
"min": 0, "max": 127, "default": 42,
"tooltip": "My tooltip 😎", "display": "slider"}),
"combo": (IO.COMBO, {"options": ["a", "b", "c"], "tooltip": "This is a combo input"}),
"combo2": (IO.COMBO, {"options": ["a", "b", "c"], "multi_select": True, "tooltip": "This is a combo input"}),
},
"optional": {
"xyz": ("XYZ",),
"mask": (IO.MASK,),
}
}
RETURN_TYPES = (IO.INT, IO.IMAGE)
RETURN_NAMES = ("INT", "img🖼")
OUTPUT_TOOLTIPS = (None, "This is an image")
FUNCTION = "do_thing"
OUTPUT_NODE = True
CATEGORY = "v3 nodes"
def do_thing(self, image: torch.Tensor, some_int: int, combo: str, combo2: list[str], xyz=None, mask: torch.Tensor=None):
return (some_int, image)
class TestSleep(ComfyNodeABC):
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": (IO.ANY, {}),
"seconds": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 9999.0, "step": 0.01, "tooltip": "The amount of seconds to sleep."}),
},
"hidden": {
"unique_id": "UNIQUE_ID",
},
}
RETURN_TYPES = (IO.ANY,)
FUNCTION = "sleep"
CATEGORY = "_for_testing"
async def sleep(self, value, seconds, unique_id):
pbar = ProgressBar(seconds, node_id=unique_id)
start = time.time()
expiration = start + seconds
now = start
while now < expiration:
now = time.time()
pbar.update_absolute(now - start)
await asyncio.sleep(0.02)
return (value,)
NODE_CLASS_MAPPINGS = {
"V1TestNode1": TestNode,
"V1TestSleep": TestSleep,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"V1TestNode1": "V1 Test Node",
"V1TestSleep": "V1 Test Sleep",
}

View File

@@ -1,6 +1,7 @@
import torch
import time
from comfy_api.latest import io, ui, _io, ComfyExtension
from comfy_api.latest import io, ui, _io
from comfy_api.latest import ComfyExtension
import logging # noqa
import comfy.utils
import asyncio
@@ -35,22 +36,6 @@ class V3TestNode(io.ComfyNode):
io.MultiCombo.Input("combo2", options=["a","b","c"]),
io.MultiType.Input(io.Int.Input("int_multitype", display_name="haha"), types=[io.Float]),
io.MultiType.Input("multitype", types=[io.Mask, io.Float, io.Int], optional=True),
# ComboInput("combo", image_upload=True, image_folder=FolderType.output,
# remote=RemoteOptions(
# route="/internal/files/output",
# refresh_button=True,
# ),
# tooltip="This is a combo input"),
# IntegerInput("some_int", display_name="new_name", min=0, tooltip="My tooltip 😎", display=NumberDisplay.slider, ),
# ComboDynamicInput("mask", behavior=InputBehavior.optional),
# IntegerInput("some_int", display_name="new_name", min=0, tooltip="My tooltip 😎", display=NumberDisplay.slider,
# dependent_inputs=[ComboDynamicInput("mask", behavior=InputBehavior.optional)],
# dependent_values=[lambda my_value: IO.STRING if my_value < 5 else IO.NUMBER],
# ),
# ["option1", "option2". "option3"]
# ComboDynamicInput["sdfgjhl", [ComboDynamicOptions("option1", [IntegerInput("some_int", display_name="new_name", min=0, tooltip="My tooltip 😎", display=NumberDisplay.slider, ImageInput(), MaskInput(), String()]),
# CombyDynamicOptons("option2", [])
# ]]
],
outputs=[
io.Int.Output(),

View File

@@ -30,7 +30,7 @@ import comfy.controlnet
from comfy.comfy_types import IO, ComfyNodeABC, InputTypeDict, FileLocator
from comfy_api.internal import register_versions, ComfyAPIWithVersion
from comfy_api.version_list import supported_versions
from comfy_api.latest import io
from comfy_api.latest import io, ComfyExtension
import comfy.clip_vision
@@ -2174,7 +2174,7 @@ async def load_custom_node(module_path: str, ignore=set(), module_parent="custom
extension = await entrypoint()
else:
extension = entrypoint()
if not isinstance(extension, io.ComfyExtension):
if not isinstance(extension, ComfyExtension):
logging.warning(f"comfy_entrypoint in {module_path} did not return a ComfyExtension, skipping.")
return False
node_list = await extension.get_node_list()
@@ -2189,20 +2189,10 @@ async def load_custom_node(module_path: str, ignore=set(), module_parent="custom
node_cls.RELATIVE_PYTHON_MODULE = "{}.{}".format(module_parent, get_module_name(module_path))
if schema.display_name is not None:
NODE_DISPLAY_NAME_MAPPINGS[schema.node_id] = schema.display_name
return True
except Exception as e:
logging.warning(f"Error while calling comfy_entrypoint in {module_path}: {e}")
return False
# V3 node definition
elif getattr(module, "NODES_LIST", None) is not None:
for node_cls in module.NODES_LIST:
node_cls: io.ComfyNode
schema = node_cls.GET_SCHEMA()
if schema.node_id not in ignore:
NODE_CLASS_MAPPINGS[schema.node_id] = node_cls
node_cls.RELATIVE_PYTHON_MODULE = "{}.{}".format(module_parent, get_module_name(module_path))
if schema.display_name is not None:
NODE_DISPLAY_NAME_MAPPINGS[schema.node_id] = schema.display_name
return True
else:
logging.warning(f"Skip {module_path} module for custom nodes due to the lack of NODE_CLASS_MAPPINGS or NODES_LIST (need one).")
return False
@@ -2330,8 +2320,6 @@ async def init_builtin_extra_nodes():
"nodes_camera_trajectory.py",
"nodes_edit_model.py",
"nodes_tcfg.py",
"nodes_v3_test.py", # TODO: remove
"nodes_v1_test.py", # TODO: remove
]
import_failed = []