From 7a94096c22be0551e2a848faaec513aed0695065 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 25 Mar 2026 14:10:27 +0530 Subject: [PATCH 1/3] tighten dependency testing. --- .../workflows/pr_torch_dependency_test.yml | 2 +- .../pipelines/consisid/consisid_utils.py | 9 ++-- tests/others/test_dependencies.py | 54 ++++++++++++++++--- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pr_torch_dependency_test.yml b/.github/workflows/pr_torch_dependency_test.yml index 79569488ae21..2e7139e40ea7 100644 --- a/.github/workflows/pr_torch_dependency_test.yml +++ b/.github/workflows/pr_torch_dependency_test.yml @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: | pip install -e . - pip install torch torchvision torchaudio pytest + pip install torch pytest - name: Check for soft dependencies run: | pytest tests/others/test_dependencies.py diff --git a/src/diffusers/pipelines/consisid/consisid_utils.py b/src/diffusers/pipelines/consisid/consisid_utils.py index c1646e15efbc..07bba890c383 100644 --- a/src/diffusers/pipelines/consisid/consisid_utils.py +++ b/src/diffusers/pipelines/consisid/consisid_utils.py @@ -5,10 +5,13 @@ import numpy as np import torch from PIL import Image, ImageOps -from torchvision.transforms import InterpolationMode -from torchvision.transforms.functional import normalize, resize -from ...utils import get_logger, load_image +from ...utils import get_logger, is_torchvision_available, load_image + + +if is_torchvision_available(): + from torchvision.transforms import InterpolationMode + from torchvision.transforms.functional import normalize, resize logger = get_logger(__name__) diff --git a/tests/others/test_dependencies.py b/tests/others/test_dependencies.py index db22f10c4b3c..504d3e60861f 100644 --- a/tests/others/test_dependencies.py +++ b/tests/others/test_dependencies.py @@ -13,16 +13,15 @@ # limitations under the License. import inspect -import unittest from importlib import import_module +from pathlib import Path +import pytest -class DependencyTester(unittest.TestCase): + +class TestDependencies: def test_diffusers_import(self): - try: - import diffusers # noqa: F401 - except ImportError: - assert False + import diffusers # noqa: F401 def test_backend_registration(self): import diffusers @@ -52,3 +51,46 @@ def test_pipeline_imports(self): if hasattr(diffusers.pipelines, cls_name): pipeline_folder_module = ".".join(str(cls_module.__module__).split(".")[:3]) _ = import_module(pipeline_folder_module, str(cls_name)) + + def test_pipeline_module_imports(self): + """Import every pipeline submodule whose folder-level dependency guards + are satisfied, to catch unguarded optional-dep imports. + + Each pipeline folder's __init__.py evaluates guards like + is_torch_available() and populates _import_structure only for submodules + whose deps are met. We use _import_structure as the source of truth: + if a submodule is listed there, its declared deps are installed, so any + ImportError from importing it is a real bug (e.g., unguarded torchvision). + """ + import diffusers.pipelines + + pipelines_dir = Path(diffusers.pipelines.__file__).parent + failures = [] + + for subdir in sorted(pipelines_dir.iterdir()): + if not subdir.is_dir() or not (subdir / "__init__.py").exists(): + continue + + # Import the pipeline package to trigger its guard evaluation + package_module_path = f"diffusers.pipelines.{subdir.name}" + try: + package_module = import_module(package_module_path) + except Exception: + continue + + # _import_structure keys are the submodules whose deps are satisfied + import_structure = getattr(package_module, "_import_structure", {}) + + for submodule_name in import_structure: + full_module_path = f"{package_module_path}.{submodule_name}" + try: + import_module(full_module_path) + except ImportError as e: + failures.append(f"{full_module_path}: {e}") + except Exception: + # Non-import errors (e.g., missing config) are fine; we only + # care about unguarded import statements. + pass + + if failures: + pytest.fail("Unguarded optional-dependency imports found:\n" + "\n".join(failures)) From cebed06b2a45c6b8a365a84b1eba4196ab51edfa Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 25 Mar 2026 14:13:48 +0530 Subject: [PATCH 2/3] invoke dependency testing temporarily. --- .github/workflows/pr_dependency_test.yml | 1 + .github/workflows/pr_torch_dependency_test.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/pr_dependency_test.yml b/.github/workflows/pr_dependency_test.yml index ba5cd1c76cbc..e89e71de6d75 100644 --- a/.github/workflows/pr_dependency_test.yml +++ b/.github/workflows/pr_dependency_test.yml @@ -6,6 +6,7 @@ on: - main paths: - "src/diffusers/**.py" + - "tests/**.py" push: branches: - main diff --git a/.github/workflows/pr_torch_dependency_test.yml b/.github/workflows/pr_torch_dependency_test.yml index 2e7139e40ea7..27b4483ac5dd 100644 --- a/.github/workflows/pr_torch_dependency_test.yml +++ b/.github/workflows/pr_torch_dependency_test.yml @@ -6,6 +6,7 @@ on: - main paths: - "src/diffusers/**.py" + - "tests/**.py" push: branches: - main From e2f8851b0b428e4188b4df8471e7f0ca4d25eb5f Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 25 Mar 2026 14:22:25 +0530 Subject: [PATCH 3/3] f --- tests/others/test_dependencies.py | 47 ++++++++++++------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/tests/others/test_dependencies.py b/tests/others/test_dependencies.py index 504d3e60861f..b2e28077b131 100644 --- a/tests/others/test_dependencies.py +++ b/tests/others/test_dependencies.py @@ -14,7 +14,6 @@ import inspect from importlib import import_module -from pathlib import Path import pytest @@ -53,44 +52,34 @@ def test_pipeline_imports(self): _ = import_module(pipeline_folder_module, str(cls_name)) def test_pipeline_module_imports(self): - """Import every pipeline submodule whose folder-level dependency guards - are satisfied, to catch unguarded optional-dep imports. + """Import every pipeline submodule whose dependencies are satisfied, + to catch unguarded optional-dep imports (e.g., torchvision). - Each pipeline folder's __init__.py evaluates guards like - is_torch_available() and populates _import_structure only for submodules - whose deps are met. We use _import_structure as the source of truth: - if a submodule is listed there, its declared deps are installed, so any - ImportError from importing it is a real bug (e.g., unguarded torchvision). + Uses inspect.getmembers to discover classes that the lazy loader can + actually resolve (same self-filtering as test_pipeline_imports), then + imports the full module path instead of truncating to the folder level. """ + import diffusers import diffusers.pipelines - pipelines_dir = Path(diffusers.pipelines.__file__).parent failures = [] + all_classes = inspect.getmembers(diffusers, inspect.isclass) - for subdir in sorted(pipelines_dir.iterdir()): - if not subdir.is_dir() or not (subdir / "__init__.py").exists(): + for cls_name, cls_module in all_classes: + if not hasattr(diffusers.pipelines, cls_name): + continue + if "dummy_" in cls_module.__module__: continue - # Import the pipeline package to trigger its guard evaluation - package_module_path = f"diffusers.pipelines.{subdir.name}" + full_module_path = cls_module.__module__ try: - package_module = import_module(package_module_path) + import_module(full_module_path) + except ImportError as e: + failures.append(f"{full_module_path}: {e}") except Exception: - continue - - # _import_structure keys are the submodules whose deps are satisfied - import_structure = getattr(package_module, "_import_structure", {}) - - for submodule_name in import_structure: - full_module_path = f"{package_module_path}.{submodule_name}" - try: - import_module(full_module_path) - except ImportError as e: - failures.append(f"{full_module_path}: {e}") - except Exception: - # Non-import errors (e.g., missing config) are fine; we only - # care about unguarded import statements. - pass + # Non-import errors (e.g., missing config) are fine; we only + # care about unguarded import statements. + pass if failures: pytest.fail("Unguarded optional-dependency imports found:\n" + "\n".join(failures))