Files
kunail0804-ComfyUI-Scene-Co…/tests/test_scene_analyzer_node.py
T
0de9b43d7a feat(nodes): add the Scene Analyzer ComfyUI node (#19) (#63)
Expose the Scene Analyzer as a ComfyUI node (MASTER_SPEC §20) plus the node
registration plumbing and a shared output adapter.

- nodes/scene_analyzer_node.py: SceneAnalyzerNode, a thin adapter. Inputs are
  Natural Language, Model Name, Temperature, Timeout, and an optional System
  Prompt override; it builds a Config, constructs OllamaBackend.from_config, and
  delegates to analyze(). Outputs (scene, warnings, errors): the SCENE model and
  the warnings/errors formatted for display. No compiler logic in the node.
- nodes/adapters.py: format_messages() renders diagnostics as CODE: description
  lines.
- Registration: nodes/__init__.py aggregates NODE_CLASS_MAPPINGS /
  NODE_DISPLAY_NAME_MAPPINGS; the root __init__.py re-exports them.

ComfyUI compatibility: the node package uses relative imports internally so our
`nodes` package is never resolved as ComfyUI's own top-level `nodes` module, and
the entry point puts the repo root on sys.path so `compiler`/`schemas` resolve
when ComfyUI loads the package by file path.

Tests (no live Ollama): INPUT_TYPES/RETURN metadata, delegation to analyze
(monkeypatched) with warnings/errors surfaced, empty-message strings, system
prompt override passthrough, and ComfyUI registration.

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 14:08:03 +02:00

78 lines
2.7 KiB
Python

"""Tests for the Scene Analyzer ComfyUI node (issue #19). No live Ollama."""
from __future__ import annotations
import nodes
import nodes.scene_analyzer_node as node_module
from compiler.common.message_codes import message
from compiler.common.result import CompilerResult
from nodes.scene_analyzer_node import SceneAnalyzerNode
def test_input_types_structure() -> None:
inputs = SceneAnalyzerNode.INPUT_TYPES()
assert set(inputs["required"]) == {
"natural_language",
"model_name",
"temperature",
"timeout",
}
assert "system_prompt" in inputs["optional"]
def test_node_metadata() -> None:
assert SceneAnalyzerNode.RETURN_TYPES == ("SCENE", "STRING", "STRING")
assert SceneAnalyzerNode.RETURN_NAMES == ("scene", "warnings", "errors")
assert SceneAnalyzerNode.FUNCTION == "run"
assert SceneAnalyzerNode.CATEGORY == "Scene Compiler"
def test_run_delegates_to_analyzer_and_surfaces_messages(monkeypatch) -> None:
captured = {}
def fake_analyze(description, backend, config):
captured["description"] = description
captured["model"] = config.analyzer.model
return (
CompilerResult(data="SCENE_MODEL")
.add_warning(message("SC0001", "unknown concept 'x'"))
.add_error(message("SC0011", "bad response"))
)
monkeypatch.setattr(node_module, "analyze", fake_analyze)
scene, warnings, errors = SceneAnalyzerNode().run(
natural_language="A girl.",
model_name="mistral",
temperature=0.0,
timeout=60,
)
assert scene == "SCENE_MODEL"
assert captured["description"] == "A girl."
assert captured["model"] == "mistral"
assert "SC0001: unknown concept 'x'" in warnings
assert "SC0011: bad response" in errors
def test_no_messages_yield_empty_strings(monkeypatch) -> None:
monkeypatch.setattr(node_module, "analyze", lambda d, b, c: CompilerResult(data="S"))
scene, warnings, errors = SceneAnalyzerNode().run("x", "llama3", 0.0, 60)
assert (warnings, errors) == ("", "")
def test_system_prompt_override_is_passed(monkeypatch) -> None:
captured = {}
def fake_analyze(description, backend, config):
captured["system_prompt"] = config.analyzer.system_prompt
return CompilerResult(data="S")
monkeypatch.setattr(node_module, "analyze", fake_analyze)
SceneAnalyzerNode().run("x", "llama3", 0.0, 60, system_prompt="CUSTOM")
assert captured["system_prompt"] == "CUSTOM"
def test_registered_for_comfyui() -> None:
assert nodes.NODE_CLASS_MAPPINGS["SceneCompilerAnalyzer"] is SceneAnalyzerNode
assert nodes.NODE_DISPLAY_NAME_MAPPINGS["SceneCompilerAnalyzer"] == "Scene Analyzer"