Files
olivv-cs-ComfyUI-FunPack/tests/test_detail_probe.py
T
digital-garbageandClaude Opus 5.5 88e4dbceb5 fix: block repeat 'video only' no longer repeats the audio
H3 blocks add their residual into the input in place, so the kept single-pass
tensor was overwritten by the next pass and audio was restored from the
repeated stream. Keep a copy instead (block repeat and span loop).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 17:43:29 +03:00

627 lines
25 KiB
Python

"""Detail probe: the three numbers that separate "sharper" from "grainier" from "different",
and the block-spec parser feeding the repeat toggle they exist to judge."""
import sys
import types
from pathlib import Path
import pytest
import torch
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
for _name in (
"comfy", "comfy.k_diffusion", "comfy.k_diffusion.sampling",
"comfy.model_sampling", "comfy.nested_tensor", "comfy.sample",
"comfy.samplers", "comfy.utils",
):
sys.modules.setdefault(_name, types.ModuleType(_name))
sys.modules["comfy.nested_tensor"].NestedTensor = object
import detail_probe as dp # noqa: E402
import samplers # noqa: E402
@pytest.fixture(autouse=True)
def _isolate(monkeypatch, tmp_path):
monkeypatch.setattr(dp, "state_path", lambda key: str(tmp_path / f"{key}.pt"))
def _edged(h=32, w=32, seed=0):
"""A plane with real structure: a few hard edges, flat elsewhere."""
g = torch.Generator().manual_seed(seed)
x = torch.zeros(1, 1, h, w)
x[:, :, :, w // 3:] = 1.0 # vertical edge
x[:, :, h // 2:, :] += 0.5 # horizontal edge
x += torch.rand(1, 1, h, w, generator=g) * 0.01
return x
# --- the three numbers ----------------------------------------------------------
def test_identical_inputs_are_a_perfect_null():
a = _edged()
r = dp.compare(a, a.clone())
assert r["detail"] == pytest.approx(1.0)
assert r["structure"] == pytest.approx(1.0)
def test_sharpening_existing_edges_reads_as_edge_aligned_detail():
"""An unsharp-mask style boost: more high frequency, concentrated where edges already
were, low frequencies untouched. This is the outcome the probe exists to recognise."""
a = _edged()
hf = dp._hf(a)
b = a + 0.6 * torch.nn.functional.conv2d(
a, dp._LAPLACIAN.view(1, 1, 3, 3), padding=1) * -1.0
r = dp.compare(a, b)
assert r["detail"] > 1.1 # finer structure appeared
assert r["structure"] > 0.9 # same picture underneath
assert r["edge_aligned"] > 0.5 # and it landed on the edges
assert float(hf.mean()) > 0 # sanity: the baseline had edges at all
def test_uniform_noise_is_detail_without_edge_alignment():
"""Grain raises `detail` exactly like sharpening does -- `edge_aligned` is the only
number that separates them, which is the reason it exists."""
a = _edged()
g = torch.Generator().manual_seed(1)
b = a + torch.randn(a.shape, generator=g) * 0.05
r = dp.compare(a, b)
assert r["detail"] > 1.1 # looks like "more detail"
assert r["edge_aligned"] < 0.35 # but it is spread everywhere
def test_a_different_picture_shows_up_as_lost_structure():
a = _edged(seed=0)
b = _edged(seed=1) * 0.3 + 0.7 # same kind of content, different low frequencies
r = dp.compare(a, b)
assert r["structure"] < 0.85
def test_blurring_reads_as_detail_lost():
a = _edged()
b = dp._lf(a)
assert dp.compare(a, b)["detail"] < 1.0
def test_shape_mismatch_is_not_compared():
assert dp.compare(_edged(32, 32), _edged(16, 16)) is None
def test_a_flat_baseline_is_refused_rather_than_dividing_by_zero():
flat = torch.zeros(1, 1, 16, 16)
assert dp.compare(flat, flat + 1.0) is None
def test_planes_pool_leading_dims_whatever_they_mean():
"""C/T ordering differs between model families; this needs spatial structure only, so it
must not care which leading axis is which."""
x = torch.randn(4, 7, 16, 16)
assert dp._planes(x).shape == (28, 1, 16, 16)
assert dp._planes(torch.randn(2, 3, 5, 16, 16)).shape == (30, 1, 16, 16)
def test_too_small_to_filter_is_none():
assert dp._planes(torch.randn(2, 2)) is None
# --- pairing consecutive runs ---------------------------------------------------
def test_the_first_run_has_nothing_to_compare_against():
assert dp.record("k", _edged(), label="no repeat") is None
assert dp.rows("k") == []
def test_the_second_run_is_scored_against_the_first():
dp.record("k", _edged(), label="no repeat")
row = dp.record("k", _edged(), label="repeat 40")
assert row is not None
assert row["label_before"] == "no repeat" and row["label_after"] == "repeat 40"
assert len(dp.rows("k")) == 1
def test_each_run_becomes_the_baseline_for_the_next():
for i in range(3):
dp.record("k", _edged(seed=i), label=f"run{i}")
rows = dp.rows("k")
assert [r["label_before"] for r in rows] == ["run0", "run1"]
assert [r["label_after"] for r in rows] == ["run1", "run2"]
def test_a_resolution_change_is_not_an_ab():
dp.record("k", _edged(32, 32), label="a")
assert dp.record("k", _edged(16, 16), label="b") is None
assert dp.rows("k") == []
# ...but it still becomes the baseline, so the NEXT matching run pairs with it.
assert dp.record("k", _edged(16, 16), label="c") is not None
def test_rows_are_capped():
for i in range(dp.MAX_ROWS + 5):
dp.record("k", _edged(seed=i % 3), label=f"r{i}")
assert len(dp.rows("k")) == dp.MAX_ROWS
def test_clear_removes_everything():
dp.record("k", _edged(), label="a")
dp.record("k", _edged(), label="b")
dp.clear_all("k")
assert dp.rows("k") == []
def test_a_non_tensor_is_a_safe_no_op():
assert dp.record("k", None) is None
assert dp.record("", _edged()) is None
def test_corrupt_state_degrades_to_empty(tmp_path, monkeypatch):
path = tmp_path / "junk.pt"
path.write_bytes(b"not a torch file")
monkeypatch.setattr(dp, "state_path", lambda key: str(path))
assert dp.rows("k") == []
# --- the block-spec parser the repeat toggle reads ------------------------------
@pytest.mark.parametrize("spec,expected", [
("", set()),
("40", {40}),
("38-42", {38, 39, 40, 41, 42}),
("10,40,44", {10, 40, 44}),
("10, 40 , 44", {10, 40, 44}), # whitespace
("42-38", {38, 39, 40, 41, 42}), # reversed range
("48-99", {48, 49}), # clamped to the stack
("-5", set()), # negative: no leading-dash range
("99", set()), # out of range
("40,junk,41", {40, 41}), # a typo costs that entry, not the run
("40-", set()),
])
def test_block_spec_parsing(spec, expected):
assert samplers.FunPackLTXAVSceneChainSampler._parse_block_spec(spec, 50) == expected
# --- the repeat hook actually repeats -------------------------------------------
class _Model:
def __init__(self):
self.model_options = {}
def clone(self):
m = _Model()
m.model_options = {k: dict(v) if isinstance(v, dict) else v
for k, v in self.model_options.items()}
return m
def _repeat_hook(blocks, times):
s = samplers.FunPackLTXAVSceneChainSampler()
patched = s._install_block_repeat(_Model(), blocks, times)
return patched.model_options["transformer_options"]["patches_replace"]["dit"]
def test_the_block_runs_once_more_per_extra_pass():
calls = []
def original(args):
calls.append(args["img"].clone())
return {"img": args["img"] + 1.0}
dit = _repeat_hook({0}, 1)
out = dit[("double_block", 0)]({"img": torch.zeros(2, 2)}, {"original_block": original})
assert len(calls) == 2 # ran twice
assert torch.equal(out["img"], torch.full((2, 2), 2.0))
assert torch.equal(calls[1], torch.ones(2, 2)) # 2nd pass saw the 1st pass's output
def test_extra_passes_scale():
def original(args):
return {"img": args["img"] + 1.0}
dit = _repeat_hook({0}, 3)
out = dit[("double_block", 0)]({"img": torch.zeros(1, 1)}, {"original_block": original})
assert float(out["img"]) == 4.0 # 1 normal pass + 3 extra
def test_only_the_named_blocks_are_patched():
dit = _repeat_hook({0, 3}, 1)
assert set(b for _tag, b in dit) == {0, 3}
def test_no_blocks_is_an_untouched_model():
s = samplers.FunPackLTXAVSceneChainSampler()
m = _Model()
assert s._install_block_repeat(m, set(), 1) is m
def test_the_callers_args_dict_is_not_mutated():
"""The block reads "img" out of args; leaking the intermediate back to the caller would
hand whatever reads args after this hook a half-processed stream."""
def original(args):
return {"img": args["img"] + 1.0}
dit = _repeat_hook({0}, 2)
args = {"img": torch.zeros(1, 1), "t_emb": "sentinel"}
dit[("double_block", 0)](args, {"original_block": original})
assert float(args["img"]) == 0.0
assert args["t_emb"] == "sentinel"
def test_an_existing_patch_at_the_same_block_is_repeated_not_dropped():
calls = []
def inner(args, extra):
calls.append(True)
return {"img": args["img"] + 1.0}
s = samplers.FunPackLTXAVSceneChainSampler()
m = _Model()
m.model_options["transformer_options"] = {
"patches_replace": {"dit": {("double_block", 0): inner}}}
patched = s._install_block_repeat(m, {0}, 1)
hook = patched.model_options["transformer_options"]["patches_replace"]["dit"][
("double_block", 0)]
out = hook({"img": torch.zeros(1, 1)}, {"original_block": lambda a: {"img": a["img"]}})
assert len(calls) == 2 # the existing patch is what gets repeated
assert float(out["img"]) == 2.0
# --- video_only against a block that writes IN PLACE, the way H3's do --------------
#
# H3's DiT blocks add their residual into the input tensor (_mod_gate uses addcmul_). A
# block that returned a fresh tensor hid the bug: holding a REFERENCE to the single-pass
# result was fine until the next pass wrote into it, and then text/audio rows were
# "restored" from the repeated stream. Rows 0-1 are audio, rows 2-3 target video.
_SEGS = [(0, 2, 2), (2, 4, 0)] # (start, stop, mod row): audio tag 2, video tag 0
def _in_place_block(args):
img = args["img"]
img.add_(1.0)
return {"img": img}
def test_video_only_repeat_keeps_audio_single_pass_with_an_in_place_block():
s = samplers.FunPackLTXAVSceneChainSampler()
patched = s._install_block_repeat(_Model(), {0}, 1, video_only=True)
hook = patched.model_options["transformer_options"]["patches_replace"]["dit"][
("double_block", 0)]
out = hook({"img": torch.zeros(4, 2), "mod_segments": _SEGS},
{"original_block": _in_place_block})["img"]
assert torch.equal(out[:2], torch.ones(2, 2)), "audio rows got the repeat"
assert torch.equal(out[2:], torch.full((2, 2), 2.0)), "video rows lost the repeat"
class _InPlaceBlock:
def __call__(self, h, t_emb, mod_segments, rope_freqs, transformer_options=None):
return h.add_(1.0)
def _span_model(n):
m = _Model()
m.model = types.SimpleNamespace(
diffusion_model=types.SimpleNamespace(blocks=[_InPlaceBlock() for _ in range(n)]))
clone = m.clone
def cloned():
c = clone()
c.model = m.model
return c
m.clone = cloned
return m
def test_video_only_span_loop_keeps_audio_single_pass_with_in_place_blocks():
s = samplers.FunPackLTXAVSceneChainSampler()
patched = s._install_span_loop(_span_model(2), {0, 1}, 1, video_only=True)
head = patched.model_options["transformer_options"]["patches_replace"]["dit"][
("double_block", 0)]
out = head({"img": torch.zeros(4, 2), "t_emb": None, "mod_segments": _SEGS,
"rope_freqs": None, "transformer_options": {}}, {})["img"]
# The span is two blocks: one run adds 2, the loop runs it twice and adds 4.
assert torch.equal(out[:2], torch.full((2, 2), 2.0)), "audio rows got the loop"
assert torch.equal(out[2:], torch.full((2, 2), 4.0)), "video rows lost the loop"
# --- the seed is what separates "invalid comparison" from "real result" -----------
#
# A low `structure` means the low-frequency picture moved. That is EITHER two different
# generations (different seed -- a reference pins the subject, not the sample, so R2V on a
# new seed is a new shot) OR the same seed whose shot was moved by the change itself. The
# three numbers cannot tell those apart, so the seed is recorded rather than guessed at.
def test_same_seed_is_flagged_on_the_row():
dp.record("k", _edged(), label="off", seed=1234)
row = dp.record("k", _edged(), label="on", seed=1234)
assert row["same_seed"] is True
assert row["seed_before"] == 1234 and row["seed_after"] == 1234
def test_a_changed_seed_is_flagged_as_not_an_ab():
dp.record("k", _edged(seed=0), label="off", seed=1)
row = dp.record("k", _edged(seed=1), label="on", seed=2)
assert row["same_seed"] is False
def test_a_missing_seed_is_unknown_not_a_match():
"""Old rows and callers that pass no seed must not be reported as same-seed -- that would
silently upgrade an uncheckable comparison into a claimed A/B."""
dp.record("k", _edged(), label="off")
row = dp.record("k", _edged(), label="on")
assert row["same_seed"] is False
assert row["seed_before"] is None and row["seed_after"] is None
def test_the_seed_rides_along_to_the_next_pairing():
dp.record("k", _edged(), label="a", seed=7)
dp.record("k", _edged(), label="b", seed=7)
row = dp.record("k", _edged(), label="c", seed=9)
assert row["seed_before"] == 7 and row["seed_after"] == 9 and row["same_seed"] is False
# --- what the A/B actually WAS ----------------------------------------------------
#
# The probe cannot know which knob the user considers the variable, and a hand-picked label
# only ever tracked one of them (every row read "no repeat -> no repeat" while the real
# difference was elsewhere, or nowhere). So it diffs the run's scalar settings instead and
# the row names the difference itself.
def test_the_row_names_what_changed_between_the_two_runs():
dp.record("k", _edged(), seed=1, settings={"seed": 1, "h3_block_repeat": "", "cfg": 1.0})
row = dp.record("k", _edged(), seed=1, settings={"seed": 1, "h3_block_repeat": "40", "cfg": 1.0})
assert row["changed"] == {"h3_block_repeat": ["", "40"]}
def test_identical_settings_report_no_change_which_is_the_noise_floor():
"""Two identical runs are not a wasted comparison -- they measure how much the generation
varies on its own, and every other row is uninterpretable without that number."""
cfg = {"seed": 5, "h3_block_repeat": ""}
dp.record("k", _edged(), seed=5, settings=cfg)
row = dp.record("k", _edged(), seed=5, settings=dict(cfg))
assert row["changed"] == {}
assert row["same_seed"] is True
def test_a_new_or_removed_setting_counts_as_changed():
dp.record("k", _edged(), settings={"a": 1})
row = dp.record("k", _edged(), settings={"a": 1, "b": 2})
assert row["changed"] == {"b": [None, 2]}
def test_several_changes_are_all_reported():
dp.record("k", _edged(), settings={"a": 1, "b": 1, "c": 1})
row = dp.record("k", _edged(), settings={"a": 2, "b": 1, "c": 3})
assert row["changed"] == {"a": [1, 2], "c": [1, 3]}
def test_no_settings_at_all_is_an_empty_diff_not_a_crash():
dp.record("k", _edged())
row = dp.record("k", _edged())
assert row["changed"] == {}
def test_a_prompt_change_is_reported_and_not_treated_as_a_repeatability_check():
"""The prompt is not a scalar -- it arrives as conditioning -- so scalars alone called two
runs of different text "nothing changed", and the resulting structure drop read as
"generation is not reproducible" rather than "you changed the prompt"."""
base = {"seed": 1, "cfg": 1.0, "conditioning": "(1,9,4096):0.01:0.5"}
dp.record("k", _edged(seed=0), seed=1, settings=base)
row = dp.record("k", _edged(seed=1), seed=1,
settings={**base, "conditioning": "(1,12,4096):0.03:0.7"})
assert "conditioning" in row["changed"]
assert row["same_seed"] is True # same seed, but NOT the same generation
# --- conditioning: drift vs a genuinely different prompt --------------------------
def test_float_wobble_in_the_encoder_is_not_a_prompt_change():
"""The first version compared a formatted string, so any float noise read as "prompt
changed" — on runs where the prompt was demonstrably identical."""
a = {"conditioning": [[4096.0, 0.010000, 0.500000]]}
b = {"conditioning": [[4096.0, 0.010000001, 0.500000002]]}
dp.record("k", _edged(seed=0), settings=a)
row = dp.record("k", _edged(seed=0), settings=b)
assert "conditioning" not in row["changed"]
assert row["cond_shift"] < dp.COND_TOL
def test_a_real_drift_is_reported_with_its_size():
a = {"conditioning": [[4096.0, 0.100, 0.500]]}
b = {"conditioning": [[4096.0, 0.102, 0.500]]}
dp.record("k", _edged(seed=0), settings=a)
row = dp.record("k", _edged(seed=0), settings=b)
assert "conditioning" in row["changed"]
# Relative to the LARGER magnitude: |0.102-0.100| / 0.102. The point is that the row
# carries a size at all, so drift can be told from a prompt swap.
assert row["cond_shift"] == pytest.approx(0.002 / 0.102, rel=1e-6)
def test_a_different_token_count_is_a_different_prompt_not_drift():
a = {"conditioning": [[4096.0, 0.1, 0.5]]}
b = {"conditioning": [[8192.0, 0.1, 0.5]]}
dp.record("k", _edged(seed=0), settings=a)
row = dp.record("k", _edged(seed=0), settings=b)
assert row["cond_shift"] == 1.0
def test_a_different_number_of_scenes_is_structural():
a = {"conditioning": [[4096.0, 0.1, 0.5]]}
b = {"conditioning": [[4096.0, 0.1, 0.5], [4096.0, 0.2, 0.6]]}
dp.record("k", _edged(seed=0), settings=a)
row = dp.record("k", _edged(seed=0), settings=b)
assert row["cond_shift"] == 1.0
def test_identical_conditioning_shifts_nothing():
cond = {"conditioning": [[4096.0, 0.1, 0.5], [2048.0, -0.3, 0.9]]}
dp.record("k", _edged(seed=0), settings=cond)
row = dp.record("k", _edged(seed=0), settings=dict(cond))
assert row["cond_shift"] == 0.0
assert row["changed"] == {}
def test_the_detail_probe_switch_is_its_own(monkeypatch, tmp_path):
"""Deliberately NOT shared with the block probe. They cost wildly different amounts —
this copies one latent per run, that gathers every block on every step — and answering
"is the measurement moving the picture?" requires running this one while that one is off.
A shared toggle made that experiment impossible."""
import block_influence as bi
monkeypatch.delenv(dp._ENV_SWITCH, raising=False)
monkeypatch.delenv(bi._ENV_SWITCH, raising=False)
monkeypatch.setattr(dp, "_switch_path", lambda: str(tmp_path / "dp" / "enabled"))
monkeypatch.setattr(bi, "_switch_dir", lambda: str(tmp_path / "bi"))
bi.set_collection_enabled(True)
assert dp.collection_enabled() is False # not dragged along by the other one
dp.set_collection_enabled(True)
bi.set_collection_enabled(False)
assert dp.collection_enabled() is True # and not switched off by it either
def test_the_detail_switch_persists_and_env_wins(monkeypatch, tmp_path):
monkeypatch.delenv(dp._ENV_SWITCH, raising=False)
monkeypatch.setattr(dp, "_switch_path", lambda: str(tmp_path / "dp" / "enabled"))
assert dp.collection_enabled() is False
dp.set_collection_enabled(True)
monkeypatch.delenv(dp._ENV_SWITCH, raising=False)
assert dp.collection_enabled() is True # from disk, after a restart
monkeypatch.setenv(dp._ENV_SWITCH, "0")
assert dp.collection_enabled() is False # env overrides
# --- video-only repeat ------------------------------------------------------------
#
# H3 packs video, text and audio into ONE sequence, so a plain repeat doubles the block for
# audio too — the leading suspect for band 31-40 inventing dialogue on every run.
def _repeat_hook_vo(blocks, times, video_only):
s = samplers.FunPackLTXAVSceneChainSampler()
patched = s._install_block_repeat(_Model(), blocks, times, video_only=video_only)
return patched.model_options["transformer_options"]["patches_replace"]["dit"]
def _run_rows(video_only, segs):
"""4 rows, block adds +1 per pass. -> the returned rows."""
dit = _repeat_hook_vo({0}, 1, video_only)
return dit[("double_block", 0)](
{"img": torch.zeros(4, 3), "mod_segments": segs},
{"original_block": lambda a: {"img": a["img"] + 1.0}})["img"]
def test_video_only_keeps_the_repeat_for_video_and_reverts_the_rest():
# upstream order: rows 0-1 target audio (tag 8 % 3 == 2), rows 2-3 target video
out = _run_rows(True, [(0, 2, 8), (2, 4, 6)])
assert torch.equal(out[2:], torch.full((2, 3), 2.0)) # two passes
assert torch.equal(out[:2], torch.full((2, 3), 1.0)) # one pass, restored
def test_video_only_does_not_repeat_the_anchor_pin():
"""A tag-0 pin is condition, not the video being made: it gets the single pass."""
out = _run_rows(True, [(0, 1, 6), (1, 2, 8), (2, 4, 6)]) # pin, audio, video
assert torch.equal(out[:2], torch.full((2, 3), 1.0))
assert torch.equal(out[2:], torch.full((2, 3), 2.0))
def test_without_video_only_every_row_gets_the_repeat():
out = _run_rows(False, [(0, 2, 6), (2, 4, 8)])
assert torch.equal(out, torch.full((4, 3), 2.0))
def test_video_only_falls_back_to_repeating_everything_when_no_mask():
"""A shape the mask code has never seen must not silently drop the feature."""
out = _run_rows(True, [(0, 4, 7)]) # text only, no video rows
assert torch.equal(out, torch.full((4, 3), 2.0))
def test_video_only_survives_several_extra_passes():
dit = _repeat_hook_vo({0}, 3, True)
out = dit[("double_block", 0)](
{"img": torch.zeros(4, 3), "mod_segments": [(0, 2, 8), (2, 4, 6)]},
{"original_block": lambda a: {"img": a["img"] + 1.0}})["img"]
assert torch.equal(out[2:], torch.full((2, 3), 4.0)) # 1 + 3 extra
assert torch.equal(out[:2], torch.full((2, 3), 1.0)) # still single-pass
# --- span loop: 31,32..40,31,32..40 rather than 31,31,32,32..40,40 -----------------
class _SpanModel(_Model):
"""A model whose DiT exposes a real block list, which is what the span loop walks —
`original_block` closes over ONE block, so a loop cannot be built from the hook alone."""
def __init__(self, n=6):
super().__init__()
self.calls = []
blocks = [self._mk(i) for i in range(n)]
self.model = types.SimpleNamespace(
diffusion_model=types.SimpleNamespace(blocks=blocks))
def _mk(self, i):
def block(img, t_emb, mod_segments, rope_freqs, transformer_options=None):
self.calls.append(i)
return img + (10 ** i) # each block leaves its own fingerprint
return block
def clone(self):
m = _SpanModel.__new__(_SpanModel)
m.model_options = {k: dict(v) if isinstance(v, dict) else v
for k, v in self.model_options.items()}
m.model, m.calls, m._mk = self.model, self.calls, self._mk
return m
def _drive_span(mdl, lo, hi, segs=None):
"""Run the model's own block loop the way minimax/model.py does."""
dit = mdl.model_options["transformer_options"]["patches_replace"]["dit"]
h = torch.zeros(4, 2)
for i in range(len(mdl.model.diffusion_model.blocks)):
args = {"img": h, "t_emb": None, "mod_segments": segs or [(0, 0, 8), (0, 4, 6)],
"rope_freqs": None, "transformer_options": {}}
if ("double_block", i) in dit:
h = dit[("double_block", i)](args, {"original_block": None})["img"]
else:
h = mdl.model.diffusion_model.blocks[i](h, None, segs, None)
return h
def test_the_span_runs_in_order_and_wraps_once():
s = samplers.FunPackLTXAVSceneChainSampler()
src = _SpanModel(n=6)
patched = s._install_span_loop(src, {2, 3, 4}, times=1)
_drive_span(patched, 2, 4)
# blocks 0,1,5 once each; the span 2,3,4 twice IN ORDER — not 2,2,3,3,4,4.
assert src.calls == [0, 1, 2, 3, 4, 2, 3, 4, 5]
def test_more_passes_loop_the_span_again():
s = samplers.FunPackLTXAVSceneChainSampler()
src = _SpanModel(n=5)
patched = s._install_span_loop(src, {1, 2}, times=2)
_drive_span(patched, 1, 2)
assert src.calls == [0, 1, 2, 1, 2, 1, 2, 3, 4]
def test_a_scattered_selection_is_refused_not_silently_widened():
"""Looping min..max of 31,34,37,40 would run 32,33,35,36,... which the user deliberately
left out. Refuse and say so rather than quietly doing something else."""
s = samplers.FunPackLTXAVSceneChainSampler()
src = _SpanModel(n=8)
assert s._install_span_loop(src, {1, 3, 5}, times=1) is src # untouched model
def test_a_model_with_no_block_list_degrades_cleanly():
s = samplers.FunPackLTXAVSceneChainSampler()
plain = _Model()
assert s._install_span_loop(plain, {1, 2}, times=1) is plain
def test_video_only_gives_text_and_audio_the_span_ONCE_not_zero_times():
"""The non-video rows must still get the span's normal single pass — reverting them to
their pre-span value would skip those blocks entirely for audio, which is a different
and worse intervention than 'do not repeat them'."""
s = samplers.FunPackLTXAVSceneChainSampler()
src = _SpanModel(n=4)
patched = s._install_span_loop(src, {1, 2}, times=1, video_only=True)
out = _drive_span(patched, 1, 2, segs=[(0, 2, 8), (2, 4, 6)])
span_once = 10 ** 1 + 10 ** 2 # the looped blocks
outside = 10 ** 0 + 10 ** 3 # blocks 0 and 3 run once for every row
assert torch.allclose(out[2:], torch.full((2, 2), float(outside + 2 * span_once)))
assert torch.allclose(out[:2], torch.full((2, 2), float(outside + span_once)))