99 lines
2.6 KiB
Python
99 lines
2.6 KiB
Python
# SimpleSyrup - workflow-focused ComfyUI extensions for image generation
|
|
# Copyright (C) 2026 Artificial Sweetener and contributors
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
"""Verify derived CLIP and patcher model coherence."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
import pytest
|
|
|
|
from simple_syrup.runtime.clip_patcher_model_alignment import (
|
|
align_clip_text_encoder_with_patcher,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class _Patcher:
|
|
"""Expose one patcher-owned text encoder."""
|
|
|
|
model: object
|
|
|
|
|
|
@dataclass
|
|
class _Clip:
|
|
"""Expose the host CLIP surface required by the alignment owner."""
|
|
|
|
patcher: _Patcher
|
|
cond_stage_model: object
|
|
|
|
|
|
def test_alignment_replaces_a_stale_source_encoder() -> None:
|
|
"""Execute the independently reloaded model owned by a static patcher."""
|
|
|
|
patcher_model = object()
|
|
clip = _Clip(_Patcher(patcher_model), object())
|
|
|
|
align_clip_text_encoder_with_patcher(clip)
|
|
|
|
assert clip.cond_stage_model is patcher_model
|
|
|
|
|
|
def test_alignment_preserves_an_already_coherent_encoder() -> None:
|
|
"""Leave the identity fast path unchanged."""
|
|
|
|
encoder = object()
|
|
clip = _Clip(_Patcher(encoder), encoder)
|
|
|
|
align_clip_text_encoder_with_patcher(clip)
|
|
|
|
assert clip.cond_stage_model is encoder
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("clip", "message"),
|
|
(
|
|
(object(), "does not expose a patcher"),
|
|
(
|
|
type("Clip", (), {"patcher": object(), "cond_stage_model": object()})(),
|
|
"patcher does not expose a model",
|
|
),
|
|
(_Clip(_Patcher(object()), None), "does not expose a text encoder"),
|
|
),
|
|
)
|
|
def test_alignment_rejects_missing_host_surfaces(
|
|
clip: object,
|
|
message: str,
|
|
) -> None:
|
|
"""Fail closed when Comfy does not expose the required relationship."""
|
|
|
|
with pytest.raises(TypeError, match=message):
|
|
align_clip_text_encoder_with_patcher(clip)
|
|
|
|
|
|
def test_alignment_rejects_a_read_only_text_encoder_surface() -> None:
|
|
"""Report host values that cannot retain the patcher-owned encoder."""
|
|
|
|
patcher_model = object()
|
|
|
|
class ReadOnlyClip:
|
|
"""Expose a derived text encoder without a writable host boundary."""
|
|
|
|
patcher = _Patcher(patcher_model)
|
|
|
|
@property
|
|
def cond_stage_model(self) -> object:
|
|
"""Return a stale source encoder."""
|
|
|
|
return self._source_encoder
|
|
|
|
def __init__(self) -> None:
|
|
"""Create the stale encoder identity."""
|
|
|
|
self._source_encoder = object()
|
|
|
|
with pytest.raises(TypeError, match="cannot be aligned"):
|
|
align_clip_text_encoder_with_patcher(ReadOnlyClip())
|