From 2309f0fa60bae05881907e374afffc2257376fbc Mon Sep 17 00:00:00 2001
From: Andrew Murray <radarhere@users.noreply.github.com>
Date: Wed, 5 Mar 2025 21:30:24 +1100
Subject: [PATCH 1/2] Inherit classes with abstractmethod from ABC

---
 src/PIL/BlpImagePlugin.py | 2 +-
 src/PIL/Image.py          | 4 ++--
 src/PIL/ImageFile.py      | 2 +-
 src/PIL/ImageFilter.py    | 2 +-
 src/PIL/ImageShow.py      | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py
index 5747c125275..f7be7746d84 100644
--- a/src/PIL/BlpImagePlugin.py
+++ b/src/PIL/BlpImagePlugin.py
@@ -291,7 +291,7 @@ def _open(self) -> None:
         self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, offset, args)]
 
 
-class _BLPBaseDecoder(ImageFile.PyDecoder):
+class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder):
     _pulls_fd = True
 
     def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
index 684c87c4d78..c9c9c2e1b16 100644
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -2966,7 +2966,7 @@ def toqpixmap(self) -> ImageQt.QPixmap:
 # Abstract handlers.
 
 
-class ImagePointHandler:
+class ImagePointHandler(abc.ABC):
     """
     Used as a mixin by point transforms
     (for use with :py:meth:`~PIL.Image.Image.point`)
@@ -2977,7 +2977,7 @@ def point(self, im: Image) -> Image:
         pass
 
 
-class ImageTransformHandler:
+class ImageTransformHandler(abc.ABC):
     """
     Used as a mixin by geometry transforms
     (for use with :py:meth:`~PIL.Image.Image.transform`)
diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py
index c3901d4888c..4bc70cc766b 100644
--- a/src/PIL/ImageFile.py
+++ b/src/PIL/ImageFile.py
@@ -438,7 +438,7 @@ def _seek_check(self, frame: int) -> bool:
         return self.tell() != frame
 
 
-class StubHandler:
+class StubHandler(abc.ABC):
     def open(self, im: StubImageFile) -> None:
         pass
 
diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py
index 1c8b29b1146..05829d0c63a 100644
--- a/src/PIL/ImageFilter.py
+++ b/src/PIL/ImageFilter.py
@@ -27,7 +27,7 @@
     from ._typing import NumpyArray
 
 
-class Filter:
+class Filter(abc.ABC):
     @abc.abstractmethod
     def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore:
         pass
diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py
index d62893d9c8b..dd240fb5500 100644
--- a/src/PIL/ImageShow.py
+++ b/src/PIL/ImageShow.py
@@ -192,7 +192,7 @@ def show_file(self, path: str, **options: Any) -> int:
     register(MacViewer)
 
 
-class UnixViewer(Viewer):
+class UnixViewer(abc.ABC, Viewer):
     format = "PNG"
     options = {"compress_level": 1, "save_all": True}
 

From d186a2a8d60ea1889d3c02c54da9c01076d233e1 Mon Sep 17 00:00:00 2001
From: Andrew Murray <radarhere@users.noreply.github.com>
Date: Wed, 5 Mar 2025 21:50:09 +1100
Subject: [PATCH 2/2] Replace NotImplementedError with abstractmethod

---
 src/PIL/ImageFile.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py
index 4bc70cc766b..1bf8a7e5f21 100644
--- a/src/PIL/ImageFile.py
+++ b/src/PIL/ImageFile.py
@@ -447,7 +447,7 @@ def load(self, im: StubImageFile) -> Image.Image:
         pass
 
 
-class StubImageFile(ImageFile):
+class StubImageFile(ImageFile, metaclass=abc.ABCMeta):
     """
     Base class for stub image loaders.
 
@@ -455,9 +455,9 @@ class StubImageFile(ImageFile):
     certain format, but relies on external code to load the file.
     """
 
+    @abc.abstractmethod
     def _open(self) -> None:
-        msg = "StubImageFile subclass must implement _open"
-        raise NotImplementedError(msg)
+        pass
 
     def load(self) -> Image.core.PixelAccess | None:
         loader = self._load()
@@ -471,10 +471,10 @@ def load(self) -> Image.core.PixelAccess | None:
         self.__dict__ = image.__dict__
         return image.load()
 
+    @abc.abstractmethod
     def _load(self) -> StubHandler | None:
         """(Hook) Find actual image loader."""
-        msg = "StubImageFile subclass must implement _load"
-        raise NotImplementedError(msg)
+        pass
 
 
 class Parser:
