Skip to content

Commit

Permalink
Added type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed May 17, 2024
1 parent 8c7be25 commit 4b3a8ab
Show file tree
Hide file tree
Showing 22 changed files with 141 additions and 96 deletions.
4 changes: 4 additions & 0 deletions docs/reference/ImageFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ Classes
:undoc-members:
:show-inheritance:

.. autoclass:: PIL.ImageFile.StubHandler()
:members:
:show-inheritance:

.. autoclass:: PIL.ImageFile.StubImageFile()
:members:
:show-inheritance:
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def _add_directory(path, subdir, where=None):
path.insert(where, subdir)


def _find_include_file(self, include):
def _find_include_file(self, include: str) -> int:
for directory in self.compiler.include_dirs:
_dbg("Checking for include file %s in %s", (include, directory))
if os.path.isfile(os.path.join(directory, include)):
Expand Down Expand Up @@ -255,7 +255,7 @@ def _cmd_exists(cmd: str) -> bool:
)


def _pkg_config(name):
def _pkg_config(name: str) -> tuple[str, str] | None:
command = os.environ.get("PKG_CONFIG", "pkg-config")
for keep_system in (True, False):
try:
Expand All @@ -282,6 +282,7 @@ def _pkg_config(name):
return libs, cflags
except Exception:
pass
return None


class pil_build_ext(build_ext):
Expand Down
22 changes: 12 additions & 10 deletions src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class AlphaEncoding(IntEnum):
DXT5 = 7


def unpack_565(i):
def unpack_565(i: int) -> tuple[int, int, int]:
return ((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3


Expand Down Expand Up @@ -284,7 +284,8 @@ def decode(self, buffer):
raise OSError(msg) from e
return -1, 0

def _read_blp_header(self):
def _read_blp_header(self) -> None:
assert self.fd is not None
self.fd.seek(4)
(self._blp_compression,) = struct.unpack("<i", self._safe_read(4))

Expand All @@ -303,10 +304,10 @@ def _read_blp_header(self):
self._blp_offsets = struct.unpack("<16I", self._safe_read(16 * 4))
self._blp_lengths = struct.unpack("<16I", self._safe_read(16 * 4))

def _safe_read(self, length):
def _safe_read(self, length: int) -> bytes:
return ImageFile._safe_read(self.fd, length)

def _read_palette(self):
def _read_palette(self) -> list[tuple[int, int, int, int]]:
ret = []
for i in range(256):
try:
Expand Down Expand Up @@ -349,29 +350,30 @@ def _load(self) -> None:
msg = f"Unsupported BLP compression {repr(self._blp_encoding)}"
raise BLPFormatError(msg)

def _decode_jpeg_stream(self):
def _decode_jpeg_stream(self) -> None:
from .JpegImagePlugin import JpegImageFile

(jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
jpeg_header = self._safe_read(jpeg_header_size)
assert self.fd is not None
self._safe_read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
data = self._safe_read(self._blp_lengths[0])
data = jpeg_header + data
data = BytesIO(data)
image = JpegImageFile(data)
image = JpegImageFile(BytesIO(data))
Image._decompression_bomb_check(image.size)
if image.mode == "CMYK":
decoder_name, extents, offset, args = image.tile[0]
image.tile = [(decoder_name, extents, offset, (args[0], "CMYK"))]
r, g, b = image.convert("RGB").split()
image = Image.merge("RGB", (b, g, r))
self.set_as_raw(image.tobytes())
reversed_image = Image.merge("RGB", (b, g, r))
self.set_as_raw(reversed_image.tobytes())


class BLP2Decoder(_BLPBaseDecoder):
def _load(self):
def _load(self) -> None:
palette = self._read_palette()

assert self.fd is not None
self.fd.seek(self._blp_offsets[0])

if self._blp_compression == 1:
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/BufrStubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
_handler = None


def register_handler(handler):
def register_handler(handler: ImageFile.StubHandler) -> None:
"""
Install application-specific BUFR image handler.
Expand Down Expand Up @@ -54,7 +54,7 @@ def _open(self) -> None:
if loader:
loader.open(self)

def _load(self):
def _load(self) -> ImageFile.StubHandler | None:
return _handler


Expand Down
4 changes: 2 additions & 2 deletions src/PIL/DcxImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class DcxImageFile(PcxImageFile):
format_description = "Intel DCX"
_close_exclusive_fp_after_loading = False

def _open(self):
def _open(self) -> None:
# Header
s = self.fp.read(4)
if not _accept(s):
Expand All @@ -58,7 +58,7 @@ def _open(self):
self._offset.append(offset)

self._fp = self.fp
self.frame = None
self.frame = -1
self.n_frames = len(self._offset)
self.is_animated = self.n_frames > 1
self.seek(0)
Expand Down
9 changes: 5 additions & 4 deletions src/PIL/GimpPaletteFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from __future__ import annotations

import re
from typing import IO

from ._binary import o8

Expand All @@ -25,8 +26,8 @@ class GimpPaletteFile:

rawmode = "RGB"

def __init__(self, fp):
self.palette = [o8(i) * 3 for i in range(256)]
def __init__(self, fp: IO[bytes]) -> None:
palette = [o8(i) * 3 for i in range(256)]

if fp.readline()[:12] != b"GIMP Palette":
msg = "not a GIMP palette file"
Expand All @@ -49,9 +50,9 @@ def __init__(self, fp):
msg = "bad palette entry"
raise ValueError(msg)

self.palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])
palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2])

self.palette = b"".join(self.palette)
self.palette = b"".join(palette)

def getpalette(self) -> tuple[bytes, str]:
return self.palette, self.rawmode
4 changes: 2 additions & 2 deletions src/PIL/GribStubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
_handler = None


def register_handler(handler):
def register_handler(handler: ImageFile.StubHandler) -> None:
"""
Install application-specific GRIB image handler.
Expand Down Expand Up @@ -54,7 +54,7 @@ def _open(self) -> None:
if loader:
loader.open(self)

def _load(self):
def _load(self) -> ImageFile.StubHandler | None:
return _handler


Expand Down
8 changes: 5 additions & 3 deletions src/PIL/Hdf5StubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
#
from __future__ import annotations

from typing import IO

from . import Image, ImageFile

_handler = None


def register_handler(handler):
def register_handler(handler: ImageFile.StubHandler) -> None:
"""
Install application-specific HDF5 image handler.
Expand Down Expand Up @@ -54,11 +56,11 @@ def _open(self) -> None:
if loader:
loader.open(self)

def _load(self):
def _load(self) -> ImageFile.StubHandler | None:
return _handler


def _save(im, fp, filename):
def _save(im: Image.Image, fp: IO[bytes], filename: str) -> None:
if _handler is None or not hasattr(_handler, "save"):
msg = "HDF5 save handler not installed"
raise OSError(msg)
Expand Down
4 changes: 3 additions & 1 deletion src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -1948,7 +1948,9 @@ def putalpha(self, alpha):

self.im.putband(alpha.im, band)

def putdata(self, data, scale=1.0, offset=0.0):
def putdata(
self, data: Sequence[float], scale: float = 1.0, offset: float = 0.0
) -> None:
"""
Copies pixel data from a flattened sequence object into the image. The
values should start at the upper left corner (0, 0), continue to the
Expand Down
13 changes: 13 additions & 0 deletions src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#
from __future__ import annotations

import abc
import io
import itertools
import struct
Expand Down Expand Up @@ -347,6 +348,18 @@ def _seek_check(self, frame):
return self.tell() != frame


class StubHandler:
def open(self, im: StubImageFile) -> None:
pass

@abc.abstractmethod
def load(self, im: StubImageFile) -> Image.Image:
pass

def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
pass


class StubImageFile(ImageFile):
"""
Base class for stub image loaders.
Expand Down
17 changes: 10 additions & 7 deletions src/PIL/ImageFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import abc
import functools
from typing import Sequence


class Filter:
Expand Down Expand Up @@ -79,7 +80,7 @@ class RankFilter(Filter):

name = "Rank"

def __init__(self, size, rank):
def __init__(self, size: int, rank: int) -> None:
self.size = size
self.rank = rank

Expand All @@ -101,7 +102,7 @@ class MedianFilter(RankFilter):

name = "Median"

def __init__(self, size=3):
def __init__(self, size: int = 3) -> None:
self.size = size
self.rank = size * size // 2

Expand All @@ -116,7 +117,7 @@ class MinFilter(RankFilter):

name = "Min"

def __init__(self, size=3):
def __init__(self, size: int = 3) -> None:
self.size = size
self.rank = 0

Expand All @@ -131,7 +132,7 @@ class MaxFilter(RankFilter):

name = "Max"

def __init__(self, size=3):
def __init__(self, size: int = 3) -> None:
self.size = size
self.rank = size * size - 1

Expand All @@ -147,7 +148,7 @@ class ModeFilter(Filter):

name = "Mode"

def __init__(self, size=3):
def __init__(self, size: int = 3) -> None:
self.size = size

def filter(self, image):
Expand All @@ -165,7 +166,7 @@ class GaussianBlur(MultibandFilter):

name = "GaussianBlur"

def __init__(self, radius=2):
def __init__(self, radius: float | Sequence[float] = 2) -> None:
self.radius = radius

def filter(self, image):
Expand Down Expand Up @@ -228,7 +229,9 @@ class UnsharpMask(MultibandFilter):

name = "UnsharpMask"

def __init__(self, radius=2, percent=150, threshold=3):
def __init__(
self, radius: float = 2, percent: int = 150, threshold: int = 3
) -> None:
self.radius = radius
self.percent = percent
self.threshold = threshold
Expand Down
6 changes: 3 additions & 3 deletions src/PIL/ImageFont.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,14 @@ def __setstate__(self, state):
path, size, index, encoding, layout_engine = state
self.__init__(path, size, index, encoding, layout_engine)

def getname(self):
def getname(self) -> tuple[str, str]:
"""
:return: A tuple of the font family (e.g. Helvetica) and the font style
(e.g. Bold)
"""
return self.font.family, self.font.style

def getmetrics(self):
def getmetrics(self) -> tuple[int, int]:
"""
:return: A tuple of the font ascent (the distance from the baseline to
the highest outline point) and descent (the distance from the
Expand Down Expand Up @@ -628,7 +628,7 @@ def font_variant(
layout_engine=layout_engine or self.layout_engine,
)

def get_variation_names(self):
def get_variation_names(self) -> list[bytes]:
"""
:returns: A list of the named styles in a variation font.
:exception OSError: If the font is not a variation font.
Expand Down
Loading

0 comments on commit 4b3a8ab

Please sign in to comment.