mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 09:26:16 +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:
|
||||
self.dispose = self._prev_im.copy()
|
||||
self.dispose = self._crop(self.dispose, self.dispose_extent)
|
||||
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