diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index be6461c93be..f818927f6a3 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -19,7 +19,6 @@ UnidentifiedImageError, features, ) -from PIL._typing import Buffer from .helper import ( assert_image, @@ -41,7 +40,6 @@ except ImportError: ElementTree = None - TEST_FILE = "Tests/images/hopper.jpg" @@ -1066,7 +1064,7 @@ def test_eof(self, monkeypatch: pytest.MonkeyPatch) -> None: # the image should still end when there is no new data class InfiniteMockPyDecoder(ImageFile.PyDecoder): def decode( - self, buffer: Buffer | Image.SupportsArrayInterface + self, buffer: bytes | Image.SupportsArrayInterface ) -> tuple[int, int]: return 0, 0 diff --git a/Tests/test_image_frombytes.py b/Tests/test_image_frombytes.py index 18aa4ccf108..06b4c5b3118 100644 --- a/Tests/test_image_frombytes.py +++ b/Tests/test_image_frombytes.py @@ -11,7 +11,7 @@ def test_sanity(data_type: str) -> None: im1 = hopper() - data: bytes | memoryview[int] = im1.tobytes() + data: bytes | memoryview = im1.tobytes() if data_type == "memoryview": data = memoryview(data) im2 = Image.frombytes(im1.mode, im1.size, data) diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index ec3cdfaec4e..7dfb3abf986 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -14,7 +14,6 @@ _binary, features, ) -from PIL._typing import Buffer from .helper import ( assert_image, @@ -239,7 +238,7 @@ def __init__(self, mode: str, *args: Any) -> None: super().__init__(mode, *args) - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: # eof return -1, 0 diff --git a/Tests/test_imagewin.py b/Tests/test_imagewin.py index 505dcbe8e68..36df32aff66 100644 --- a/Tests/test_imagewin.py +++ b/Tests/test_imagewin.py @@ -116,7 +116,7 @@ def test_dib_frombytes_tobytes_roundtrip(self) -> None: # Act # Make one the same as the using tobytes()/frombytes() - test_buffer: bytes | memoryview[int] = dib1.tobytes() + test_buffer: bytes | memoryview = dib1.tobytes() for datatype in ("bytes", "memoryview"): if datatype == "memoryview": test_buffer = memoryview(test_buffer) diff --git a/Tests/test_qt_image_toqimage.py b/Tests/test_qt_image_toqimage.py index 5647847d427..0004b552153 100644 --- a/Tests/test_qt_image_toqimage.py +++ b/Tests/test_qt_image_toqimage.py @@ -10,15 +10,13 @@ if TYPE_CHECKING: from pathlib import Path - QImage = type -else: - if ImageQt.qt_is_installed: - from PIL.ImageQt import QImage - pytestmark = pytest.mark.skipif( not ImageQt.qt_is_installed, reason="Qt bindings are not installed" ) +if ImageQt.qt_is_installed: + from PIL.ImageQt import QImage + @pytest.mark.parametrize("mode", ("RGB", "RGBA", "L", "P", "1")) def test_sanity(mode: str, tmp_path: Path) -> None: diff --git a/docs/example/DdsImagePlugin.py b/docs/example/DdsImagePlugin.py index 7a054dcca5e..e0557976c28 100644 --- a/docs/example/DdsImagePlugin.py +++ b/docs/example/DdsImagePlugin.py @@ -14,16 +14,10 @@ import struct from io import BytesIO +from typing import IO from PIL import Image, ImageFile -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import IO - - from typing_extensions import Buffer - - # Magic ("DDS ") DDS_MAGIC = 0x20534444 @@ -264,7 +258,7 @@ def load_seek(self, pos: int) -> None: class DXT1Decoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None try: self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize)) @@ -277,7 +271,7 @@ def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, in class DXT5Decoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None try: self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize)) diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index 11139c3522d..6bb92edf891 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -39,7 +39,6 @@ from typing import IO from . import Image, ImageFile -from ._typing import Buffer class Format(IntEnum): @@ -296,7 +295,7 @@ def _open(self) -> None: class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: try: self._read_header() self._load() diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index 810c19d2504..a1227137017 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -33,7 +33,6 @@ from ._binary import o8 from ._binary import o16le as o16 from ._binary import o32le as o32 -from ._typing import Buffer # # -------------------------------------------------------------------- @@ -328,7 +327,7 @@ def _open(self) -> None: class BmpRleDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None rle4 = self.args[1] data = bytearray() diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index 4a61759f61e..312f602a6b1 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -21,7 +21,6 @@ from ._binary import i32le as i32 from ._binary import o8 from ._binary import o32le as o32 -from ._typing import Buffer # Magic ("DDS ") DDS_MAGIC = 0x20534444 @@ -489,7 +488,7 @@ def load_seek(self, pos: int) -> None: class DdsRgbDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None bitcount, masks = self.args diff --git a/src/PIL/FitsImagePlugin.py b/src/PIL/FitsImagePlugin.py index 943dd62c580..a3fdc0efeec 100644 --- a/src/PIL/FitsImagePlugin.py +++ b/src/PIL/FitsImagePlugin.py @@ -14,7 +14,6 @@ import math from . import Image, ImageFile -from ._typing import Buffer def _accept(prefix: bytes) -> bool: @@ -127,7 +126,7 @@ def _parse_headers( class FitsGzipDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None value = gzip.decompress(self.fd.read()) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 64378d52a8e..76a0d4ab99f 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -52,6 +52,7 @@ from typing import IO, Literal from . import _imaging + from ._typing import Buffer class LoadingStrategy(IntEnum): @@ -1187,7 +1188,7 @@ def getdata( class Collector(BytesIO): data = [] - def write(self, data: bytes) -> int: # type: ignore[override] + def write(self, data: Buffer) -> int: self.data.append(data) return len(data) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 394b333abba..6d79e280677 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -88,45 +88,37 @@ class DecompressionBombError(Exception): MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3) -if TYPE_CHECKING: - from . import _imaging - - # mypy will not recognize `core` as a public symbol when imported as - # `from . import _imaging as core` - core = _imaging -else: - try: - # If the _imaging C module is not present, Pillow will not load. - # Note that other modules should not refer to _imaging directly; - # import Image and use the Image.core variable instead. - # Also note that Image.core is not a publicly documented interface, - # and should be considered private and subject to change. - from . import _imaging as core - - if __version__ != getattr(core, "PILLOW_VERSION", None): - msg = ( - f"The _imaging extension was built for another version of Pillow or " - f"PIL:\n " - f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n" - f"Pillow version: {__version__}" - ) - raise ImportError(msg) +try: + # If the _imaging C module is not present, Pillow will not load. + # Note that other modules should not refer to _imaging directly; + # import Image and use the Image.core variable instead. + # Also note that Image.core is not a publicly documented interface, + # and should be considered private and subject to change. + from . import _imaging as core + + if __version__ != getattr(core, "PILLOW_VERSION", None): + msg = ( + "The _imaging extension was built for another version of Pillow or PIL:\n" + f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n" + f"Pillow version: {__version__}" + ) + raise ImportError(msg) - except ImportError as v: - # Explanations for ways that we know we might have an import error - if str(v).startswith("Module use of python"): - # The _imaging C module is present, but not compiled for - # the right version (windows only). Print a warning, if - # possible. - warnings.warn( - "The _imaging extension was built for another version of Python.", - RuntimeWarning, - ) - elif str(v).startswith("The _imaging extension"): - warnings.warn(str(v), RuntimeWarning) - # Fail here anyway. Don't let people run with a mostly broken Pillow. - # see docs/porting.rst - raise +except ImportError as v: + # Explanations for ways that we know we might have an import error + if str(v).startswith("Module use of python"): + # The _imaging C module is present, but not compiled for + # the right version (windows only). Print a warning, if + # possible. + warnings.warn( + "The _imaging extension was built for another version of Python.", + RuntimeWarning, + ) + elif str(v).startswith("The _imaging extension"): + warnings.warn(str(v), RuntimeWarning) + # Fail here anyway. Don't let people run with a mostly broken Pillow. + # see docs/porting.rst + raise # diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index 81a288858bb..277087a8677 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -31,7 +31,6 @@ from . import Image, ImageFile from ._binary import i16le as i16 from ._binary import o16le as o16 -from ._typing import Buffer # # read MSP files @@ -113,7 +112,7 @@ class MspDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None img = io.BytesIO() diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index f537c78bb9e..1fdf6ec8d52 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -322,7 +322,7 @@ def __init__(self, dictionary: PdfDict, buf: Buffer) -> None: self.dictionary = dictionary self.buf = buf - def decode(self) -> Buffer: + def decode(self) -> bytes: try: filter = self.dictionary[b"Filter"] except KeyError: diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index 6bc5c8e0a03..5b17216156a 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -22,7 +22,6 @@ from ._binary import i16be as i16 from ._binary import o8 from ._binary import o32le as o32 -from ._typing import Buffer # # -------------------------------------------------------------------- @@ -217,9 +216,8 @@ def _decode_bitonal(self) -> bytearray: data = bytearray() total_bytes = self.state.xsize * self.state.ysize - block: bytes | bytearray while len(data) != total_bytes: - block = self._read_block() # read next block + block: bytes | bytearray = self._read_block() # read next block if not block: # eof break @@ -286,7 +284,7 @@ def _decode_blocks(self, maxval: int) -> bytearray: break return data - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: self._comment_spans = False if self.mode == "1": data = self._decode_bitonal() @@ -302,7 +300,7 @@ def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, in class PpmDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None data = bytearray() diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index 0dd6e7416b6..f6e2e831cab 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -14,7 +14,6 @@ from ._binary import i32be as i32 from ._binary import o8 from ._binary import o32be as o32 -from ._typing import Buffer def _accept(prefix: bytes) -> bool: @@ -52,7 +51,7 @@ def _add_to_previous_pixels(self, value: bytes | bytearray) -> None: hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64 self._previously_seen_pixels[hash_value] = value - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None self._previously_seen_pixels = {} diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index 336f859fb36..853022150ae 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -29,7 +29,6 @@ from . import Image, ImageFile from ._binary import i16be as i16 from ._binary import o8 -from ._typing import Buffer def _accept(prefix: bytes) -> bool: @@ -199,7 +198,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: class SGI16Decoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None assert self.im is not None diff --git a/src/PIL/XpmImagePlugin.py b/src/PIL/XpmImagePlugin.py index 55302fab4fb..3be240fbc1a 100644 --- a/src/PIL/XpmImagePlugin.py +++ b/src/PIL/XpmImagePlugin.py @@ -19,7 +19,6 @@ from . import Image, ImageFile, ImagePalette from ._binary import o8 -from ._typing import Buffer # XPM header xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)') @@ -119,7 +118,7 @@ def load_read(self, read_bytes: int) -> bytes: class XpmDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: assert self.fd is not None data = bytearray() diff --git a/src/PIL/_typing.py b/src/PIL/_typing.py index 19c6a4d6a32..a941f89806f 100644 --- a/src/PIL/_typing.py +++ b/src/PIL/_typing.py @@ -21,13 +21,10 @@ else: CapsuleType = object -if TYPE_CHECKING: - from typing_extensions import Buffer +if sys.version_info >= (3, 12): + from collections.abc import Buffer else: - if sys.version_info >= (3, 12): - from collections.abc import Buffer - else: - Buffer = Any + Buffer = Any _Ink = float | tuple[int, ...] | str