Compare commits

..

9 Commits

Author SHA1 Message Date
Sayak Paul
28052b0691 Merge branch 'main' into tests-load-components 2026-03-20 16:07:07 +05:30
Sayak Paul
522b523e40 [ci] hoping to fix is_flaky with wanvace. (#13294)
* hoping to fix is_flaky with wanvace.

* revert changes in src/diffusers/utils/testing_utils.py and propagate them to tests/testing_utils.py.

* up
2026-03-20 16:02:16 +05:30
Sayak Paul
443d73584b Merge branch 'main' into tests-load-components 2026-03-20 12:32:42 +05:30
Sayak Paul
faca9b90a7 Merge branch 'main' into tests-load-components 2026-03-12 20:57:38 +05:30
sayakpaul
a1f63a398c up 2026-03-10 17:55:08 +05:30
sayakpaul
bf846f722c u[ 2026-03-10 17:49:51 +05:30
sayakpaul
78a86e85cf fix 2026-03-10 17:46:55 +05:30
sayakpaul
7673ab1757 fix 2026-03-10 16:50:27 +05:30
sayakpaul
b7648557d4 test load_components. 2026-03-10 16:09:02 +05:30
4 changed files with 63 additions and 65 deletions

View File

@@ -1,34 +0,0 @@
# PR Review Rules
Rules for Claude to check during PR reviews. Focus on correctness — style is handled by ruff.
## Code style
- Inline logic — minimize small helper/utility functions. A reader should follow the full flow without jumping between functions.
- No defensive code or unused code paths — no fallback paths, safety checks, or config options "just in case".
- No silent fallbacks — raise a concise error for unsupported cases rather than guessing user intent.
## Dependencies
- No new mandatory dependencies without prior discussion.
- Optional deps must be guarded with `is_X_available()` and have a dummy in `utils/dummy_*.py`.
- Never use `einops` — rewrite with native PyTorch (`reshape`, `permute`, `unflatten`).
## Models
- All layer calls must be visible directly in `forward()` — no helper functions hiding `nn.Module` calls.
- No NumPy operations in `forward()` — breaks `torch.compile` with `fullgraph=True`.
- No hardcoded dtypes (e.g. `torch.float32`, `torch.bfloat16`) in forward — use input tensor dtype or `self.dtype`.
- Attention must use `dispatch_attention_fn`, not `F.scaled_dot_product_attention` directly.
- Every `__init__` parameter in a `ModelMixin` subclass must be captured by `register_to_config`.
- New classes must be registered in `__init__.py` with lazy imports (both `_import_structure` and `_lazy_modules`).
## Pipelines
- Must inherit from `DiffusionPipeline`.
- `@torch.no_grad()` on pipeline `__call__` — forgetting this causes OOM from gradient accumulation.
- Do NOT subclass an existing pipeline for a variant (e.g. don't subclass `FluxPipeline` for `FluxImg2ImgPipeline`).
- Support `output_type="latent"` for skipping VAE decode.
- Support `generator` parameter for reproducibility.
## Copied code
- Never edit a `# Copied from` block directly — run `make fix-copies` to propagate changes from the source.
- Remove the `# Copied from` header to intentionally break the sync link.
## Common mistakes (add new rules below this line)

View File

@@ -1,27 +0,0 @@
name: Claude PR Review
on:
issue_comment:
types: [created]
permissions:
contents: write
pull-requests: write
issues: read
jobs:
claude-review:
if: |
github.event.issue.pull_request &&
github.event.issue.state == 'open' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'COLLABORATOR')
runs-on: ubuntu-latest
steps:
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: |
--append-system-prompt "Review this PR against the rules in .ai/review-rules.md. Focus on correctness, not style (ruff handles style). Only review changes under src/diffusers/."

View File

@@ -28,7 +28,6 @@ from diffusers.utils.import_utils import is_peft_available
from ..testing_utils import (
floats_tensor,
is_flaky,
require_peft_backend,
require_peft_version_greater,
skip_mps,
@@ -46,7 +45,6 @@ from .utils import PeftLoraLoaderMixinTests # noqa: E402
@require_peft_backend
@skip_mps
@is_flaky(max_attempts=10, description="very flaky class")
class WanVACELoRATests(unittest.TestCase, PeftLoraLoaderMixinTests):
pipeline_class = WanVACEPipeline
scheduler_cls = FlowMatchEulerDiscreteScheduler
@@ -73,8 +71,8 @@ class WanVACELoRATests(unittest.TestCase, PeftLoraLoaderMixinTests):
"base_dim": 3,
"z_dim": 4,
"dim_mult": [1, 1, 1, 1],
"latents_mean": torch.randn(4).numpy().tolist(),
"latents_std": torch.randn(4).numpy().tolist(),
"latents_mean": [-0.7571, -0.7089, -0.9113, -0.7245],
"latents_std": [2.8184, 1.4541, 2.3275, 2.6558],
"num_res_blocks": 1,
"temperal_downsample": [False, True, True],
}

View File

@@ -5,6 +5,7 @@ from typing import Callable
import pytest
import torch
from huggingface_hub import hf_hub_download
import diffusers
from diffusers import AutoModel, ComponentsManager, ModularPipeline, ModularPipelineBlocks
@@ -32,6 +33,33 @@ from ..testing_utils import (
)
def _get_specified_components(path_or_repo_id, cache_dir=None):
if os.path.isdir(path_or_repo_id):
config_path = os.path.join(path_or_repo_id, "modular_model_index.json")
else:
try:
config_path = hf_hub_download(
repo_id=path_or_repo_id,
filename="modular_model_index.json",
local_dir=cache_dir,
)
except Exception:
return None
with open(config_path) as f:
config = json.load(f)
components = set()
for k, v in config.items():
if isinstance(v, (str, int, float, bool)):
continue
for entry in v:
if isinstance(entry, dict) and (entry.get("repo") or entry.get("pretrained_model_name_or_path")):
components.add(k)
break
return components
class ModularPipelineTesterMixin:
"""
It provides a set of common tests for each modular pipeline,
@@ -360,6 +388,39 @@ class ModularPipelineTesterMixin:
assert torch.abs(image_slices[0] - image_slices[1]).max() < 1e-3
def test_load_expected_components_from_pretrained(self, tmp_path):
pipe = self.get_pipeline()
expected = _get_specified_components(self.pretrained_model_name_or_path, cache_dir=tmp_path)
if not expected:
pytest.skip("Skipping test as we couldn't fetch the expected components.")
actual = {
name
for name in pipe.components
if getattr(pipe, name, None) is not None
and getattr(getattr(pipe, name), "_diffusers_load_id", None) not in (None, "null")
}
assert expected == actual, f"Component mismatch: missing={expected - actual}, unexpected={actual - expected}"
def test_load_expected_components_from_save_pretrained(self, tmp_path):
pipe = self.get_pipeline()
save_dir = str(tmp_path / "saved-pipeline")
pipe.save_pretrained(save_dir)
expected = _get_specified_components(save_dir)
loaded_pipe = ModularPipeline.from_pretrained(save_dir)
loaded_pipe.load_components(torch_dtype=torch.float32)
actual = {
name
for name in loaded_pipe.components
if getattr(loaded_pipe, name, None) is not None
and getattr(getattr(loaded_pipe, name), "_diffusers_load_id", None) not in (None, "null")
}
assert expected == actual, (
f"Component mismatch after save/load: missing={expected - actual}, unexpected={actual - expected}"
)
def test_modular_index_consistency(self, tmp_path):
pipe = self.get_pipeline()
components_spec = pipe._component_specs