Files
DumiFlex-ComfyUI-Wildcard-P…/wp_nodes/var_to_float.py
T
DumiFlex ccbf38af99 feat(nodes): add wp_seedlist + split loop config types + wp_ prefix sweep + tooltips
Three coordinated changes to the WP_* node family.

1. New WP_SeedList node
   Emits a list of N derived seeds for a downstream loop (is_output_list).
   Three independent override toggles (override_seed / override_count /
   override_strategy) each mirror the wired Loop's base_seed / count /
   strategy. Connecting loop_config auto-flips override_count +
   override_strategy ON so the natural intent of wiring in a loop gets
   the defaults right; override_seed stays explicit opt-in.
   All emitted seeds are masked to 50 bits via the new MAX_SAFE_SEED
   constant in engine.seed_derive so values sit inside ComfyUI's
   frontend randomize range and copy-paste reproduces identically in a
   standalone sampler.

2. Context Loop type split + downstream Context seed widget lock
   Split WP_CONTEXT_LOOP_CONFIG (wire payload) from a new
   WP_CONTEXT_LOOP_WIDGET (DOM-widget-only TYPE). Loop's own widget
   mounts on the widget type; the wire type has no factory so consumers
   like WP_SeedList render their loop_config socket as a plain input
   instead of being hidden by a fallback-undefined widget.
   New graph walker hasUpstreamLoopOverridingSeed: WP_Context's widget
   glue greys out the local seed stock widget when an upstream Loop has
   override_seed ON, so users read "this value is dead while the Loop
   drives it" without inspecting the Loop config separately.

3. wp_ prefix sweep + tooltips across every WP_* node input
   Custom DOM widget input names now carry the wp_ prefix so canvas
   socket labels read as branded WP widgets: modules -> wp_modules,
   rows -> wp_rows, viewer -> wp_viewer, cleaner -> wp_cleaner,
   context_loop_config -> wp_context_loop_config. Every stock input
   across the node family gets a tooltip describing what it does and
   when to wire it from another node. Tests + comfy_api stub updated.
   CLAUDE.md notes the wp_ convention for future custom widgets.

Bundle size budget bumped 388 -> 395 KB to fit the SeedList Vue chunk
(~4.9 KB net gzip) + override lock UI; entry stays at ~4 KB gzipped.
2026-05-28 12:40:44 +03:00

78 lines
2.8 KiB
Python

"""WP_VarToFloat — reads a named $var from PipelineContext, emits a FLOAT.
Parsing rule: Nth signed-float substring match from the var's value
(``-?\\d+(?:\\.\\d+)?(?:[eE][-+]?\\d+)?``). Integers match too, so
``"1920"`` yields ``1920.0``. Fallback path identical to WPVarToInt.
"""
from comfy_api.latest import io # pyright: ignore[reportMissingImports]
from engine.converters import lookup_var, parse_float
from wp_nodes.types import PipelineContext, VarPickerInput
class WPVarToFloat(io.ComfyNode):
"""PipelineContext $var → FLOAT."""
@classmethod
def define_schema(cls):
return io.Schema(
node_id="WP_VarToFloat",
display_name="WP Var → Float",
category="wildcard-pipeline",
inputs=[
PipelineContext.Input(
"context",
tooltip=(
"The resolved $variable context from any upstream "
"WP Context / Loop / Injector chain. Required — "
"without it the node has no variables to read."
),
),
VarPickerInput.Input("wp_var_name", socketless=True),
io.Int.Input(
"index",
default=0,
min=0,
max=999,
tooltip=(
"Which number in the value to extract when multiple "
"are present (0 = first)."
),
),
io.Float.Input(
"default",
default=0.0,
min=-1.0e38,
max=1.0e38,
step=0.01,
tooltip=(
"Value to use when the variable is missing or the "
"index is out of range. The node never errors — it "
"falls back to this."
),
),
],
outputs=[io.Float.Output("value")],
not_idempotent=False,
)
@classmethod
def execute(cls, context, wp_var_name, index, default):
text = lookup_var(context, wp_var_name)
value = parse_float(text, index, default)
a = parse_float(text, index, 0.0)
b = parse_float(text, index, 1.0)
matched = a == b
# See WP_VarToInt for the `wp_varpicker_*` UI-payload rationale
# — engine-resolved source + parsed output feeds the widget's
# "last execute" strip so wildcard-template vars show the truth.
return io.NodeOutput(
value,
ui={
"wp_varpicker_source": [text],
"wp_varpicker_parsed": [str(value) if matched else None],
"wp_varpicker_default": [str(default)],
},
)