Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions tests/test_cache_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import os
import sys

import diffusers
import pytest
import torch

Expand Down Expand Up @@ -234,11 +235,16 @@ def _state_manager(model):


def test_cache_state_needs_a_context():
"""Without the context, the hook raises - the failure the wrapper prevents."""
"""Without the context, the hook raises - the failure the wrapper prevents.

Only the exception type is asserted: the message is diffusers' own private
wording (already changed once upstream) and not part of any contract dw
relies on.
"""

manager = _state_manager(_cached_tiny_model())

with pytest.raises(ValueError, match="No context is set"):
with pytest.raises(ValueError):
manager.get_state()


Expand Down Expand Up @@ -268,7 +274,12 @@ def test_cache_state_does_not_leak_between_runs():


def test_cache_context_clears_after_an_error():
"""An errored run must not strand a context that the next run inherits."""
"""An errored run must not strand a context that the next run inherits.

Checked behaviorally (get_state rejects a missing context, same as before
any context was ever set) rather than via the state manager's private
context attribute, whose name is diffusers' own implementation detail.
"""
from dw.pipeline_processors.pipeline import stateful_cache_context

model = _cached_tiny_model()
Expand All @@ -278,7 +289,8 @@ def test_cache_context_clears_after_an_error():
with stateful_cache_context(_FakePipeline(model)):
raise RuntimeError("boom")

assert manager._current_context is None
with pytest.raises(ValueError):
manager.get_state()


@pytest.mark.parametrize("transformer", [None, object()])
Expand Down Expand Up @@ -330,7 +342,12 @@ def forward(self, hidden_states, audio_hidden_states, encoder_hidden_states=None
return hidden_states + 1.0, audio_hidden_states + 10.0


class _DualStreamModel(torch.nn.Module):
class _DualStreamModel(torch.nn.Module, diffusers.CacheMixin):
"""Mixes in CacheMixin so `cache_context` is the same public method
dw.pipeline_processors.pipeline.stateful_cache_context calls in production,
rather than a test-only stand-in for it.
"""

def __init__(self, num_blocks=2):
super().__init__()
self.transformer_blocks = torch.nn.ModuleList(
Expand Down Expand Up @@ -365,25 +382,19 @@ def _register_dual_stream_block(remap):
def _run_two_steps(model):
"""Drive the model twice - the second step is the one the cache skips.

The context is set the way CacheMixin.cache_context sets it; the stub model
is a bare Module rather than a diffusers model, so it has no such method of
its own.
Uses the model's own CacheMixin.cache_context, the same public method
dw's stateful_cache_context calls in production, rather than reaching into
HookRegistry's private context-setting internals directly.
"""
from diffusers.hooks import HookRegistry

hidden_states = torch.zeros(1, 6, 4)
audio_hidden_states = torch.zeros(1, 5, 4)
encoder_hidden_states = torch.zeros(1, 3, 4)

registry = HookRegistry.check_if_exists_or_initialize(model)
registry._set_context("test")
try:
with model.cache_context("test"):
for _ in range(2):
hidden_states, audio_hidden_states = model(
hidden_states, audio_hidden_states, encoder_hidden_states
)
finally:
registry._set_context(None)
return hidden_states, audio_hidden_states


Expand Down
Loading