Skip to content

contract

Contract tests guarding FastVideo's public API against drift.

These tests run against the public surface only (fastvideo.VideoGenerator, fastvideo.api.*) — never via private helpers. They fail at FastVideo CI if a change breaks the shape the Dynamo backend package and the private Dreamverse adapter depend on, so drift is caught here before it reaches downstream integrators.

Modules

fastvideo.tests.contract.test_dreamverse_shape

Contract test: Dreamverse-style inputs normalize through the public typed API without needing any private-only compatibility promise.

The private Dreamverse UI server (FastVideo-internal/ui/ltx2-streaming/ server/gpu_pool.py) has historically called VideoGenerator.from_pretrained(**load_kwargs) with a flat kwarg bag containing LTX-2-specific names (ltx2_refine_enabled, ltx2_refine_upsampler_path, etc.). PR 6 gave every one of those kwargs a typed home under GeneratorConfig.

This test makes sure:

  1. The public typed API can represent everything Dreamverse currently passes at init time (legacy_from_pretrained_to_config).
  2. The request-path Dreamverse uses (generator.generate_video(**kwargs) with per-segment flags) round-trips through the typed GenerationRequest without reintroducing private-only fields at the public boundary.
  3. Private-only Dreamverse fields that don't belong on the public surface either go to pipeline.experimental / request.extensions (the documented escape hatch) or raise explicitly, rather than silently becoming part of the public compatibility promise.

Regression guard for the scoping rule in apirefactor.md §"Schema Parity Requirement".

Classes

fastvideo.tests.contract.test_dreamverse_shape.TestDreamverseLoadKwargsShape

Every current Dreamverse init-time kwarg must land on a typed field, not in the experimental escape hatch.

fastvideo.tests.contract.test_dreamverse_shape.TestDreamverseNoPrivateImports

The public entry points must not force a Dreamverse integrator to import from fastvideo.pipelines.* or other internal paths.

fastvideo.tests.contract.test_dreamverse_shape.TestDreamversePrivateOnlyFields

Dreamverse carries a handful of private-only names (e.g. legacy internal aliases). These must NOT silently turn into a public compatibility promise — the documented contract is that unknown fields land on pipeline.experimental so integrators see them but FastVideo does not promise to preserve them.

fastvideo.tests.contract.test_dreamverse_shape.TestDreamverseRequestShape

The per-segment Dreamverse request path mirrors OpenAI's shape plus a few LTX-2 knobs. All of them must have a typed home.

Functions
fastvideo.tests.contract.test_dreamverse_shape.TestDreamverseRequestShape.test_return_state_reaches_output_config
test_return_state_reaches_output_config()

PR 7 added output.return_state — must survive the legacy translation path so Dreamverse callers can opt in.

Source code in fastvideo/tests/contract/test_dreamverse_shape.py
def test_return_state_reaches_output_config(self):
    """PR 7 added ``output.return_state`` — must survive the legacy
    translation path so Dreamverse callers can opt in."""
    request = GenerationRequest(
        prompt="x",
        output=__import__(
            "fastvideo.api", fromlist=["OutputConfig"]).OutputConfig(
                return_state=True),
    )
    normalized = normalize_generation_request(request)
    assert normalized.output.return_state is True

fastvideo.tests.contract.test_dynamo_shape

Contract test: a mock Dynamo-style handler wraps FastVideo's public API without touching any private module.

The Dynamo backend package (components/src/dynamo/fastvideo/ in the Dynamo repo) imports only these symbols:

from fastvideo import VideoGenerator
from fastvideo.api import (
    ContinuationState, GenerationRequest, InputConfig, OutputConfig,
    SamplingConfig,
)

If a FastVideo refactor breaks the adapter shape this test fails at FastVideo CI — before the Dynamo-side integration knows. The plan (PR 7.10) requires the backend to be expressible without flat legacy LTX-2 kwargs or FastVideo-internal imports; this file asserts the subset that exists today and is stable.

Classes

fastvideo.tests.contract.test_dynamo_shape.TestDynamoHandlerContract
Functions
fastvideo.tests.contract.test_dynamo_shape.TestDynamoHandlerContract.test_handler_serializes_state_back_to_nvext
test_handler_serializes_state_back_to_nvext()

When the request carries state, the handler should be able to include a matching serialized state on the response. (Dynamo's NvVideosResponse has nvext.continuation_state reserved for this in the pending disaggregation path.)

Source code in fastvideo/tests/contract/test_dynamo_shape.py
def test_handler_serializes_state_back_to_nvext(self):
    """When the request carries state, the handler should be able to
    include a matching serialized state on the response. (Dynamo's
    NvVideosResponse has nvext.continuation_state reserved for this
    in the pending disaggregation path.)"""
    handler = _MockFastVideoHandler({"b64_json": "abc"})
    state_in = {
        "kind": "ltx2.v1",
        "payload": {"schema_version": 1, "segment_index": 4},
    }

    async def run():
        async for chunk in handler.generate(
                _nv_create_video_request(
                    nvext={"continuation_state": state_in}),
                _FakeContext()):
            return chunk
        raise AssertionError("no chunk emitted")

    chunk = asyncio.run(run())
    assert chunk["nvext"]["continuation_state"]["kind"] == "ltx2.v1"
    assert (
        chunk["nvext"]["continuation_state"]["payload"]["segment_index"]
        == 4)
fastvideo.tests.contract.test_dynamo_shape.TestNoInternalImports

The adapter template in this file imports only the public surface.

Any change to FastVideo that requires the Dynamo adapter to reach into a private module would make this test fail at review time.

Functions

fastvideo.tests.contract.test_dynamo_shape.nv_request_to_generation_request
nv_request_to_generation_request(request: dict[str, Any]) -> GenerationRequest

Translate Dynamo's request shape into FastVideo's typed request.

This function is the template integrators copy into the Dynamo repo. It uses only public FastVideo symbols.

Source code in fastvideo/tests/contract/test_dynamo_shape.py
def nv_request_to_generation_request(
    request: dict[str, Any], ) -> GenerationRequest:
    """Translate Dynamo's request shape into FastVideo's typed request.

    This function is the template integrators copy into the Dynamo repo.
    It uses only public FastVideo symbols.
    """
    nvext = request.get("nvext") or {}
    width, height = _parse_size(request.get("size"))
    fps = nvext.get("fps") or 24
    num_frames = nvext.get("num_frames") or (request.get("seconds") or 4) * fps

    state = nvext.get("continuation_state")
    if isinstance(state, dict):
        state = ContinuationState(kind=state["kind"], payload=state["payload"])

    return GenerationRequest(
        prompt=request["prompt"],
        negative_prompt=nvext.get("negative_prompt"),
        inputs=InputConfig(image_path=request.get("input_reference")),
        sampling=SamplingConfig(
            width=width,
            height=height,
            num_frames=num_frames,
            fps=fps,
            num_inference_steps=nvext.get("num_inference_steps", 50),
            guidance_scale=nvext.get("guidance_scale", 1.0),
            seed=nvext.get("seed", 1024),
            true_cfg_scale=nvext.get("true_cfg_scale"),
        ),
        output=OutputConfig(save_video=False, return_frames=False),
        state=state,
    )

fastvideo.tests.contract.test_generate_async

Contract tests for VideoGenerator.generate_async.

These tests monkey-patch the synchronous _generate_request_impl so the suite runs CPU-only -- the async wrapper is the piece under test, not the pipeline.

Classes

fastvideo.tests.contract.test_generate_async.TestDynamoStyleHandlerIntegration

Mirror the shape the Dynamo backend package uses.