Merge pull request #8105 from radarhere/type_hint

This commit is contained in:
Hugo van Kemenade 2024-06-04 05:33:14 -06:00 committed by GitHub
commit ca1caadd06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 40 additions and 29 deletions

View File

@ -35,6 +35,7 @@ import os
import struct import struct
from enum import IntEnum from enum import IntEnum
from io import BytesIO from io import BytesIO
from typing import IO
from . import Image, ImageFile from . import Image, ImageFile
@ -448,7 +449,7 @@ class BLPEncoder(ImageFile.PyEncoder):
return len(data), 0, data return len(data), 0, data
def _save(im, fp, filename): def _save(im: Image.Image, fp: IO[bytes], filename: str) -> None:
if im.mode != "P": if im.mode != "P":
msg = "Unsupported BLP image mode" msg = "Unsupported BLP image mode"
raise ValueError(msg) raise ValueError(msg)

View File

@ -228,7 +228,7 @@ class EpsImageFile(ImageFile.ImageFile):
reading_trailer_comments = False reading_trailer_comments = False
trailer_reached = False trailer_reached = False
def check_required_header_comments(): def check_required_header_comments() -> None:
if "PS-Adobe" not in self.info: if "PS-Adobe" not in self.info:
msg = 'EPS header missing "%!PS-Adobe" comment' msg = 'EPS header missing "%!PS-Adobe" comment'
raise SyntaxError(msg) raise SyntaxError(msg)

View File

@ -70,7 +70,7 @@ class FpxImageFile(ImageFile.ImageFile):
self._open_index(1) self._open_index(1)
def _open_index(self, index=1): def _open_index(self, index: int = 1) -> None:
# #
# get the Image Contents Property Set # get the Image Contents Property Set
@ -85,7 +85,7 @@ class FpxImageFile(ImageFile.ImageFile):
size = max(self.size) size = max(self.size)
i = 1 i = 1
while size > 64: while size > 64:
size = size / 2 size = size // 2
i += 1 i += 1
self.maxid = i - 1 self.maxid = i - 1
@ -118,7 +118,7 @@ class FpxImageFile(ImageFile.ImageFile):
self._open_subimage(1, self.maxid) self._open_subimage(1, self.maxid)
def _open_subimage(self, index=1, subimage=0): def _open_subimage(self, index: int = 1, subimage: int = 0) -> None:
# #
# setup tile descriptors for a given subimage # setup tile descriptors for a given subimage

View File

@ -23,7 +23,10 @@ from . import Image, ImageFilter, ImageStat
class _Enhance: class _Enhance:
def enhance(self, factor): image: Image.Image
degenerate: Image.Image
def enhance(self, factor: float) -> Image.Image:
""" """
Returns an enhanced image. Returns an enhanced image.
@ -46,7 +49,7 @@ class Color(_Enhance):
the original image. the original image.
""" """
def __init__(self, image): def __init__(self, image: Image.Image) -> None:
self.image = image self.image = image
self.intermediate_mode = "L" self.intermediate_mode = "L"
if "A" in image.getbands(): if "A" in image.getbands():
@ -63,7 +66,7 @@ class Contrast(_Enhance):
gives a solid gray image. A factor of 1.0 gives the original image. gives a solid gray image. A factor of 1.0 gives the original image.
""" """
def __init__(self, image): def __init__(self, image: Image.Image) -> None:
self.image = image self.image = image
mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5) mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
self.degenerate = Image.new("L", image.size, mean).convert(image.mode) self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
@ -80,7 +83,7 @@ class Brightness(_Enhance):
original image. original image.
""" """
def __init__(self, image): def __init__(self, image: Image.Image) -> None:
self.image = image self.image = image
self.degenerate = Image.new(image.mode, image.size, 0) self.degenerate = Image.new(image.mode, image.size, 0)
@ -96,7 +99,7 @@ class Sharpness(_Enhance):
original image, and a factor of 2.0 gives a sharpened image. original image, and a factor of 2.0 gives a sharpened image.
""" """
def __init__(self, image): def __init__(self, image: Image.Image) -> None:
self.image = image self.image = image
self.degenerate = image.filter(ImageFilter.SMOOTH) self.degenerate = image.filter(ImageFilter.SMOOTH)

View File

@ -18,7 +18,8 @@ from __future__ import annotations
import abc import abc
import functools import functools
from typing import Sequence from types import ModuleType
from typing import Any, Sequence
class Filter: class Filter:
@ -57,7 +58,13 @@ class Kernel(BuiltinFilter):
name = "Kernel" name = "Kernel"
def __init__(self, size, kernel, scale=None, offset=0): def __init__(
self,
size: tuple[int, int],
kernel: Sequence[float],
scale: float | None = None,
offset: float = 0,
) -> None:
if scale is None: if scale is None:
# default scale is sum of kernel # default scale is sum of kernel
scale = functools.reduce(lambda a, b: a + b, kernel) scale = functools.reduce(lambda a, b: a + b, kernel)
@ -194,10 +201,8 @@ class BoxBlur(MultibandFilter):
name = "BoxBlur" name = "BoxBlur"
def __init__(self, radius): def __init__(self, radius: float | Sequence[float]) -> None:
xy = radius xy = radius if isinstance(radius, (tuple, list)) else (radius, radius)
if not isinstance(xy, (tuple, list)):
xy = (xy, xy)
if xy[0] < 0 or xy[1] < 0: if xy[0] < 0 or xy[1] < 0:
msg = "radius must be >= 0" msg = "radius must be >= 0"
raise ValueError(msg) raise ValueError(msg)
@ -381,7 +386,9 @@ class Color3DLUT(MultibandFilter):
name = "Color 3D LUT" name = "Color 3D LUT"
def __init__(self, size, table, channels=3, target_mode=None, **kwargs): def __init__(
self, size, table, channels: int = 3, target_mode: str | None = None, **kwargs
):
if channels not in (3, 4): if channels not in (3, 4):
msg = "Only 3 or 4 output channels are supported" msg = "Only 3 or 4 output channels are supported"
raise ValueError(msg) raise ValueError(msg)
@ -395,7 +402,7 @@ class Color3DLUT(MultibandFilter):
items = size[0] * size[1] * size[2] items = size[0] * size[1] * size[2]
wrong_size = False wrong_size = False
numpy = None numpy: ModuleType | None = None
if hasattr(table, "shape"): if hasattr(table, "shape"):
try: try:
import numpy import numpy
@ -442,7 +449,7 @@ class Color3DLUT(MultibandFilter):
self.table = table self.table = table
@staticmethod @staticmethod
def _check_size(size): def _check_size(size: Any) -> list[int]:
try: try:
_, _, _ = size _, _, _ = size
except ValueError as e: except ValueError as e:

View File

@ -200,7 +200,7 @@ class MorphOp:
elif patterns is not None: elif patterns is not None:
self.lut = LutBuilder(patterns=patterns).build_lut() self.lut = LutBuilder(patterns=patterns).build_lut()
def apply(self, image: Image.Image): def apply(self, image: Image.Image) -> tuple[int, Image.Image]:
"""Run a single morphological operation on an image """Run a single morphological operation on an image
Returns a tuple of the number of changed pixels and the Returns a tuple of the number of changed pixels and the
@ -216,7 +216,7 @@ class MorphOp:
count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id) count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id)
return count, outimage return count, outimage
def match(self, image: Image.Image): def match(self, image: Image.Image) -> list[tuple[int, int]]:
"""Get a list of coordinates matching the morphological operation on """Get a list of coordinates matching the morphological operation on
an image. an image.
@ -231,7 +231,7 @@ class MorphOp:
raise ValueError(msg) raise ValueError(msg)
return _imagingmorph.match(bytes(self.lut), image.im.id) return _imagingmorph.match(bytes(self.lut), image.im.id)
def get_on_pixels(self, image: Image.Image): def get_on_pixels(self, image: Image.Image) -> list[tuple[int, int]]:
"""Get a list of all turned on pixels in a binary image """Get a list of all turned on pixels in a binary image
Returns a list of tuples of (x,y) coordinates Returns a list of tuples of (x,y) coordinates

View File

@ -34,7 +34,7 @@ class BoxReader:
self.length = length self.length = length
self.remaining_in_box = -1 self.remaining_in_box = -1
def _can_read(self, num_bytes): def _can_read(self, num_bytes: int) -> bool:
if self.has_length and self.fp.tell() + num_bytes > self.length: if self.has_length and self.fp.tell() + num_bytes > self.length:
# Outside box: ensure we don't read past the known file length # Outside box: ensure we don't read past the known file length
return False return False
@ -44,7 +44,7 @@ class BoxReader:
else: else:
return True # No length known, just read return True # No length known, just read
def _read_bytes(self, num_bytes): def _read_bytes(self, num_bytes: int) -> bytes:
if not self._can_read(num_bytes): if not self._can_read(num_bytes):
msg = "Not enough data in header" msg = "Not enough data in header"
raise SyntaxError(msg) raise SyntaxError(msg)
@ -74,7 +74,7 @@ class BoxReader:
else: else:
return True return True
def next_box_type(self): def next_box_type(self) -> bytes:
# Skip the rest of the box if it has not been read # Skip the rest of the box if it has not been read
if self.remaining_in_box > 0: if self.remaining_in_box > 0:
self.fp.seek(self.remaining_in_box, os.SEEK_CUR) self.fp.seek(self.remaining_in_box, os.SEEK_CUR)

View File

@ -48,5 +48,5 @@ class PaletteFile:
self.palette = b"".join(self.palette) self.palette = b"".join(self.palette)
def getpalette(self): def getpalette(self) -> tuple[bytes, str]:
return self.palette, self.rawmode return self.palette, self.rawmode

View File

@ -38,7 +38,7 @@ class QoiImageFile(ImageFile.ImageFile):
class QoiDecoder(ImageFile.PyDecoder): class QoiDecoder(ImageFile.PyDecoder):
_pulls_fd = True _pulls_fd = True
def _add_to_previous_pixels(self, value): def _add_to_previous_pixels(self, value: bytes | bytearray) -> None:
self._previous_pixel = value self._previous_pixel = value
r, g, b, a = value r, g, b, a = value

View File

@ -233,7 +233,7 @@ def loadImageSeries(filelist=None):
# For saving images in Spider format # For saving images in Spider format
def makeSpiderHeader(im): def makeSpiderHeader(im: Image.Image) -> list[bytes]:
nsam, nrow = im.size nsam, nrow = im.size
lenbyt = nsam * 4 # There are labrec records in the header lenbyt = nsam * 4 # There are labrec records in the header
labrec = int(1024 / lenbyt) labrec = int(1024 / lenbyt)

View File

@ -117,7 +117,7 @@ class WebPImageFile(ImageFile.ImageFile):
# Set logical frame to requested position # Set logical frame to requested position
self.__logical_frame = frame self.__logical_frame = frame
def _reset(self, reset=True): def _reset(self, reset: bool = True) -> None:
if reset: if reset:
self._decoder.reset() self._decoder.reset()
self.__physical_frame = 0 self.__physical_frame = 0