Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
UnidentifiedImageError,
features,
)
from PIL._typing import Buffer

from .helper import (
assert_image,
Expand All @@ -41,7 +40,6 @@
except ImportError:
ElementTree = None


TEST_FILE = "Tests/images/hopper.jpg"


Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_image_frombytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions Tests/test_imagefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
_binary,
features,
)
from PIL._typing import Buffer

from .helper import (
assert_image,
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imagewin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 3 additions & 5 deletions Tests/test_qt_image_toqimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
12 changes: 3 additions & 9 deletions docs/example/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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))
Expand All @@ -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))
Expand Down
3 changes: 1 addition & 2 deletions src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
from typing import IO

from . import Image, ImageFile
from ._typing import Buffer


class Format(IntEnum):
Expand Down Expand Up @@ -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()
Expand Down
3 changes: 1 addition & 2 deletions src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from ._binary import o8
from ._binary import o16le as o16
from ._binary import o32le as o32
from ._typing import Buffer

#
# --------------------------------------------------------------------
Expand Down Expand Up @@ -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()
Expand Down
3 changes: 1 addition & 2 deletions src/PIL/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
3 changes: 1 addition & 2 deletions src/PIL/FitsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import math

from . import Image, ImageFile
from ._typing import Buffer


def _accept(prefix: bytes) -> bool:
Expand Down Expand Up @@ -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())

Expand Down
3 changes: 2 additions & 1 deletion src/PIL/GifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
from typing import IO, Literal

from . import _imaging
from ._typing import Buffer


class LoadingStrategy(IntEnum):
Expand Down Expand Up @@ -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)

Expand Down
68 changes: 30 additions & 38 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


#
Expand Down
3 changes: 1 addition & 2 deletions src/PIL/MspImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm strange, I thought this was an LSP violation 🤔. Maybe it's a mypy false negative? Either way, I'm fine with reverting this :)

assert self.fd is not None

img = io.BytesIO()
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/PdfParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 3 additions & 5 deletions src/PIL/PpmImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from ._binary import i16be as i16
from ._binary import o8
from ._binary import o32le as o32
from ._typing import Buffer

#
# --------------------------------------------------------------------
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down
3 changes: 1 addition & 2 deletions src/PIL/QoiImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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 = {}
Expand Down
3 changes: 1 addition & 2 deletions src/PIL/SgiImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down
3 changes: 1 addition & 2 deletions src/PIL/XpmImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]*)')
Expand Down Expand Up @@ -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()
Expand Down
Loading