Repository: huggingface/transformers
Pull request: Force new vision models addition to include a fast image processor

# What does this PR do?

As the title says, this adds a test that will fail for models added after September 1st 2025, if they include a slow image processor but not a fast one.
Cc @qubvel as we discussed this

Changed files:
filename: tests/test_image_processing_common.py
patch: @@ -16,11 +16,13 @@
 import json
 import os
 import pathlib
+import subprocess
 import tempfile
 import time
 import unittest
 import warnings
 from copy import deepcopy
+from datetime import datetime
 
 import httpx
 import numpy as np
@@ -29,6 +31,7 @@
 
 from transformers import AutoImageProcessor, BatchFeature
 from transformers.image_utils import AnnotationFormat, AnnotionFormat
+from transformers.models.auto.image_processing_auto import IMAGE_PROCESSOR_MAPPING_NAMES
 from transformers.testing_utils import (
     check_json_file_has_correct_format,
     require_torch,
@@ -630,6 +633,66 @@ def test_can_compile_fast_image_processor(self):
             output_eager.pixel_values, output_compiled.pixel_values, atol=1e-4, rtol=1e-4, mean_atol=1e-5
         )
 
+    def test_new_models_require_fast_image_processor(self):
+        """
+        Test that new models have a fast image processor.
+        For more information on how to implement a fast image processor, see this issue: https://github.com/huggingface/transformers/issues/36978,
+        and ping @yonigozlan for help.
+        """
+        if self.fast_image_processing_class is not None:
+            return
+        if self.image_processing_class is None:
+            self.skipTest("No image processing class defined")
+
+        def _is_old_model_by_commit_date(model_type, date_cutoff=(2025, 9, 1)):
+            try:
+                # Convert model_type to directory name and construct file path
+                model_dir = model_type.replace("-", "_")
+                slow_processor_file = f"src/transformers/models/{model_dir}/image_processing_{model_dir}.py"
+                # Check if the file exists otherwise skip the test
+                if not os.path.exists(slow_processor_file):
+                    return None
+                # Get the first commit date of the slow processor file
+                result = subprocess.run(
+                    ["git", "log", "--reverse", "--pretty=format:%ad", "--date=iso", slow_processor_file],
+                    capture_output=True,
+                    text=True,
+                    cwd=os.getcwd(),
+                )
+                if result.returncode != 0 or not result.stdout.strip():
+                    return None
+                # Parse the first line (earliest commit)
+                first_line = result.stdout.strip().split("\n")[0]
+                date_part = first_line.split(" ")[0]  # Extract just the date part
+                commit_date = datetime.strptime(date_part, "%Y-%m-%d")
+                # Check if committed before the cutoff date
+                cutoff_date = datetime(*date_cutoff)
+                return commit_date <= cutoff_date
+
+            except Exception:
+                # If any error occurs, skip the test
+                return None
+
+        image_processor_name = self.image_processing_class.__name__
+        model_type = None
+        for mapping_model_type, (slow_class, _) in IMAGE_PROCESSOR_MAPPING_NAMES.items():
+            if slow_class == image_processor_name:
+                model_type = mapping_model_type
+                break
+
+        if model_type is None:
+            self.skipTest(f"Could not find model type for {image_processor_name} in IMAGE_PROCESSOR_MAPPING_NAMES")
+        # Check if this is a new model (added after 2024-01-01) based on git history
+        is_old_model = _is_old_model_by_commit_date(model_type)
+        if is_old_model is None:
+            self.skipTest(f"Could not determine if {model_type} is new based on git history")
+        # New models must have fast processors
+        self.assertTrue(
+            is_old_model,
+            f"Model '{model_type}' (processor: {image_processor_name}) was added after the cutoff date and must have "
+            f"a fast image processor implementation. Please implement the corresponding fast processor.",
+        )
+
 
 class AnnotationFormatTestMixin:
     # this mixin adds a test to assert that usages of the