mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-01 08:27:30 +03:00 
			
		
		
		
	Merge pull request #8134 from radarhere/type_hint
This commit is contained in:
		
						commit
						5d3338f13e
					
				|  | @ -103,7 +103,7 @@ def bdf_char( | |||
| class BdfFontFile(FontFile.FontFile): | ||||
|     """Font file plugin for the X11 BDF format.""" | ||||
| 
 | ||||
|     def __init__(self, fp: BinaryIO): | ||||
|     def __init__(self, fp: BinaryIO) -> None: | ||||
|         super().__init__() | ||||
| 
 | ||||
|         s = fp.readline() | ||||
|  |  | |||
|  | @ -34,12 +34,16 @@ from __future__ import annotations | |||
| import math | ||||
| import numbers | ||||
| import struct | ||||
| from types import ModuleType | ||||
| from typing import TYPE_CHECKING, AnyStr, Sequence, cast | ||||
| 
 | ||||
| from . import Image, ImageColor | ||||
| from ._deprecate import deprecate | ||||
| from ._typing import Coords | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from . import ImageDraw2, ImageFont | ||||
| 
 | ||||
| """ | ||||
| A simple 2D drawing interface for PIL images. | ||||
| <p> | ||||
|  | @ -93,9 +97,6 @@ class ImageDraw: | |||
|             self.fontmode = "L"  # aliasing is okay for other modes | ||||
|         self.fill = False | ||||
| 
 | ||||
|     if TYPE_CHECKING: | ||||
|         from . import ImageFont | ||||
| 
 | ||||
|     def getfont( | ||||
|         self, | ||||
|     ) -> ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont: | ||||
|  | @ -879,7 +880,7 @@ class ImageDraw: | |||
|         return bbox | ||||
| 
 | ||||
| 
 | ||||
| def Draw(im, mode: str | None = None) -> ImageDraw: | ||||
| def Draw(im: Image.Image, mode: str | None = None) -> ImageDraw: | ||||
|     """ | ||||
|     A simple 2D drawing interface for PIL images. | ||||
| 
 | ||||
|  | @ -891,7 +892,7 @@ def Draw(im, mode: str | None = None) -> ImageDraw: | |||
|        defaults to the mode of the image. | ||||
|     """ | ||||
|     try: | ||||
|         return im.getdraw(mode) | ||||
|         return getattr(im, "getdraw")(mode) | ||||
|     except AttributeError: | ||||
|         return ImageDraw(im, mode) | ||||
| 
 | ||||
|  | @ -903,7 +904,9 @@ except AttributeError: | |||
|     Outline = None | ||||
| 
 | ||||
| 
 | ||||
| def getdraw(im=None, hints=None): | ||||
| def getdraw( | ||||
|     im: Image.Image | None = None, hints: list[str] | None = None | ||||
| ) -> tuple[ImageDraw2.Draw | None, ModuleType]: | ||||
|     """ | ||||
|     :param im: The image to draw in. | ||||
|     :param hints: An optional list of hints. Deprecated. | ||||
|  | @ -913,9 +916,8 @@ def getdraw(im=None, hints=None): | |||
|         deprecate("'hints' parameter", 12) | ||||
|     from . import ImageDraw2 | ||||
| 
 | ||||
|     if im: | ||||
|         im = ImageDraw2.Draw(im) | ||||
|     return im, ImageDraw2 | ||||
|     draw = ImageDraw2.Draw(im) if im is not None else None | ||||
|     return draw, ImageDraw2 | ||||
| 
 | ||||
| 
 | ||||
| def floodfill( | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ class ImagePalette: | |||
|         self._palette = palette | ||||
| 
 | ||||
|     @property | ||||
|     def colors(self): | ||||
|     def colors(self) -> dict[tuple[int, int, int] | tuple[int, int, int, int], int]: | ||||
|         if self._colors is None: | ||||
|             mode_len = len(self.mode) | ||||
|             self._colors = {} | ||||
|  | @ -66,7 +66,9 @@ class ImagePalette: | |||
|         return self._colors | ||||
| 
 | ||||
|     @colors.setter | ||||
|     def colors(self, colors): | ||||
|     def colors( | ||||
|         self, colors: dict[tuple[int, int, int] | tuple[int, int, int, int], int] | ||||
|     ) -> None: | ||||
|         self._colors = colors | ||||
| 
 | ||||
|     def copy(self) -> ImagePalette: | ||||
|  | @ -107,11 +109,13 @@ class ImagePalette: | |||
|     # Declare tostring as an alias for tobytes | ||||
|     tostring = tobytes | ||||
| 
 | ||||
|     def _new_color_index(self, image=None, e=None): | ||||
|     def _new_color_index( | ||||
|         self, image: Image.Image | None = None, e: Exception | None = None | ||||
|     ) -> int: | ||||
|         if not isinstance(self.palette, bytearray): | ||||
|             self._palette = bytearray(self.palette) | ||||
|         index = len(self.palette) // 3 | ||||
|         special_colors = () | ||||
|         special_colors: tuple[int | tuple[int, ...] | None, ...] = () | ||||
|         if image: | ||||
|             special_colors = ( | ||||
|                 image.info.get("background"), | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): | |||
|             msg = "not an MIC file; no image entries" | ||||
|             raise SyntaxError(msg) | ||||
| 
 | ||||
|         self.frame = None | ||||
|         self.frame = -1 | ||||
|         self._n_frames = len(self.images) | ||||
|         self.is_animated = self._n_frames > 1 | ||||
| 
 | ||||
|  | @ -85,7 +85,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): | |||
| 
 | ||||
|         self.frame = frame | ||||
| 
 | ||||
|     def tell(self): | ||||
|     def tell(self) -> int: | ||||
|         return self.frame | ||||
| 
 | ||||
|     def close(self) -> None: | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ import struct | |||
| import warnings | ||||
| import zlib | ||||
| from enum import IntEnum | ||||
| from typing import IO, Any | ||||
| from typing import IO, TYPE_CHECKING, Any, NoReturn | ||||
| 
 | ||||
| from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence | ||||
| from ._binary import i16be as i16 | ||||
|  | @ -48,6 +48,9 @@ from ._binary import o8 | |||
| from ._binary import o16be as o16 | ||||
| from ._binary import o32be as o32 | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from . import _imaging | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
| is_cid = re.compile(rb"\w\w\w\w").match | ||||
|  | @ -249,6 +252,9 @@ class iTXt(str): | |||
| 
 | ||||
|     """ | ||||
| 
 | ||||
|     lang: str | bytes | None | ||||
|     tkey: str | bytes | None | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def __new__(cls, text, lang=None, tkey=None): | ||||
|         """ | ||||
|  | @ -270,10 +276,10 @@ class PngInfo: | |||
| 
 | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.chunks = [] | ||||
|     def __init__(self) -> None: | ||||
|         self.chunks: list[tuple[bytes, bytes, bool]] = [] | ||||
| 
 | ||||
|     def add(self, cid, data, after_idat=False): | ||||
|     def add(self, cid: bytes, data: bytes, after_idat: bool = False) -> None: | ||||
|         """Appends an arbitrary chunk. Use with caution. | ||||
| 
 | ||||
|         :param cid: a byte string, 4 bytes long. | ||||
|  | @ -283,12 +289,16 @@ class PngInfo: | |||
| 
 | ||||
|         """ | ||||
| 
 | ||||
|         chunk = [cid, data] | ||||
|         if after_idat: | ||||
|             chunk.append(True) | ||||
|         self.chunks.append(tuple(chunk)) | ||||
|         self.chunks.append((cid, data, after_idat)) | ||||
| 
 | ||||
|     def add_itxt(self, key, value, lang="", tkey="", zip=False): | ||||
|     def add_itxt( | ||||
|         self, | ||||
|         key: str | bytes, | ||||
|         value: str | bytes, | ||||
|         lang: str | bytes = "", | ||||
|         tkey: str | bytes = "", | ||||
|         zip: bool = False, | ||||
|     ) -> None: | ||||
|         """Appends an iTXt chunk. | ||||
| 
 | ||||
|         :param key: latin-1 encodable text key name | ||||
|  | @ -316,7 +326,9 @@ class PngInfo: | |||
|         else: | ||||
|             self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value) | ||||
| 
 | ||||
|     def add_text(self, key, value, zip=False): | ||||
|     def add_text( | ||||
|         self, key: str | bytes, value: str | bytes | iTXt, zip: bool = False | ||||
|     ) -> None: | ||||
|         """Appends a text chunk. | ||||
| 
 | ||||
|         :param key: latin-1 encodable text key name | ||||
|  | @ -326,7 +338,13 @@ class PngInfo: | |||
| 
 | ||||
|         """ | ||||
|         if isinstance(value, iTXt): | ||||
|             return self.add_itxt(key, value, value.lang, value.tkey, zip=zip) | ||||
|             return self.add_itxt( | ||||
|                 key, | ||||
|                 value, | ||||
|                 value.lang if value.lang is not None else b"", | ||||
|                 value.tkey if value.tkey is not None else b"", | ||||
|                 zip=zip, | ||||
|             ) | ||||
| 
 | ||||
|         # The tEXt chunk stores latin-1 text | ||||
|         if not isinstance(value, bytes): | ||||
|  | @ -434,7 +452,7 @@ class PngStream(ChunkStream): | |||
|             raise SyntaxError(msg) | ||||
|         return s | ||||
| 
 | ||||
|     def chunk_IDAT(self, pos, length): | ||||
|     def chunk_IDAT(self, pos: int, length: int) -> NoReturn: | ||||
|         # image data | ||||
|         if "bbox" in self.im_info: | ||||
|             tile = [("zip", self.im_info["bbox"], pos, self.im_rawmode)] | ||||
|  | @ -447,7 +465,7 @@ class PngStream(ChunkStream): | |||
|         msg = "image data found" | ||||
|         raise EOFError(msg) | ||||
| 
 | ||||
|     def chunk_IEND(self, pos, length): | ||||
|     def chunk_IEND(self, pos: int, length: int) -> NoReturn: | ||||
|         msg = "end of PNG image" | ||||
|         raise EOFError(msg) | ||||
| 
 | ||||
|  | @ -821,7 +839,10 @@ class PngImageFile(ImageFile.ImageFile): | |||
|                 msg = "no more images in APNG file" | ||||
|                 raise EOFError(msg) from e | ||||
| 
 | ||||
|     def _seek(self, frame, rewind=False): | ||||
|     def _seek(self, frame: int, rewind: bool = False) -> None: | ||||
|         assert self.png is not None | ||||
| 
 | ||||
|         self.dispose: _imaging.ImagingCore | None | ||||
|         if frame == 0: | ||||
|             if rewind: | ||||
|                 self._fp.seek(self.__rewind) | ||||
|  | @ -906,14 +927,14 @@ class PngImageFile(ImageFile.ImageFile): | |||
|         if self._prev_im is None and self.dispose_op == Disposal.OP_PREVIOUS: | ||||
|             self.dispose_op = Disposal.OP_BACKGROUND | ||||
| 
 | ||||
|         self.dispose = None | ||||
|         if self.dispose_op == Disposal.OP_PREVIOUS: | ||||
|             if self._prev_im: | ||||
|                 self.dispose = self._prev_im.copy() | ||||
|                 self.dispose = self._crop(self.dispose, self.dispose_extent) | ||||
|         elif self.dispose_op == Disposal.OP_BACKGROUND: | ||||
|             self.dispose = Image.core.fill(self.mode, self.size) | ||||
|             self.dispose = self._crop(self.dispose, self.dispose_extent) | ||||
|         else: | ||||
|             self.dispose = None | ||||
| 
 | ||||
|     def tell(self) -> int: | ||||
|         return self.__frame | ||||
|  | @ -1026,7 +1047,7 @@ class PngImageFile(ImageFile.ImageFile): | |||
|             return None | ||||
|         return self.getexif()._get_merged_dict() | ||||
| 
 | ||||
|     def getexif(self): | ||||
|     def getexif(self) -> Image.Exif: | ||||
|         if "exif" not in self.info: | ||||
|             self.load() | ||||
| 
 | ||||
|  | @ -1346,7 +1367,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): | |||
|                 chunk(fp, cid, data) | ||||
|             elif cid[1:2].islower(): | ||||
|                 # Private chunk | ||||
|                 after_idat = info_chunk[2:3] | ||||
|                 after_idat = len(info_chunk) == 3 and info_chunk[2] | ||||
|                 if not after_idat: | ||||
|                     chunk(fp, cid, data) | ||||
| 
 | ||||
|  | @ -1425,7 +1446,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): | |||
|             cid, data = info_chunk[:2] | ||||
|             if cid[1:2].islower(): | ||||
|                 # Private chunk | ||||
|                 after_idat = info_chunk[2:3] | ||||
|                 after_idat = len(info_chunk) == 3 and info_chunk[2] | ||||
|                 if after_idat: | ||||
|                     chunk(fp, cid, data) | ||||
| 
 | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ import warnings | |||
| from collections.abc import MutableMapping | ||||
| from fractions import Fraction | ||||
| from numbers import Number, Rational | ||||
| from typing import IO, TYPE_CHECKING, Any, Callable | ||||
| from typing import IO, TYPE_CHECKING, Any, Callable, NoReturn | ||||
| 
 | ||||
| from . import ExifTags, Image, ImageFile, ImageOps, ImagePalette, TiffTags | ||||
| from ._binary import i16be as i16 | ||||
|  | @ -384,7 +384,7 @@ class IFDRational(Rational): | |||
|     def __repr__(self) -> str: | ||||
|         return str(float(self._val)) | ||||
| 
 | ||||
|     def __hash__(self): | ||||
|     def __hash__(self) -> int: | ||||
|         return self._val.__hash__() | ||||
| 
 | ||||
|     def __eq__(self, other: object) -> bool: | ||||
|  | @ -551,7 +551,12 @@ class ImageFileDirectory_v2(_IFDv2Base): | |||
|     _load_dispatch: dict[int, Callable[[ImageFileDirectory_v2, bytes, bool], Any]] = {} | ||||
|     _write_dispatch: dict[int, Callable[..., Any]] = {} | ||||
| 
 | ||||
|     def __init__(self, ifh=b"II\052\0\0\0\0\0", prefix=None, group=None): | ||||
|     def __init__( | ||||
|         self, | ||||
|         ifh: bytes = b"II\052\0\0\0\0\0", | ||||
|         prefix: bytes | None = None, | ||||
|         group: int | None = None, | ||||
|     ) -> None: | ||||
|         """Initialize an ImageFileDirectory. | ||||
| 
 | ||||
|         To construct an ImageFileDirectory from a real file, pass the 8-byte | ||||
|  | @ -575,7 +580,7 @@ class ImageFileDirectory_v2(_IFDv2Base): | |||
|             raise SyntaxError(msg) | ||||
|         self._bigtiff = ifh[2] == 43 | ||||
|         self.group = group | ||||
|         self.tagtype = {} | ||||
|         self.tagtype: dict[int, int] = {} | ||||
|         """ Dictionary of tag types """ | ||||
|         self.reset() | ||||
|         (self.next,) = ( | ||||
|  | @ -587,18 +592,18 @@ class ImageFileDirectory_v2(_IFDv2Base): | |||
|     offset = property(lambda self: self._offset) | ||||
| 
 | ||||
|     @property | ||||
|     def legacy_api(self): | ||||
|     def legacy_api(self) -> bool: | ||||
|         return self._legacy_api | ||||
| 
 | ||||
|     @legacy_api.setter | ||||
|     def legacy_api(self, value): | ||||
|     def legacy_api(self, value: bool) -> NoReturn: | ||||
|         msg = "Not allowing setting of legacy api" | ||||
|         raise Exception(msg) | ||||
| 
 | ||||
|     def reset(self): | ||||
|         self._tags_v1 = {}  # will remain empty if legacy_api is false | ||||
|         self._tags_v2 = {}  # main tag storage | ||||
|         self._tagdata = {} | ||||
|     def reset(self) -> None: | ||||
|         self._tags_v1: dict[int, Any] = {}  # will remain empty if legacy_api is false | ||||
|         self._tags_v2: dict[int, Any] = {}  # main tag storage | ||||
|         self._tagdata: dict[int, bytes] = {} | ||||
|         self.tagtype = {}  # added 2008-06-05 by Florian Hoech | ||||
|         self._next = None | ||||
|         self._offset = None | ||||
|  | @ -2039,7 +2044,7 @@ class AppendingTiffWriter: | |||
|             num_tags = self.readShort() | ||||
|             self.f.seek(num_tags * 12, os.SEEK_CUR) | ||||
| 
 | ||||
|     def write(self, data): | ||||
|     def write(self, data: bytes) -> int | None: | ||||
|         return self.f.write(data) | ||||
| 
 | ||||
|     def readShort(self) -> int: | ||||
|  | @ -2122,7 +2127,9 @@ class AppendingTiffWriter: | |||
|                 # skip the locally stored value that is not an offset | ||||
|                 self.f.seek(4, os.SEEK_CUR) | ||||
| 
 | ||||
|     def fixOffsets(self, count, isShort=False, isLong=False): | ||||
|     def fixOffsets( | ||||
|         self, count: int, isShort: bool = False, isLong: bool = False | ||||
|     ) -> None: | ||||
|         if not isShort and not isLong: | ||||
|             msg = "offset is neither short nor long" | ||||
|             raise RuntimeError(msg) | ||||
|  |  | |||
|  | @ -12,5 +12,5 @@ class ImagingDraw: | |||
| class PixelAccess: | ||||
|     def __getattr__(self, name: str) -> Any: ... | ||||
| 
 | ||||
| def font(image, glyphdata: bytes) -> ImagingFont: ... | ||||
| def font(image: ImagingCore, glyphdata: bytes) -> ImagingFont: ... | ||||
| def __getattr__(name: str) -> Any: ... | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import collections | |||
| import os | ||||
| import sys | ||||
| import warnings | ||||
| from typing import IO | ||||
| 
 | ||||
| import PIL | ||||
| 
 | ||||
|  | @ -223,7 +224,7 @@ def get_supported() -> list[str]: | |||
|     return ret | ||||
| 
 | ||||
| 
 | ||||
| def pilinfo(out=None, supported_formats=True): | ||||
| def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None: | ||||
|     """ | ||||
|     Prints information about this installation of Pillow. | ||||
|     This function can be called with ``python3 -m PIL``. | ||||
|  | @ -244,9 +245,9 @@ def pilinfo(out=None, supported_formats=True): | |||
| 
 | ||||
|     print("-" * 68, file=out) | ||||
|     print(f"Pillow {PIL.__version__}", file=out) | ||||
|     py_version = sys.version.splitlines() | ||||
|     print(f"Python {py_version[0].strip()}", file=out) | ||||
|     for py_version in py_version[1:]: | ||||
|     py_version_lines = sys.version.splitlines() | ||||
|     print(f"Python {py_version_lines[0].strip()}", file=out) | ||||
|     for py_version in py_version_lines[1:]: | ||||
|         print(f"       {py_version.strip()}", file=out) | ||||
|     print("-" * 68, file=out) | ||||
|     print(f"Python executable is {sys.executable or 'unknown'}", file=out) | ||||
|  | @ -282,9 +283,12 @@ def pilinfo(out=None, supported_formats=True): | |||
|         ("xcb", "XCB (X protocol)"), | ||||
|     ]: | ||||
|         if check(name): | ||||
|             if name == "jpg" and check_feature("libjpeg_turbo"): | ||||
|                 v = "libjpeg-turbo " + version_feature("libjpeg_turbo") | ||||
|             else: | ||||
|             v: str | None = None | ||||
|             if name == "jpg": | ||||
|                 libjpeg_turbo_version = version_feature("libjpeg_turbo") | ||||
|                 if libjpeg_turbo_version is not None: | ||||
|                     v = "libjpeg-turbo " + libjpeg_turbo_version | ||||
|             if v is None: | ||||
|                 v = version(name) | ||||
|             if v is not None: | ||||
|                 version_static = name in ("pil", "jpg") | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user