Files
2026-04-17 01:29:08 +03:00

123 lines
3.7 KiB
Python

import re
from typing import Any, List
_PLACEHOLDER_RE = re.compile(
r"%(?:"
r"%|" # escaped percent
r"(?:[-+#0 ]*)?" # flags
r"(?:\d+|\*)?" # width
r"(?:\.(?:\d+|\*))?" # precision
r"[hlL]?" # length modifier (ignored by Python for most)
r"[diuoxXeEfFgGcrsa]" # conversion type
r")"
)
class CNPFormat:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"format": (
"STRING",
{
"default": "Size: %u x %u | Prompt: %s",
"multiline": True,
},
),
"arg_1": ("*", {}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",)
FUNCTION = "format_text"
CATEGORY = "ComfyNodesPlus/Text"
@classmethod
def VALIDATE_INPUTS(cls, input_types):
return True
def _ordered_args(self, kwargs: dict[str, Any]) -> List[Any]:
args: List[Any] = []
index = 1
while True:
key = f"arg_{index}"
if key not in kwargs:
break
args.append(kwargs[key])
index += 1
return args
def _normalise_value(self, value: Any, specifier: str) -> Any:
if value is None:
return "" if specifier == "s" else 0
if specifier == "s":
return str(value)
if specifier == "c":
if isinstance(value, int):
return value
text = str(value)
if len(text) != 1:
raise ValueError(f"%c expects a single character, got {value!r}")
return text
if specifier in {"d", "i", "u", "o", "x", "X"}:
if isinstance(value, bool):
return int(value)
if isinstance(value, (int, float)):
return int(value)
text = str(value).strip()
if text == "":
return 0
return int(float(text))
if specifier in {"e", "E", "f", "F", "g", "G"}:
if isinstance(value, bool):
return 1.0 if value else 0.0
if isinstance(value, (int, float)):
return float(value)
text = str(value).strip()
if text == "":
return 0.0
return float(text)
return value
def _extract_specifiers(self, fmt: str) -> List[str]:
specifiers: List[str] = []
for match in _PLACEHOLDER_RE.finditer(fmt):
token = match.group(0)
if token == "%%":
continue
specifiers.append(token[-1])
return specifiers
def format_text(self, format: str, **kwargs):
args = self._ordered_args(kwargs)
specifiers = self._extract_specifiers(format)
if len(args) < len(specifiers):
raise ValueError(
f"CNPFormat: format string expects {len(specifiers)} argument(s), "
f"but only {len(args)} were connected."
)
converted = []
for index, specifier in enumerate(specifiers):
converted.append(self._normalise_value(args[index], specifier))
try:
if len(converted) == 0:
result = format % () if "%%" in format else format
elif len(converted) == 1:
result = format % converted[0]
else:
result = format % tuple(converted)
except Exception as exc:
raise ValueError(f"CNPFormat failed to format string: {exc}") from exc
return (str(result),)