Files
olivv-cs-ComfyUI-FunPack/tests/test_run_phase.py
T
digital-garbageandClaude Opus 5 2011b18b95 fix: don't reject projects saved with the old context_window_schedule names
Renaming the combo's choices to core's spellings broke queueing for anyone who
had one of the old ones saved: ComfyUI validates combo VALUES at queue time,
before the node ever runs, so the alias map added with the rename never got a
chance. The three legacy names are back in the list (they resolve through the
alias map at runtime), and the Editor now displays a stored legacy value as the
name it maps to and writes that back, so the dropdown can't show one setting
while another runs.

And that rejection was unreadable. ComfyUI's top-level `error` for a validation
failure is a fixed blob ("Prompt outputs failed validation", details ""); the
part naming the node, the widget and the bad value is in `node_errors`, which
`error or node_errors` never reached because the blob is always truthy. Every
rejected prompt therefore reported the same nothing. Both are formatted now:

  Prompt outputs failed validation; FunPackLTXAVSceneChainSampler: Value not in
  list — context_window_schedule: 'static_standard' not in [...]

Also: the progress poll no longer imports anything. current_progress() reads
run_phase's label straight off `sys`. It fires every 700ms on ComfyUI's event
loop WHILE the worker thread samples, and that is not a path to do import work
on — the direct read is both cheaper and the correct one, since run_phase keeps
its state there anyway.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 18:10:10 +03:00

65 lines
2.6 KiB
Python

"""run_phase — the live "what is the sampler doing" label behind the progress readout.
The one invariant that actually breaks in production: the WRITER (samplers.py) reaches this
module as a package-relative import and the READER (movie_editor's bridge) imports FunPack
modules top-level by name, so the two can hold different module objects. State in module
globals would be two separate copies and the label would never arrive. It lives on `sys`
for exactly that reason, and this pins it down.
"""
import importlib.util
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
import run_phase # noqa: E402
def _second_import():
"""A second, independent module object for the same file — what the other import path
produces at runtime."""
spec = importlib.util.spec_from_file_location("other_pkg.run_phase", ROOT / "run_phase.py")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
def test_both_import_paths_see_the_same_label():
other = _second_import()
run_phase.set_phase("scene 2/3 · pass 2 of 2")
assert other.current()["label"] == "scene 2/3 · pass 2 of 2"
other.clear()
assert run_phase.current()["label"] == ""
def test_seq_only_ever_increases():
"""A poller uses it to tell "still the same phase" from "this phase came round again",
so it must never reset — not even when the label is cleared."""
before = run_phase.current()["seq"]
run_phase.set_phase("a")
run_phase.set_phase("a")
run_phase.clear()
assert run_phase.current()["seq"] == before + 3
def test_a_bad_label_never_raises():
"""This is a readout on the sampling path: it must not be able to fail a render."""
run_phase.set_phase(None)
assert run_phase.current()["label"] == ""
run_phase.set_phase(12)
assert run_phase.current()["label"] == "12"
run_phase.clear()
def test_the_bridge_reads_the_same_sys_key_without_importing_this_module():
"""movie_editor's progress poll runs every 700ms on ComfyUI's event loop WHILE the
worker thread samples, so it reads the label straight off `sys` rather than importing
anything. That makes the key name a contract between two files — pin it."""
src = (ROOT / "movie_editor" / "backend" / "bridge.py").read_text()
assert run_phase._SYS_KEY == "_funpack_run_phase"
assert f'getattr(sys, "{run_phase._SYS_KEY}"' in src
# ...and the poll must not have grown an import back.
poll = src.split("def current_progress(")[1].split("\ndef ")[0]
assert "import_module" not in poll and "_funpack_attr" not in poll