diff --git a/src/PIL/FliImagePlugin.py b/src/PIL/FliImagePlugin.py index eea2c0c951f..dceb839279a 100644 --- a/src/PIL/FliImagePlugin.py +++ b/src/PIL/FliImagePlugin.py @@ -132,7 +132,7 @@ def seek(self, frame: int) -> None: for f in range(self.__frame + 1, frame + 1): self._seek(f) - def _seek(self, frame): + def _seek(self, frame: int) -> None: if frame == 0: self.__frame = -1 self._fp.seek(self.__rewind) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 26e5958191b..eede4154994 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -82,7 +82,7 @@ def data(self) -> bytes | None: return self.fp.read(s[0]) return None - def _is_palette_needed(self, p): + def _is_palette_needed(self, p: bytes) -> bool: for i in range(0, len(p), 3): if not (i // 3 == p[i] == p[i + 1] == p[i + 2]): return True @@ -474,7 +474,7 @@ def tell(self) -> int: RAWMODE = {"1": "L", "L": "L", "P": "P"} -def _normalize_mode(im): +def _normalize_mode(im: Image.Image) -> Image.Image: """ Takes an image (or frame), returns an image in a mode that is appropriate for saving in a Gif. @@ -887,7 +887,7 @@ def _get_optimize(im, info): return used_palette_colors -def _get_color_table_size(palette_bytes): +def _get_color_table_size(palette_bytes: bytes) -> int: # calculate the palette size for the header if not palette_bytes: return 0 @@ -897,7 +897,7 @@ def _get_color_table_size(palette_bytes): return math.ceil(math.log(len(palette_bytes) // 3, 2)) - 1 -def _get_header_palette(palette_bytes): +def _get_header_palette(palette_bytes: bytes) -> bytes: """ Returns the palette, null padded to the next power of 2 (*3) bytes suitable for direct inclusion in the GIF header @@ -915,7 +915,7 @@ def _get_header_palette(palette_bytes): return palette_bytes -def _get_palette_bytes(im): +def _get_palette_bytes(im: Image.Image) -> bytes: """ Gets the palette for inclusion in the gif header diff --git a/src/PIL/GimpPaletteFile.py b/src/PIL/GimpPaletteFile.py index a3109ebaa1b..2274f1a8bfe 100644 --- a/src/PIL/GimpPaletteFile.py +++ b/src/PIL/GimpPaletteFile.py @@ -53,5 +53,5 @@ def __init__(self, fp): self.palette = b"".join(self.palette) - def getpalette(self): + def getpalette(self) -> tuple[bytes, str]: return self.palette, self.rawmode diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index a325f8552d5..8e949ebaf9d 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -271,11 +271,11 @@ def _open(self) -> None: self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))] @property - def n_frames(self): + def n_frames(self) -> int: return self.info[FRAMES] @property - def is_animated(self): + def is_animated(self) -> bool: return self.info[FRAMES] > 1 def seek(self, frame: int) -> None: diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index d3efe64865e..42f2ee8c799 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -34,7 +34,7 @@ import math import numbers import struct -from typing import Sequence, cast +from typing import TYPE_CHECKING, Sequence, cast from . import Image, ImageColor from ._typing import Coords @@ -92,7 +92,10 @@ def __init__(self, im: Image.Image, mode: str | None = None) -> None: self.fontmode = "L" # aliasing is okay for other modes self.fill = False - def getfont(self): + if TYPE_CHECKING: + from . import ImageFont + + def getfont(self) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: """ Get the current default font. diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index fa9ebd9defb..678bd29a2d7 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -544,7 +544,7 @@ def transform(self, callback, with_normals=False, channels=None, target_mode=Non _copy_table=False, ) - def __repr__(self): + def __repr__(self) -> str: r = [ f"{self.__class__.__name__} from {self.table.__class__.__name__}", "size={:d}x{:d}x{:d}".format(*self.size), diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py index 770d10025c8..ae5c5dec0da 100644 --- a/src/PIL/ImagePalette.py +++ b/src/PIL/ImagePalette.py @@ -66,7 +66,7 @@ def colors(self): def colors(self, colors): self._colors = colors - def copy(self): + def copy(self) -> ImagePalette: new = ImagePalette() new.mode = self.mode @@ -77,7 +77,7 @@ def copy(self): return new - def getdata(self): + def getdata(self) -> tuple[str, bytes]: """ Get palette contents in format suitable for the low-level ``im.putpalette`` primitive. @@ -88,7 +88,7 @@ def getdata(self): return self.rawmode, self.palette return self.mode, self.tobytes() - def tobytes(self): + def tobytes(self) -> bytes: """Convert palette to bytes. .. warning:: This method is experimental. diff --git a/src/PIL/ImageTk.py b/src/PIL/ImageTk.py index 2f9d7f505ba..6e2e7db1e19 100644 --- a/src/PIL/ImageTk.py +++ b/src/PIL/ImageTk.py @@ -136,7 +136,7 @@ def __del__(self) -> None: except Exception: pass # ignore internal errors - def __str__(self): + def __str__(self) -> str: """ Get the Tkinter photo image identifier. This method is automatically called by Tkinter whenever a PhotoImage object is passed to a Tkinter @@ -146,7 +146,7 @@ def __str__(self): """ return str(self.__photo) - def width(self): + def width(self) -> int: """ Get the width of the image. @@ -154,7 +154,7 @@ def width(self): """ return self.__size[0] - def height(self): + def height(self) -> int: """ Get the height of the image. @@ -227,7 +227,7 @@ def __del__(self) -> None: except Exception: pass # ignore internal errors - def width(self): + def width(self) -> int: """ Get the width of the image. @@ -235,7 +235,7 @@ def width(self): """ return self.__size[0] - def height(self): + def height(self) -> int: """ Get the height of the image. @@ -243,7 +243,7 @@ def height(self): """ return self.__size[1] - def __str__(self): + def __str__(self) -> str: """ Get the Tkinter bitmap image identifier. This method is automatically called by Tkinter whenever a BitmapImage object is passed to a Tkinter diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index 81ef32253bd..ce6342bdba2 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -63,12 +63,12 @@ def read_fields(self, field_format): data = self._read_bytes(size) return struct.unpack(field_format, data) - def read_boxes(self): + def read_boxes(self) -> BoxReader: size = self.remaining_in_box data = self._read_bytes(size) return BoxReader(io.BytesIO(data), size) - def has_next_box(self): + def has_next_box(self) -> bool: if self.has_length: return self.fp.tell() + self.remaining_in_box < self.length else: diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index 077c9ec8ba7..68501d625d4 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -87,10 +87,10 @@ class IndirectReferenceTuple(NamedTuple): class IndirectReference(IndirectReferenceTuple): - def __str__(self): + def __str__(self) -> str: return f"{self.object_id} {self.generation} R" - def __bytes__(self): + def __bytes__(self) -> bytes: return self.__str__().encode("us-ascii") def __eq__(self, other): @@ -108,7 +108,7 @@ def __hash__(self): class IndirectObjectDef(IndirectReference): - def __str__(self): + def __str__(self) -> str: return f"{self.object_id} {self.generation} obj" @@ -150,7 +150,7 @@ def __delitem__(self, key): def __contains__(self, key): return key in self.existing_entries or key in self.new_entries - def __len__(self): + def __len__(self) -> int: return len( set(self.existing_entries.keys()) | set(self.new_entries.keys()) @@ -211,7 +211,7 @@ def __init__(self, name): else: self.name = name.encode("us-ascii") - def name_as_str(self): + def name_as_str(self) -> str: return self.name.decode("us-ascii") def __eq__(self, other): @@ -222,7 +222,7 @@ def __eq__(self, other): def __hash__(self): return hash(self.name) - def __repr__(self): + def __repr__(self) -> str: return f"{self.__class__.__name__}({repr(self.name)})" @classmethod @@ -231,7 +231,7 @@ def from_pdf_stream(cls, data): allowed_chars = set(range(33, 127)) - {ord(c) for c in "#%/()<>[]{}"} - def __bytes__(self): + def __bytes__(self) -> bytes: result = bytearray(b"/") for b in self.name: if b in self.allowed_chars: @@ -242,7 +242,7 @@ def __bytes__(self): class PdfArray(List[Any]): - def __bytes__(self): + def __bytes__(self) -> bytes: return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]" @@ -286,7 +286,7 @@ def __getattr__(self, key): value = time.gmtime(calendar.timegm(value) + offset) return value - def __bytes__(self): + def __bytes__(self) -> bytes: out = bytearray(b"<<") for key, value in self.items(): if value is None: @@ -304,7 +304,7 @@ class PdfBinary: def __init__(self, data): self.data = data - def __bytes__(self): + def __bytes__(self) -> bytes: return b"<%s>" % b"".join(b"%02X" % b for b in self.data) diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index 21509b2d99f..5b8ad47f0cd 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -37,6 +37,7 @@ import os import struct import sys +from typing import TYPE_CHECKING from . import Image, ImageFile @@ -157,11 +158,11 @@ def _open(self) -> None: self._fp = self.fp # FIXME: hack @property - def n_frames(self): + def n_frames(self) -> int: return self._nimages @property - def is_animated(self): + def is_animated(self) -> bool: return self._nimages > 1 # 1st image index is zero (although SPIDER imgnumber starts at 1) @@ -191,8 +192,11 @@ def convert2byte(self, depth=255): b = -m * minimum return self.point(lambda i, m=m, b=b: i * m + b).convert("L") + if TYPE_CHECKING: + from . import ImageTk + # returns a ImageTk.PhotoImage object, after rescaling to 0..255 - def tkPhotoImage(self): + def tkPhotoImage(self) -> ImageTk.PhotoImage: from . import ImageTk return ImageTk.PhotoImage(self.convert2byte(), palette=256) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index a7a7e28bdbc..54faa59c55f 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -381,7 +381,7 @@ def limit_rational(self, max_denominator): f = self._val.limit_denominator(max_denominator) return f.numerator, f.denominator - def __repr__(self): + def __repr__(self) -> str: return str(float(self._val)) def __hash__(self): @@ -603,7 +603,7 @@ def reset(self): self._next = None self._offset = None - def __str__(self): + def __str__(self) -> str: return str(dict(self)) def named(self): @@ -617,7 +617,7 @@ def named(self): for code, value in self.items() } - def __len__(self): + def __len__(self) -> int: return len(set(self._tagdata) | set(self._tags_v2)) def __getitem__(self, tag): @@ -1041,7 +1041,7 @@ def from_v2(cls, original): ifd.next = original.next # an indicator for multipage tiffs return ifd - def to_v2(self): + def to_v2(self) -> ImageFileDirectory_v2: """Returns an :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2` instance with the same data as is contained in the original @@ -1061,7 +1061,7 @@ def to_v2(self): def __contains__(self, tag): return tag in self._tags_v1 or tag in self._tagdata - def __len__(self): + def __len__(self) -> int: return len(set(self._tagdata) | set(self._tags_v1)) def __iter__(self): @@ -1154,7 +1154,7 @@ def seek(self, frame: int) -> None: Image._decompression_bomb_check(self.size) self.im = Image.core.new(self.mode, self.size) - def _seek(self, frame): + def _seek(self, frame: int) -> None: self.fp = self._fp # reset buffered io handle in case fp @@ -2003,7 +2003,7 @@ def __exit__(self, exc_type, exc_value, traceback): self.close() return False - def tell(self): + def tell(self) -> int: return self.f.tell() - self.offsetOfNewPage def seek(self, offset, whence=io.SEEK_SET): diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index 052f253cf4e..4b8cfe65c7e 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -144,7 +144,7 @@ def _get_next(self): timestamp -= duration return data, timestamp, duration - def _seek(self, frame): + def _seek(self, frame: int) -> None: if self.__physical_frame == frame: return # Nothing to do if frame < self.__physical_frame: