Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
venv/
|
||||
__pycache__/
|
||||
|
||||
.vscode/*
|
||||
@@ -0,0 +1,4 @@
|
||||
[mypy]
|
||||
strict = True
|
||||
mypy_path = src
|
||||
packages = primitivetypes
|
||||
@@ -0,0 +1,8 @@
|
||||
# primitive-types
|
||||
This repository contains typed primitives for ComfyUI in the form of the following nodes:
|
||||
- `int`
|
||||
- `float`
|
||||
- `string`
|
||||
- `string` (multiline)
|
||||
|
||||
The motivation for these primitives is that the standard primitive node cannot be routed. As a result, if you have a configuration node, e.g., `CFG`, you must connect it directly to the sampler node. However, with an `int` node, you can route it (several times if you wish)
|
||||
@@ -0,0 +1 @@
|
||||
from .src.primitivetypes.export import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS # noqa: F401
|
||||
@@ -0,0 +1,69 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Generic, Literal, NotRequired, TypedDict, TypeVar
|
||||
|
||||
|
||||
Number = TypeVar("Number", int, float)
|
||||
TypeString = Literal["INT", "FLOAT", "STRING"]
|
||||
|
||||
|
||||
class NumberInputDict(TypedDict, Generic[Number]):
|
||||
default: Number
|
||||
min: NotRequired[Number]
|
||||
max: NotRequired[Number]
|
||||
step: Number
|
||||
display: Literal["number", "slider"]
|
||||
|
||||
|
||||
class StringInputDict(TypedDict):
|
||||
default: str
|
||||
multiline: bool
|
||||
|
||||
|
||||
class InputDict(TypedDict):
|
||||
required: dict[
|
||||
str,
|
||||
(
|
||||
tuple[TypeString | list[TypeString]] |
|
||||
tuple[TypeString, NumberInputDict[int] | NumberInputDict[float] | StringInputDict]
|
||||
)
|
||||
]
|
||||
|
||||
hidden: NotRequired[dict[
|
||||
str,
|
||||
(
|
||||
tuple[TypeString | list[TypeString]] |
|
||||
tuple[TypeString, NumberInputDict[int] | NumberInputDict[float] | StringInputDict]
|
||||
)
|
||||
]]
|
||||
|
||||
optional: NotRequired[dict[
|
||||
str,
|
||||
(
|
||||
tuple[TypeString | list[TypeString]] |
|
||||
tuple[TypeString, NumberInputDict[int] | NumberInputDict[float] | StringInputDict]
|
||||
)
|
||||
]]
|
||||
|
||||
|
||||
class Node(ABC):
|
||||
FUNCTION = "execute"
|
||||
OUTPUT_NODE = False
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def RETURN_TYPES(self) -> tuple[TypeString, ...]:
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def CATEGORY(self) -> str:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def INPUT_TYPES(cls) -> InputDict:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute(self) -> tuple[Any, ...] | None:
|
||||
pass
|
||||
@@ -0,0 +1,17 @@
|
||||
from .nodes import Int, Float, String, StringMultiline
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"int": Int,
|
||||
"float": Float,
|
||||
"string": String,
|
||||
"string_multiline": StringMultiline
|
||||
}
|
||||
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"int": "int",
|
||||
"float": "float",
|
||||
"string": "string",
|
||||
"string_multiline": "string (multiline)"
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
from typing import TypeVar
|
||||
from .base import Node, InputDict
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class CategoryTyped:
|
||||
CATEGORY = "utils/Primitive Types"
|
||||
|
||||
|
||||
class PassthroughExecute:
|
||||
FUNCTION = "execute"
|
||||
|
||||
def execute(self, *values: T) -> tuple[T, ...] | None:
|
||||
if values:
|
||||
return tuple(values)
|
||||
return None
|
||||
|
||||
|
||||
class Int(PassthroughExecute, CategoryTyped, Node):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputDict:
|
||||
return dict(
|
||||
required=dict(
|
||||
value=("INT", dict(default=0, step=1, display="number"))
|
||||
)
|
||||
)
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
|
||||
|
||||
class Float(PassthroughExecute, CategoryTyped, Node):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputDict:
|
||||
return dict(
|
||||
required=dict(
|
||||
value=("FLOAT", dict(default=0, min=0, max=4096, step=1, display="number"))
|
||||
)
|
||||
)
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
|
||||
|
||||
class String(PassthroughExecute, CategoryTyped, Node):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputDict:
|
||||
return dict(
|
||||
required=dict(
|
||||
text=("STRING", dict(default="", multiline=False))
|
||||
)
|
||||
)
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
|
||||
|
||||
class StringMultiline(PassthroughExecute, CategoryTyped, Node):
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputDict:
|
||||
return dict(
|
||||
required=dict(
|
||||
text=("STRING", dict(default="", multiline=True))
|
||||
)
|
||||
)
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
Reference in New Issue
Block a user