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 Tests/test_file_jpeg2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def test_reduce() -> None:
assert callable(im.reduce)

im.reduce = 2 # type: ignore[assignment, method-assign]
assert im.reduce == 2
assert im.reduce == 2 # type: ignore[comparison-overlap]

im.load()
assert im.size == (160, 120)
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
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
11 changes: 5 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,10 @@ testpaths = [
[tool.mypy]
python_version = "3.10"
pretty = true
disallow_any_generics = true
disallow_untyped_defs = true
strict = true
disallow_subclassing_any = false
disallow_untyped_calls = false
enable_error_code = "ignore-without-code"
extra_checks = true
follow_imports = "silent"
warn_redundant_casts = true
no_implicit_reexport = false
warn_return_any = false
warn_unreachable = true
warn_unused_ignores = true
4 changes: 3 additions & 1 deletion src/PIL/EpsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ def _open(self) -> None:
imagedata_size: tuple[int, int] | None = None

byte_arr = bytearray(255)
bytes_mv = memoryview(byte_arr)
# the extra `bytes` annotation here works around several false positive
# `comparison-overlap` mypy errors
bytes_mv: bytes | memoryview = memoryview(byte_arr)
bytes_read = 0
reading_header_comments = True
reading_trailer_comments = False
Expand Down
6 changes: 4 additions & 2 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
from types import ModuleType
from typing import Any, Literal

from ._typing import Buffer

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -931,7 +933,7 @@ def tobitmap(self, name: str = "image") -> bytes:

def frombytes(
self,
data: bytes | bytearray | SupportsArrayInterface,
data: Buffer | SupportsArrayInterface,
decoder_name: str = "raw",
*args: Any,
) -> None:
Expand Down Expand Up @@ -3232,7 +3234,7 @@ def new(
def frombytes(
mode: str,
size: tuple[int, int],
data: bytes | bytearray | SupportsArrayInterface,
data: Buffer | SupportsArrayInterface,
decoder_name: str = "raw",
*args: Any,
) -> Image:
Expand Down
11 changes: 7 additions & 4 deletions src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

TYPE_CHECKING = False
if TYPE_CHECKING:
from ._typing import StrOrBytesPath
from ._typing import Buffer, StrOrBytesPath

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -839,7 +839,7 @@ 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: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
"""
Override to perform the decoding process.

Expand All @@ -852,7 +852,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 Expand Up @@ -893,7 +896,7 @@ class PyEncoder(PyCodec):
def pushes_fd(self) -> bool:
return self._pushes_fd

def encode(self, bufsize: int) -> tuple[int, int, bytes]:
def encode(self, bufsize: int) -> tuple[int, int, bytes | bytearray]:
"""
Override to perform the encoding process.

Expand Down
3 changes: 2 additions & 1 deletion src/PIL/ImageWin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from __future__ import annotations

from . import Image
from ._typing import Buffer


class HDC:
Expand Down Expand Up @@ -183,7 +184,7 @@ def paste(
else:
self.image.paste(im.im)

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

Expand Down
4 changes: 3 additions & 1 deletion src/PIL/PdfParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
if TYPE_CHECKING:
from typing import IO

from ._typing import Buffer

_DictBase = collections.UserDict[str | bytes, Any]
else:
_DictBase = collections.UserDict
Expand Down Expand Up @@ -316,7 +318,7 @@ def __bytes__(self) -> bytes:


class PdfStream:
def __init__(self, dictionary: PdfDict, buf: bytes) -> None:
def __init__(self, dictionary: PdfDict, buf: Buffer) -> None:
self.dictionary = dictionary
self.buf = buf

Expand Down
10 changes: 5 additions & 5 deletions src/PIL/PpmImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,12 @@ def _read_block(self) -> bytes:

return self.fd.read(ImageFile.SAFEBLOCK)

def _find_comment_end(self, block: bytes, start: int = 0) -> int:
def _find_comment_end(self, block: bytes | bytearray, start: int = 0) -> int:
a = block.find(b"\n", start)
b = block.find(b"\r", start)
return min(a, b) if a * b > 0 else max(a, b) # lowest nonnegative index (or -1)

def _ignore_comments(self, block: bytes) -> bytes:
def _ignore_comments(self, block: bytes | bytearray) -> bytes | bytearray:
if self._comment_spans:
# Finish current comment
while block:
Expand Down Expand Up @@ -217,7 +217,7 @@ def _decode_bitonal(self) -> bytearray:
total_bytes = self.state.xsize * self.state.ysize

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 All @@ -241,9 +241,9 @@ def _decode_blocks(self, maxval: int) -> bytearray:
bands = Image.getmodebands(self.mode)
total_bytes = self.state.xsize * self.state.ysize * bands * out_byte_count

half_token = b""
half_token: bytes | bytearray = b""
while len(data) != total_bytes:
block = self._read_block() # read next block
block: bytes | bytearray = self._read_block() # read next block
if not block:
if half_token:
block = bytearray(b" ") # flush half_token
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/QoiImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def _delta(self, left: int, right: int) -> int:
result -= 256
return result

def encode(self, bufsize: int) -> tuple[int, int, bytes]:
def encode(self, bufsize: int) -> tuple[int, int, bytearray]:
assert self.im is not None

self._previously_seen_pixels = {0: (0, 0, 0, 0)}
Expand Down