Skip to content

Commit

Permalink
Added type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Jun 24, 2024
1 parent ad4c23b commit f2302ab
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 53 deletions.
1 change: 1 addition & 0 deletions Tests/test_file_spider.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def test_load_image_series() -> None:
img_list = SpiderImagePlugin.loadImageSeries(file_list)

# Assert
assert img_list is not None
assert len(img_list) == 1
assert isinstance(img_list[0], Image.Image)
assert img_list[0].size == (128, 128)
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_imagefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def __init__(self, mode: str, *args: Any) -> None:

super().__init__(mode, *args)

def decode(self, buffer):
def decode(self, buffer: bytes) -> tuple[int, int]:
# eof
return -1, 0

Expand All @@ -222,7 +222,7 @@ def __init__(self, mode: str, *args: Any) -> None:

super().__init__(mode, *args)

def encode(self, buffer):
def encode(self, bufsize: int) -> tuple[int, int, bytes]:
return 1, 1, b""

def cleanup(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imageops_usm.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def test_blur_accuracy(test_images: dict[str, ImageFile.ImageFile]) -> None:
assert i.im.getpixel((x, y))[c] >= 250
# Fuzzy match.

def gp(x, y):
def gp(x: int, y: int) -> tuple[int, ...]:
return i.im.getpixel((x, y))

assert 236 <= gp(7, 4)[0] <= 239
Expand Down
8 changes: 4 additions & 4 deletions Tests/test_imagepalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ def test_file(tmp_path: Path) -> None:

palette.save(f)

p = ImagePalette.load(f)
lut = ImagePalette.load(f)

# load returns raw palette information
assert len(p[0]) == 768
assert p[1] == "RGB"
assert len(lut[0]) == 768
assert lut[1] == "RGB"

p = ImagePalette.raw(p[1], p[0])
p = ImagePalette.raw(lut[1], lut[0])
assert isinstance(p, ImagePalette.ImagePalette)
assert p.palette == palette.tobytes()

Expand Down
2 changes: 2 additions & 0 deletions src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ class BLPEncoder(ImageFile.PyEncoder):

def _write_palette(self) -> bytes:
data = b""
assert self.im is not None

Check warning on line 433 in src/PIL/BlpImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/BlpImagePlugin.py#L433

Added line #L433 was not covered by tests
palette = self.im.getpalette("RGBA", "RGBA")
for i in range(len(palette) // 4):
r, g, b, a = palette[i * 4 : (i + 1) * 4]
Expand All @@ -444,6 +445,7 @@ def encode(self, bufsize: int) -> tuple[int, int, bytes]:
offset = 20 + 16 * 4 * 2 + len(palette_data)
data = struct.pack("<16I", offset, *((0,) * 15))

assert self.im is not None

Check warning on line 448 in src/PIL/BlpImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/BlpImagePlugin.py#L448

Added line #L448 was not covered by tests
w, h = self.im.size
data += struct.pack("<16I", w * h, *((0,) * 15))

Expand Down
7 changes: 6 additions & 1 deletion src/PIL/ImageDraw2.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
"""
from __future__ import annotations

from typing import BinaryIO

Check warning on line 27 in src/PIL/ImageDraw2.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageDraw2.py#L27

Added line #L27 was not covered by tests

from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
from ._typing import StrOrBytesPath

Check warning on line 30 in src/PIL/ImageDraw2.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageDraw2.py#L30

Added line #L30 was not covered by tests


class Pen:
Expand All @@ -45,7 +48,9 @@ def __init__(self, color: str, opacity: int = 255) -> None:
class Font:
"""Stores a TrueType font and color"""

def __init__(self, color, file, size=12):
def __init__(

Check warning on line 51 in src/PIL/ImageDraw2.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageDraw2.py#L51

Added line #L51 was not covered by tests
self, color: str, file: StrOrBytesPath | BinaryIO, size: float = 12
) -> None:
# FIXME: add support for bitmap fonts
self.color = ImageColor.getrgb(color)
self.font = ImageFont.truetype(file, size)
Expand Down
25 changes: 14 additions & 11 deletions src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
# Helpers


def _get_oserror(error, *, encoder):
def _get_oserror(error: int, *, encoder: bool) -> OSError:

Check warning on line 68 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L68

Added line #L68 was not covered by tests
try:
msg = Image.core.getcodecstatus(error)
except AttributeError:
Expand All @@ -76,7 +76,7 @@ def _get_oserror(error, *, encoder):
return OSError(msg)


def raise_oserror(error):
def raise_oserror(error: int) -> OSError:

Check warning on line 79 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L79

Added line #L79 was not covered by tests
deprecate(
"raise_oserror",
12,
Expand Down Expand Up @@ -154,11 +154,12 @@ def __init__(self, fp=None, filename=None):
self.fp.close()
raise

def get_format_mimetype(self):
def get_format_mimetype(self) -> str | None:

Check warning on line 157 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L157

Added line #L157 was not covered by tests
if self.custom_mimetype:
return self.custom_mimetype
if self.format is not None:
return Image.MIME.get(self.format.upper())
return None

Check warning on line 162 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L162

Added line #L162 was not covered by tests

def __setstate__(self, state):
self.tile = []
Expand Down Expand Up @@ -365,7 +366,7 @@ class StubImageFile(ImageFile):
certain format, but relies on external code to load the file.
"""

def _open(self):
def _open(self) -> None:

Check warning on line 369 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L369

Added line #L369 was not covered by tests
msg = "StubImageFile subclass must implement _open"
raise NotImplementedError(msg)

Expand All @@ -381,7 +382,7 @@ def load(self):
self.__dict__ = image.__dict__
return image.load()

def _load(self):
def _load(self) -> StubHandler | None:

Check warning on line 385 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L385

Added line #L385 was not covered by tests
"""(Hook) Find actual image loader."""
msg = "StubImageFile subclass must implement _load"
raise NotImplementedError(msg)
Expand Down Expand Up @@ -621,7 +622,7 @@ def __init__(self) -> None:
self.xoff = 0
self.yoff = 0

def extents(self):
def extents(self) -> tuple[int, int, int, int]:

Check warning on line 625 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L625

Added line #L625 was not covered by tests
return self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize


Expand Down Expand Up @@ -661,7 +662,7 @@ def setfd(self, fd):
"""
self.fd = fd

def setimage(self, im, extents=None):
def setimage(self, im, extents: tuple[int, int, int, int] | None = None) -> None:

Check warning on line 665 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L665

Added line #L665 was not covered by tests
"""
Called from ImageFile to set the core output image for the codec
Expand Down Expand Up @@ -710,10 +711,10 @@ class PyDecoder(PyCodec):
_pulls_fd = False

@property
def pulls_fd(self):
def pulls_fd(self) -> bool:

Check warning on line 714 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L714

Added line #L714 was not covered by tests
return self._pulls_fd

def decode(self, buffer):
def decode(self, buffer: bytes) -> tuple[int, int]:

Check warning on line 717 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L717

Added line #L717 was not covered by tests
"""
Override to perform the decoding process.
Expand All @@ -738,6 +739,7 @@ def set_as_raw(self, data: bytes, rawmode=None) -> None:
if not rawmode:
rawmode = self.mode
d = Image._getdecoder(self.mode, "raw", rawmode)
assert self.im is not None

Check warning on line 742 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L742

Added line #L742 was not covered by tests
d.setimage(self.im, self.state.extents())
s = d.decode(data)

Expand All @@ -760,7 +762,7 @@ class PyEncoder(PyCodec):
_pushes_fd = False

@property
def pushes_fd(self):
def pushes_fd(self) -> bool:

Check warning on line 765 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L765

Added line #L765 was not covered by tests
return self._pushes_fd

def encode(self, bufsize: int) -> tuple[int, int, bytes]:
Expand All @@ -775,7 +777,7 @@ def encode(self, bufsize: int) -> tuple[int, int, bytes]:
msg = "unavailable in base encoder"
raise NotImplementedError(msg)

def encode_to_pyfd(self):
def encode_to_pyfd(self) -> tuple[int, int]:

Check warning on line 780 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L780

Added line #L780 was not covered by tests
"""
If ``pushes_fd`` is ``True``, then this method will be used,
and ``encode()`` will only be called once.
Expand All @@ -787,6 +789,7 @@ def encode_to_pyfd(self):
return 0, -8 # bad configuration
bytes_consumed, errcode, data = self.encode(0)
if data:
assert self.fd is not None

Check warning on line 792 in src/PIL/ImageFile.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageFile.py#L792

Added line #L792 was not covered by tests
self.fd.write(data)
return bytes_consumed, errcode

Expand Down
48 changes: 29 additions & 19 deletions src/PIL/ImagePalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,27 @@ class ImagePalette:
Defaults to an empty palette.
"""

def __init__(self, mode: str = "RGB", palette: Sequence[int] | None = None) -> None:
def __init__(

Check warning on line 41 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L41

Added line #L41 was not covered by tests
self,
mode: str = "RGB",
palette: Sequence[int] | bytes | bytearray | None = None,
) -> None:
self.mode = mode
self.rawmode = None # if set, palette contains raw data
self.rawmode: str | None = None # if set, palette contains raw data

Check warning on line 47 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L47

Added line #L47 was not covered by tests
self.palette = palette or bytearray()
self.dirty: int | None = None

@property
def palette(self):
def palette(self) -> Sequence[int] | bytes | bytearray:

Check warning on line 52 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L52

Added line #L52 was not covered by tests
return self._palette

@palette.setter
def palette(self, palette):
self._colors = None
def palette(self, palette: Sequence[int] | bytes | bytearray) -> None:
self._colors: dict[tuple[int, ...], int] | None = None

Check warning on line 57 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L56-L57

Added lines #L56 - L57 were not covered by tests
self._palette = palette

@property
def colors(self) -> dict[tuple[int, int, int] | tuple[int, int, int, int], int]:
def colors(self) -> dict[tuple[int, ...], int]:

Check warning on line 61 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L61

Added line #L61 was not covered by tests
if self._colors is None:
mode_len = len(self.mode)
self._colors = {}
Expand All @@ -66,9 +70,7 @@ def colors(self) -> dict[tuple[int, int, int] | tuple[int, int, int, int], int]:
return self._colors

@colors.setter
def colors(
self, colors: dict[tuple[int, int, int] | tuple[int, int, int, int], int]
) -> None:
def colors(self, colors: dict[tuple[int, ...], int]) -> None:

Check warning on line 73 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L73

Added line #L73 was not covered by tests
self._colors = colors

def copy(self) -> ImagePalette:
Expand All @@ -82,7 +84,7 @@ def copy(self) -> ImagePalette:

return new

def getdata(self) -> tuple[str, bytes]:
def getdata(self) -> tuple[str, Sequence[int] | bytes | bytearray]:

Check warning on line 87 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L87

Added line #L87 was not covered by tests
"""
Get palette contents in format suitable for the low-level
``im.putpalette`` primitive.
Expand Down Expand Up @@ -137,7 +139,7 @@ def _new_color_index(

def getcolor(
self,
color: tuple[int, int, int] | tuple[int, int, int, int],
color: tuple[int, ...],
image: Image.Image | None = None,
) -> int:
"""Given an rgb tuple, allocate palette entry.
Expand All @@ -162,12 +164,13 @@ def getcolor(
except KeyError as e:
# allocate new color slot
index = self._new_color_index(image, e)
assert isinstance(self._palette, bytearray)

Check warning on line 167 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L167

Added line #L167 was not covered by tests
self.colors[color] = index
if index * 3 < len(self.palette):
self._palette = (
self.palette[: index * 3]
self._palette[: index * 3]
+ bytes(color)
+ self.palette[index * 3 + 3 :]
+ self._palette[index * 3 + 3 :]
)
else:
self._palette += bytes(color)
Expand Down Expand Up @@ -204,7 +207,7 @@ def save(self, fp: str | IO[str]) -> None:
# Internal


def raw(rawmode, data) -> ImagePalette:
def raw(rawmode, data: Sequence[int] | bytes | bytearray) -> ImagePalette:

Check warning on line 210 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L210

Added line #L210 was not covered by tests
palette = ImagePalette()
palette.rawmode = rawmode
palette.palette = data
Expand All @@ -216,9 +219,9 @@ def raw(rawmode, data) -> ImagePalette:
# Factories


def make_linear_lut(black, white):
def make_linear_lut(black: int, white: float) -> list[int]:

Check warning on line 222 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L222

Added line #L222 was not covered by tests
if black == 0:
return [white * i // 255 for i in range(256)]
return [int(white * i // 255) for i in range(256)]

Check warning on line 224 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L224

Added line #L224 was not covered by tests

msg = "unavailable when black is non-zero"
raise NotImplementedError(msg) # FIXME
Expand Down Expand Up @@ -251,15 +254,22 @@ def wedge(mode: str = "RGB") -> ImagePalette:
return ImagePalette(mode, [i // len(mode) for i in palette])


def load(filename):
def load(filename: str) -> tuple[bytes, str]:

Check warning on line 257 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L257

Added line #L257 was not covered by tests
# FIXME: supports GIMP gradients only

with open(filename, "rb") as fp:
for paletteHandler in [
paletteHandlers: list[

Check warning on line 261 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L261

Added line #L261 was not covered by tests
type[
GimpPaletteFile.GimpPaletteFile
| GimpGradientFile.GimpGradientFile
| PaletteFile.PaletteFile
]
] = [
GimpPaletteFile.GimpPaletteFile,
GimpGradientFile.GimpGradientFile,
PaletteFile.PaletteFile,
]:
]
for paletteHandler in paletteHandlers:

Check warning on line 272 in src/PIL/ImagePalette.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImagePalette.py#L272

Added line #L272 was not covered by tests
try:
fp.seek(0)
lut = paletteHandler(fp).getpalette()
Expand Down
13 changes: 8 additions & 5 deletions src/PIL/ImageWin.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,22 @@ class Dib:
defines the size of the image.
"""

def __init__(self, image, size=None):
if hasattr(image, "mode") and hasattr(image, "size"):
def __init__(

Check warning on line 72 in src/PIL/ImageWin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageWin.py#L72

Added line #L72 was not covered by tests
self, image: Image.Image | str, size: tuple[int, int] | list[int] | None = None
) -> None:
if isinstance(image, str):
mode = image
image = ""

Check warning on line 77 in src/PIL/ImageWin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageWin.py#L75-L77

Added lines #L75 - L77 were not covered by tests
else:
mode = image.mode
size = image.size
else:
mode = image
image = None
if mode not in ["1", "L", "P", "RGB"]:
mode = Image.getmodebase(mode)
self.image = Image.core.display(mode, size)
self.mode = mode
self.size = size
if image:
assert not isinstance(image, str)

Check warning on line 87 in src/PIL/ImageWin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageWin.py#L87

Added line #L87 was not covered by tests
self.paste(image)

def expose(self, handle):
Expand Down
Loading

0 comments on commit f2302ab

Please sign in to comment.