From d961a388fd02e4db38d17350c8dd9b8abe642e05 Mon Sep 17 00:00:00 2001 From: Patrick Ribbsaeter Date: Thu, 8 Oct 2026 10:24:47 +0200 Subject: [PATCH] fix(image_processor): maintain 3-tuple return contract in InpaintProcessor.preprocess when mask is None (#14481) fix(image_processor): preserve 3-tuple return contract when mask is None (#14470) Ensure InpaintProcessor.preprocess returns (image, None, postprocessing_kwargs) when mask is None, preserving the expected 3-tuple return contract and signature consistency across all preprocess branches. Consolidate unit tests into a parameterized test covering with-mask, without-mask, and crop configurations. --- src/diffusers/image_processor.py | 11 ++++++-- tests/others/test_image_processor.py | 38 +++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/diffusers/image_processor.py b/src/diffusers/image_processor.py index 4f6f4bd..6dccc02 100644 --- a/src/diffusers/image_processor.py +++ b/src/diffusers/image_processor.py @@ -14,6 +14,7 @@ import math import warnings +from typing import Any import numpy as np import PIL.Image @@ -885,7 +886,7 @@ class InpaintProcessor(ConfigMixin): height: int | None = None, width: int | None = None, padding_mask_crop: int | None = None, - ) -> tuple[torch.Tensor, torch.Tensor]: + ) -> tuple[torch.Tensor, torch.Tensor | None, dict[str, Any]]: """ Preprocess the image and mask. """ @@ -894,7 +895,13 @@ class InpaintProcessor(ConfigMixin): # if mask is None, same behavior as regular image processor if mask is None: - return self._image_processor.preprocess(image, height=height, width=width) + processed_image = self._image_processor.preprocess(image, height=height, width=width) + postprocessing_kwargs = { + "crops_coords": None, + "original_image": None, + "original_mask": None, + } + return processed_image, None, postprocessing_kwargs if padding_mask_crop is not None: crops_coords = self._image_processor.get_crop_region(mask, width, height, pad=padding_mask_crop) diff --git a/tests/others/test_image_processor.py b/tests/others/test_image_processor.py index 0d35869..05cbb8a 100644 --- a/tests/others/test_image_processor.py +++ b/tests/others/test_image_processor.py @@ -15,9 +15,10 @@ import numpy as np import PIL.Image +import pytest import torch -from diffusers.image_processor import VaeImageProcessor +from diffusers.image_processor import InpaintProcessor, VaeImageProcessor class TestImageProcessor: @@ -306,3 +307,38 @@ class TestImageProcessor: assert out_np.shape == exp_np_shape, ( f"resized image output shape '{out_np.shape}' didn't match expected shape '{exp_np_shape}'." ) + + @pytest.mark.parametrize( + "has_mask, padding_mask_crop", + [ + (True, None), + (False, None), + (True, 8), + ], + ) + def test_inpaint_processor_preprocess(self, has_mask, padding_mask_crop): + processor = InpaintProcessor() + image = PIL.Image.fromarray(np.zeros((64, 64, 3), dtype=np.uint8)) + mask = PIL.Image.fromarray(np.ones((64, 64), dtype=np.uint8) * 255) if has_mask else None + + kwargs = {"height": 64, "width": 64} + if padding_mask_crop is not None: + kwargs["padding_mask_crop"] = padding_mask_crop + + out_img, out_mask, postprocessing_kwargs = processor.preprocess(image, mask=mask, **kwargs) + + assert isinstance(out_img, torch.Tensor) + if has_mask: + assert isinstance(out_mask, torch.Tensor) + else: + assert out_mask is None + assert isinstance(postprocessing_kwargs, dict) + + if padding_mask_crop is not None: + assert postprocessing_kwargs["crops_coords"] is not None + assert postprocessing_kwargs["original_image"] == image + assert postprocessing_kwargs["original_mask"] == mask + else: + assert postprocessing_kwargs["crops_coords"] is None + assert postprocessing_kwargs["original_image"] is None + assert postprocessing_kwargs["original_mask"] is None -- 2.55.0.windows.3