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
2 changes: 1 addition & 1 deletion .ci/requirements-mypy.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mypy==1.20.2
mypy==2.1.0
arro3-compute
arro3-core
IceSpringPySideStubs-PyQt6
Expand Down
3 changes: 2 additions & 1 deletion Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,8 @@ 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: bytes | Image.SupportsArrayInterface
self,
buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface,
) -> tuple[int, int]:
return 0, 0

Expand Down
3 changes: 2 additions & 1 deletion Tests/test_file_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def helper_save_as_pdf(tmp_path: Path, mode: str, **kwargs: Any) -> str:
with open(outfile, "rb") as fp:
contents = fp.read()
size = tuple(
float(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
int(float(d))
for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
)
assert im.size == size

Expand Down
6 changes: 3 additions & 3 deletions Tests/test_format_lab.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ def test_white() -> None:

assert k == (255, 128, 128)

assert L == (255,) * 100
assert a == (128,) * 100
assert b == (128,) * 100
assert L == (255.0,) * 100
assert a == (128.0,) * 100
assert b == (128.0,) * 100


def test_green() -> None:
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 = im1.tobytes()
data: bytes | memoryview = im1.tobytes()
if data_type == "memoryview":
data = memoryview(data)
im2 = Image.frombytes(im1.mode, im1.size, data)
Expand Down
6 changes: 3 additions & 3 deletions Tests/test_imagecms.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,9 @@ def test_simple_lab() -> None:
a_data = i_lab.get_flattened_data(1)
b_data = i_lab.get_flattened_data(2)

assert l_data == (137,) * 100
assert a_data == (128,) * 100
assert b_data == (128,) * 100
assert l_data == (137.0,) * 100
assert a_data == (128.0,) * 100
assert b_data == (128.0,) * 100


def test_lab_color() -> None:
Expand Down
4 changes: 3 additions & 1 deletion Tests/test_imagefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,9 @@ def __init__(self, mode: str, *args: Any) -> None:

super().__init__(mode, *args)

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
# eof
return -1, 0

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ def test_variation_set_by_axes(font: ImageFont.FreeTypeFont) -> None:
ids=("ls", "ms", "rs", "ma", "mt", "mm", "mb", "md"),
)
def test_anchor(
layout_engine: ImageFont.Layout, anchor: str, left: int, top: int
layout_engine: ImageFont.Layout, anchor: str, left: float, top: float
) -> None:
name, text = "quick", "Quick"
path = f"Tests/images/test_anchor_{name}_{anchor}.png"
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 = 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: 6 additions & 2 deletions docs/example/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@ def load_seek(self, pos: int) -> None:
class DXT1Decoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | 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 @@ -271,7 +273,9 @@ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int
class DXT5Decoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | 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
4 changes: 3 additions & 1 deletion src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,9 @@ def _open(self) -> None:
class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
try:
self._read_header()
self._load()
Expand Down
4 changes: 3 additions & 1 deletion src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,9 @@ def _open(self) -> None:
class BmpRleDecoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None
rle4 = self.args[1]
data = bytearray()
Expand Down
4 changes: 3 additions & 1 deletion src/PIL/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,9 @@ def load_seek(self, pos: int) -> None:
class DdsRgbDecoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None
bitcount, masks = self.args

Expand Down
4 changes: 3 additions & 1 deletion src/PIL/FitsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ def _parse_headers(
class FitsGzipDecoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None
with gzip.open(self.fd) as fp:
value = fp.read(self.state.xsize * self.state.ysize * 4)
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ def tobitmap(self, name: str = "image") -> bytes:

def frombytes(
self,
data: bytes | bytearray | SupportsArrayInterface,
data: bytes | bytearray | memoryview | SupportsArrayInterface,
decoder_name: str = "raw",
*args: Any,
) -> None:
Expand Down Expand Up @@ -3241,7 +3241,7 @@ def new(
def frombytes(
mode: str,
size: tuple[int, int],
data: bytes | bytearray | SupportsArrayInterface,
data: bytes | bytearray | memoryview | SupportsArrayInterface,
decoder_name: str = "raw",
*args: Any,
) -> Image:
Expand Down
9 changes: 7 additions & 2 deletions src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,9 @@ class PyDecoder(PyCodec):
def pulls_fd(self) -> bool:
return self._pulls_fd

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
"""
Override to perform the decoding process.

Expand All @@ -849,7 +851,10 @@ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int
raise NotImplementedError(msg)

def set_as_raw(
self, data: bytes, rawmode: str | None = None, extra: tuple[Any, ...] = ()
self,
data: bytes | bytearray,
rawmode: str | None = None,
extra: tuple[Any, ...] = (),
) -> None:
"""
Convenience method to set the internal image from a stream of raw data
Expand Down
8 changes: 4 additions & 4 deletions src/PIL/ImageFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,10 @@ def __init__(self, radius: float | Sequence[float] = 2) -> None:

def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore:
xy = self.radius
if xy == (0, 0) or xy == 0:
return image.copy()
if isinstance(xy, (int, float)):
xy = (xy, xy)
if xy == (0, 0):
return image.copy()
return image.gaussian_blur(xy)


Expand Down Expand Up @@ -221,10 +221,10 @@ def __init__(self, radius: float | Sequence[float]) -> None:

def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore:
xy = self.radius
if xy == (0, 0) or xy == 0:
return image.copy()
if isinstance(xy, (int, float)):
xy = (xy, xy)
if xy == (0, 0):
return image.copy()
return image.box_blur(xy)


Expand Down
2 changes: 1 addition & 1 deletion src/PIL/ImageShow.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from . import Image

_viewers = []
_viewers: list[Viewer] = []


def register(viewer: type[Viewer] | Viewer, order: int = 1) -> None:
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/ImageWin.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def paste(
else:
self.image.paste(im.im)

def frombytes(self, buffer: bytes) -> None:
def frombytes(self, buffer: bytes | memoryview) -> None:
"""
Load display memory contents from byte data.

Expand Down
4 changes: 3 additions & 1 deletion src/PIL/MspImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ class MspDecoder(ImageFile.PyDecoder):

_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None

img = io.BytesIO()
Expand Down
6 changes: 3 additions & 3 deletions src/PIL/PdfParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ def interpret_name(cls, raw: bytes, as_text: bool = False) -> str | bytes:
@classmethod
def get_value(
cls,
data: bytes | bytearray | mmap.mmap,
data: bytes | bytearray | memoryview | mmap.mmap,
offset: int,
expect_indirect: IndirectReference | None = None,
max_nesting: int = -1,
Expand Down Expand Up @@ -902,7 +902,7 @@ def get_value(
if stream_len is None or not isinstance(stream_len, int):
msg = f"bad or missing Length in stream dict ({stream_len})"
raise PdfFormatError(msg)
stream_data = data[m.end() : m.end() + stream_len]
stream_data = bytes(data[m.end() : m.end() + stream_len])
m = cls.re_stream_end.match(data, m.end() + stream_len)
check_format_condition(m is not None, "stream end not found")
assert m is not None
Expand Down Expand Up @@ -985,7 +985,7 @@ def get_value(

@classmethod
def get_literal_string(
cls, data: bytes | bytearray | mmap.mmap, offset: int
cls, data: bytes | bytearray | memoryview | mmap.mmap, offset: int
) -> tuple[bytes, int]:
nesting_depth = 0
result = bytearray()
Expand Down
10 changes: 7 additions & 3 deletions src/PIL/PpmImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def _decode_blocks(self, maxval: int) -> bytearray:
block = self._read_block() # read next block
if not block:
if half_token:
block = bytearray(b" ") # flush half_token
block = b" " # flush half_token
else:
# eof
break
Expand Down Expand Up @@ -284,7 +284,9 @@ def _decode_blocks(self, maxval: int) -> bytearray:
break
return data

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
self._comment_spans = False
if self.mode == "1":
data = self._decode_bitonal()
Expand All @@ -300,7 +302,9 @@ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int
class PpmDecoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None

data = bytearray()
Expand Down
6 changes: 4 additions & 2 deletions src/PIL/QoiImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ 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: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None

self._previously_seen_pixels = {}
Expand Down Expand Up @@ -224,7 +226,7 @@ def encode(self, bufsize: int) -> tuple[int, int, bytes]:
data += self._write_run()
data += bytes((0, 0, 0, 0, 0, 0, 0, 1)) # padding

return len(data), 0, data
return len(data), 0, bytes(data)


Image.register_open(QoiImageFile.format, QoiImageFile, _accept)
Expand Down
4 changes: 3 additions & 1 deletion src/PIL/SgiImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
class SGI16Decoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None
assert self.im is not None

Expand Down
4 changes: 2 additions & 2 deletions src/PIL/SpiderImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import os
import struct
import sys
from typing import IO, Any, cast
from typing import IO, Any

from . import Image, ImageFile
from ._util import DeferredError
Expand Down Expand Up @@ -193,7 +193,7 @@ def seek(self, frame: int) -> None:
def convert2byte(self, depth: int = 255) -> Image.Image:
extrema = self.getextrema()
assert isinstance(extrema[0], float)
minimum, maximum = cast(tuple[float, float], extrema)
minimum, maximum = extrema
m: float = 1
if maximum != minimum:
m = depth / (maximum - minimum)
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/TiffImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ def _limit_signed_rational(
##
# Wrapper for TIFF IFDs.

_load_dispatch = {}
_write_dispatch = {}
_load_dispatch: dict[int, tuple[int, _LoaderFunc]] = {}
_write_dispatch: dict[int, Callable[..., Any]] = {}


def _delegate(op: str) -> Any:
Expand Down
4 changes: 3 additions & 1 deletion src/PIL/XpmImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ def load_read(self, read_bytes: int) -> bytes:
class XpmDecoder(ImageFile.PyDecoder):
_pulls_fd = True

def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
def decode(
self, buffer: bytes | bytearray | memoryview | Image.SupportsArrayInterface
) -> tuple[int, int]:
assert self.fd is not None

data = bytearray()
Expand Down
Loading