mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 16:07:30 +03:00 
			
		
		
		
	Merge pull request #8270 from radarhere/type_hint
This commit is contained in:
		
						commit
						4df4df2a18
					
				|  | @ -154,7 +154,7 @@ class TestFileJpeg: | |||
|             assert k > 0.9 | ||||
| 
 | ||||
|     def test_rgb(self) -> None: | ||||
|         def getchannels(im: JpegImagePlugin.JpegImageFile) -> tuple[int, int, int]: | ||||
|         def getchannels(im: JpegImagePlugin.JpegImageFile) -> tuple[int, ...]: | ||||
|             return tuple(v[0] for v in im.layer) | ||||
| 
 | ||||
|         im = hopper() | ||||
|  |  | |||
|  | @ -99,7 +99,7 @@ class TestImage: | |||
|         im = Image.new("L", (100, 100)) | ||||
| 
 | ||||
|         p = Pretty() | ||||
|         im._repr_pretty_(p, None) | ||||
|         im._repr_pretty_(p, False) | ||||
|         assert p.pretty_output == "<PIL.Image.Image image mode=L size=100x100>" | ||||
| 
 | ||||
|     def test_open_formats(self) -> None: | ||||
|  |  | |||
|  | @ -185,6 +185,14 @@ Plugin reference | |||
|     :undoc-members: | ||||
|     :show-inheritance: | ||||
| 
 | ||||
| :mod:`~PIL.MpoImagePlugin` Module | ||||
| ---------------------------------- | ||||
| 
 | ||||
| .. automodule:: PIL.MpoImagePlugin | ||||
|     :members: | ||||
|     :undoc-members: | ||||
|     :show-inheritance: | ||||
| 
 | ||||
| :mod:`~PIL.MspImagePlugin` Module | ||||
| --------------------------------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -65,16 +65,24 @@ def has_ghostscript() -> bool: | |||
|     return gs_binary is not False | ||||
| 
 | ||||
| 
 | ||||
| def Ghostscript(tile, size, fp, scale=1, transparency: bool = False) -> Image.Image: | ||||
| def Ghostscript( | ||||
|     tile: list[ImageFile._Tile], | ||||
|     size: tuple[int, int], | ||||
|     fp: IO[bytes], | ||||
|     scale: int = 1, | ||||
|     transparency: bool = False, | ||||
| ) -> Image.Image: | ||||
|     """Render an image using Ghostscript""" | ||||
|     global gs_binary | ||||
|     if not has_ghostscript(): | ||||
|         msg = "Unable to locate Ghostscript on paths" | ||||
|         raise OSError(msg) | ||||
|     assert isinstance(gs_binary, str) | ||||
| 
 | ||||
|     # Unpack decoder tile | ||||
|     decoder, tile, offset, data = tile[0] | ||||
|     length, bbox = data | ||||
|     args = tile[0].args | ||||
|     assert isinstance(args, tuple) | ||||
|     length, bbox = args | ||||
| 
 | ||||
|     # Hack to support hi-res rendering | ||||
|     scale = int(scale) or 1 | ||||
|  | @ -227,7 +235,11 @@ class EpsImageFile(ImageFile.ImageFile): | |||
|                         # put floating point values there anyway. | ||||
|                         box = [int(float(i)) for i in v.split()] | ||||
|                         self._size = box[2] - box[0], box[3] - box[1] | ||||
|                         self.tile = [("eps", (0, 0) + self.size, offset, (length, box))] | ||||
|                         self.tile = [ | ||||
|                             ImageFile._Tile( | ||||
|                                 "eps", (0, 0) + self.size, offset, (length, box) | ||||
|                             ) | ||||
|                         ] | ||||
|                     except Exception: | ||||
|                         pass | ||||
|             return True | ||||
|  |  | |||
|  | @ -220,7 +220,7 @@ if hasattr(core, "DEFAULT_STRATEGY"): | |||
| if TYPE_CHECKING: | ||||
|     from xml.etree.ElementTree import Element | ||||
| 
 | ||||
|     from . import ImageFile, ImagePalette | ||||
|     from . import ImageFile, ImagePalette, TiffImagePlugin | ||||
|     from ._typing import NumpyArray, StrOrBytesPath, TypeGuard | ||||
| ID: list[str] = [] | ||||
| OPEN: dict[ | ||||
|  | @ -676,7 +676,7 @@ class Image: | |||
|             id(self), | ||||
|         ) | ||||
| 
 | ||||
|     def _repr_pretty_(self, p, cycle) -> None: | ||||
|     def _repr_pretty_(self, p, cycle: bool) -> None: | ||||
|         """IPython plain text display support""" | ||||
| 
 | ||||
|         # Same as __repr__ but without unpredictable id(self), | ||||
|  | @ -1551,6 +1551,7 @@ class Image: | |||
|                     ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset)) | ||||
|         ifd1 = exif.get_ifd(ExifTags.IFD.IFD1) | ||||
|         if ifd1 and ifd1.get(513): | ||||
|             assert exif._info is not None | ||||
|             ifds.append((ifd1, exif._info.next)) | ||||
| 
 | ||||
|         offset = None | ||||
|  | @ -1560,6 +1561,7 @@ class Image: | |||
|                 offset = current_offset | ||||
| 
 | ||||
|             fp = self.fp | ||||
|             if ifd is not None: | ||||
|                 thumbnail_offset = ifd.get(513) | ||||
|                 if thumbnail_offset is not None: | ||||
|                     thumbnail_offset += getattr(self, "_exif_offset", 0) | ||||
|  | @ -3869,14 +3871,14 @@ class Exif(_ExifBase): | |||
|     bigtiff = False | ||||
|     _loaded = False | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self._data = {} | ||||
|         self._hidden_data = {} | ||||
|         self._ifds = {} | ||||
|         self._info = None | ||||
|         self._loaded_exif = None | ||||
|     def __init__(self) -> None: | ||||
|         self._data: dict[int, Any] = {} | ||||
|         self._hidden_data: dict[int, Any] = {} | ||||
|         self._ifds: dict[int, dict[int, Any]] = {} | ||||
|         self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None | ||||
|         self._loaded_exif: bytes | None = None | ||||
| 
 | ||||
|     def _fixup(self, value): | ||||
|     def _fixup(self, value: Any) -> Any: | ||||
|         try: | ||||
|             if len(value) == 1 and isinstance(value, tuple): | ||||
|                 return value[0] | ||||
|  | @ -3884,24 +3886,26 @@ class Exif(_ExifBase): | |||
|             pass | ||||
|         return value | ||||
| 
 | ||||
|     def _fixup_dict(self, src_dict): | ||||
|     def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: | ||||
|         # Helper function | ||||
|         # returns a dict with any single item tuples/lists as individual values | ||||
|         return {k: self._fixup(v) for k, v in src_dict.items()} | ||||
| 
 | ||||
|     def _get_ifd_dict(self, offset: int, group: int | None = None): | ||||
|     def _get_ifd_dict( | ||||
|         self, offset: int, group: int | None = None | ||||
|     ) -> dict[int, Any] | None: | ||||
|         try: | ||||
|             # an offset pointer to the location of the nested embedded IFD. | ||||
|             # It should be a long, but may be corrupted. | ||||
|             self.fp.seek(offset) | ||||
|         except (KeyError, TypeError): | ||||
|             pass | ||||
|             return None | ||||
|         else: | ||||
|             from . import TiffImagePlugin | ||||
| 
 | ||||
|             info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) | ||||
|             info.load(self.fp) | ||||
|             return self._fixup_dict(info) | ||||
|             return self._fixup_dict(dict(info)) | ||||
| 
 | ||||
|     def _get_head(self) -> bytes: | ||||
|         version = b"\x2B" if self.bigtiff else b"\x2A" | ||||
|  | @ -3966,7 +3970,7 @@ class Exif(_ExifBase): | |||
|         self.fp.seek(offset) | ||||
|         self._info.load(self.fp) | ||||
| 
 | ||||
|     def _get_merged_dict(self): | ||||
|     def _get_merged_dict(self) -> dict[int, Any]: | ||||
|         merged_dict = dict(self) | ||||
| 
 | ||||
|         # get EXIF extension | ||||
|  | @ -4124,7 +4128,7 @@ class Exif(_ExifBase): | |||
|             keys.update(self._info) | ||||
|         return len(keys) | ||||
| 
 | ||||
|     def __getitem__(self, tag: int): | ||||
|     def __getitem__(self, tag: int) -> Any: | ||||
|         if self._info is not None and tag not in self._data and tag in self._info: | ||||
|             self._data[tag] = self._fixup(self._info[tag]) | ||||
|             del self._info[tag] | ||||
|  | @ -4133,7 +4137,7 @@ class Exif(_ExifBase): | |||
|     def __contains__(self, tag: object) -> bool: | ||||
|         return tag in self._data or (self._info is not None and tag in self._info) | ||||
| 
 | ||||
|     def __setitem__(self, tag: int, value) -> None: | ||||
|     def __setitem__(self, tag: int, value: Any) -> None: | ||||
|         if self._info is not None and tag in self._info: | ||||
|             del self._info[tag] | ||||
|         self._data[tag] = value | ||||
|  |  | |||
|  | @ -86,7 +86,7 @@ def raise_oserror(error: int) -> OSError: | |||
|     raise _get_oserror(error, encoder=False) | ||||
| 
 | ||||
| 
 | ||||
| def _tilesort(t) -> int: | ||||
| def _tilesort(t: _Tile) -> int: | ||||
|     # sort on offset | ||||
|     return t[2] | ||||
| 
 | ||||
|  | @ -161,7 +161,7 @@ class ImageFile(Image.Image): | |||
|             return Image.MIME.get(self.format.upper()) | ||||
|         return None | ||||
| 
 | ||||
|     def __setstate__(self, state) -> None: | ||||
|     def __setstate__(self, state: list[Any]) -> None: | ||||
|         self.tile = [] | ||||
|         super().__setstate__(state) | ||||
| 
 | ||||
|  | @ -525,7 +525,7 @@ class Parser: | |||
| # -------------------------------------------------------------------- | ||||
| 
 | ||||
| 
 | ||||
| def _save(im, fp, tile, bufsize: int = 0) -> None: | ||||
| def _save(im: Image.Image, fp: IO[bytes], tile, bufsize: int = 0) -> None: | ||||
|     """Helper to save image based on tile list | ||||
| 
 | ||||
|     :param im: Image object. | ||||
|  | @ -554,7 +554,12 @@ def _save(im, fp, tile, bufsize: int = 0) -> None: | |||
| 
 | ||||
| 
 | ||||
| def _encode_tile( | ||||
|     im, fp: IO[bytes], tile: list[_Tile], bufsize: int, fh, exc=None | ||||
|     im: Image.Image, | ||||
|     fp: IO[bytes], | ||||
|     tile: list[_Tile], | ||||
|     bufsize: int, | ||||
|     fh, | ||||
|     exc: BaseException | None = None, | ||||
| ) -> None: | ||||
|     for encoder_name, extents, offset, args in tile: | ||||
|         if offset > 0: | ||||
|  | @ -664,7 +669,11 @@ class PyCodec: | |||
|         """ | ||||
|         self.fd = fd | ||||
| 
 | ||||
|     def setimage(self, im, extents=None): | ||||
|     def setimage( | ||||
|         self, | ||||
|         im: Image.core.ImagingCore, | ||||
|         extents: tuple[int, int, int, int] | None = None, | ||||
|     ) -> None: | ||||
|         """ | ||||
|         Called from ImageFile to set the core output image for the codec | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ import subprocess | |||
| import sys | ||||
| import tempfile | ||||
| import warnings | ||||
| from typing import IO, Any | ||||
| from typing import IO, TYPE_CHECKING, Any | ||||
| 
 | ||||
| from . import Image, ImageFile | ||||
| from ._binary import i16be as i16 | ||||
|  | @ -51,6 +51,9 @@ from ._binary import o8 | |||
| from ._binary import o16be as o16 | ||||
| from .JpegPresets import presets | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from .MpoImagePlugin import MpoImageFile | ||||
| 
 | ||||
| # | ||||
| # Parser | ||||
| 
 | ||||
|  | @ -329,7 +332,7 @@ class JpegImageFile(ImageFile.ImageFile): | |||
|     format = "JPEG" | ||||
|     format_description = "JPEG (ISO 10918)" | ||||
| 
 | ||||
|     def _open(self): | ||||
|     def _open(self) -> None: | ||||
|         s = self.fp.read(3) | ||||
| 
 | ||||
|         if not _accept(s): | ||||
|  | @ -342,13 +345,13 @@ class JpegImageFile(ImageFile.ImageFile): | |||
|         self._exif_offset = 0 | ||||
| 
 | ||||
|         # JPEG specifics (internal) | ||||
|         self.layer = [] | ||||
|         self.huffman_dc = {} | ||||
|         self.huffman_ac = {} | ||||
|         self.quantization = {} | ||||
|         self.app = {}  # compatibility | ||||
|         self.applist = [] | ||||
|         self.icclist = [] | ||||
|         self.layer: list[tuple[int, int, int, int]] = [] | ||||
|         self.huffman_dc: dict[Any, Any] = {} | ||||
|         self.huffman_ac: dict[Any, Any] = {} | ||||
|         self.quantization: dict[int, list[int]] = {} | ||||
|         self.app: dict[str, bytes] = {}  # compatibility | ||||
|         self.applist: list[tuple[str, bytes]] = [] | ||||
|         self.icclist: list[bytes] = [] | ||||
| 
 | ||||
|         while True: | ||||
|             i = s[0] | ||||
|  | @ -831,7 +834,9 @@ def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: | |||
| 
 | ||||
| ## | ||||
| # Factory for making JPEG and MPO instances | ||||
| def jpeg_factory(fp: IO[bytes] | None = None, filename: str | bytes | None = None): | ||||
| def jpeg_factory( | ||||
|     fp: IO[bytes] | None = None, filename: str | bytes | None = None | ||||
| ) -> JpegImageFile | MpoImageFile: | ||||
|     im = JpegImageFile(fp, filename) | ||||
|     try: | ||||
|         mpheader = im._getmp() | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ import warnings | |||
| import zlib | ||||
| from collections.abc import Callable | ||||
| from enum import IntEnum | ||||
| from typing import IO, TYPE_CHECKING, Any, NamedTuple, NoReturn | ||||
| from typing import IO, TYPE_CHECKING, Any, NamedTuple, NoReturn, cast | ||||
| 
 | ||||
| from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence | ||||
| from ._binary import i16be as i16 | ||||
|  | @ -1223,7 +1223,11 @@ def _write_multiple_frames( | |||
|     if default_image: | ||||
|         if im.mode != mode: | ||||
|             im = im.convert(mode) | ||||
|         ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]) | ||||
|         ImageFile._save( | ||||
|             im, | ||||
|             cast(IO[bytes], _idat(fp, chunk)), | ||||
|             [("zip", (0, 0) + im.size, 0, rawmode)], | ||||
|         ) | ||||
| 
 | ||||
|     seq_num = 0 | ||||
|     for frame, frame_data in enumerate(im_frames): | ||||
|  | @ -1258,14 +1262,14 @@ def _write_multiple_frames( | |||
|             # first frame must be in IDAT chunks for backwards compatibility | ||||
|             ImageFile._save( | ||||
|                 im_frame, | ||||
|                 _idat(fp, chunk), | ||||
|                 cast(IO[bytes], _idat(fp, chunk)), | ||||
|                 [("zip", (0, 0) + im_frame.size, 0, rawmode)], | ||||
|             ) | ||||
|         else: | ||||
|             fdat_chunks = _fdat(fp, chunk, seq_num) | ||||
|             ImageFile._save( | ||||
|                 im_frame, | ||||
|                 fdat_chunks, | ||||
|                 cast(IO[bytes], fdat_chunks), | ||||
|                 [("zip", (0, 0) + im_frame.size, 0, rawmode)], | ||||
|             ) | ||||
|             seq_num = fdat_chunks.seq_num | ||||
|  | @ -1465,7 +1469,9 @@ def _save( | |||
|         ) | ||||
|     if single_im: | ||||
|         ImageFile._save( | ||||
|             single_im, _idat(fp, chunk), [("zip", (0, 0) + single_im.size, 0, rawmode)] | ||||
|             single_im, | ||||
|             cast(IO[bytes], _idat(fp, chunk)), | ||||
|             [("zip", (0, 0) + single_im.size, 0, rawmode)], | ||||
|         ) | ||||
| 
 | ||||
|     if info: | ||||
|  |  | |||
|  | @ -288,8 +288,10 @@ def _accept(prefix: bytes) -> bool: | |||
|     return prefix[:4] in PREFIXES | ||||
| 
 | ||||
| 
 | ||||
| def _limit_rational(val, max_val): | ||||
|     inv = abs(val) > 1 | ||||
| def _limit_rational( | ||||
|     val: float | Fraction | IFDRational, max_val: int | ||||
| ) -> tuple[float, float]: | ||||
|     inv = abs(float(val)) > 1 | ||||
|     n_d = IFDRational(1 / val if inv else val).limit_rational(max_val) | ||||
|     return n_d[::-1] if inv else n_d | ||||
| 
 | ||||
|  | @ -792,7 +794,9 @@ class ImageFileDirectory_v2(_IFDv2Base): | |||
|         return value + b"\0" | ||||
| 
 | ||||
|     @_register_loader(5, 8) | ||||
|     def load_rational(self, data, legacy_api: bool = True): | ||||
|     def load_rational( | ||||
|         self, data: bytes, legacy_api: bool = True | ||||
|     ) -> tuple[tuple[int, int] | IFDRational, ...]: | ||||
|         vals = self._unpack(f"{len(data) // 4}L", data) | ||||
| 
 | ||||
|         def combine(a: int, b: int) -> tuple[int, int] | IFDRational: | ||||
|  | @ -801,7 +805,7 @@ class ImageFileDirectory_v2(_IFDv2Base): | |||
|         return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) | ||||
| 
 | ||||
|     @_register_writer(5) | ||||
|     def write_rational(self, *values) -> bytes: | ||||
|     def write_rational(self, *values: IFDRational) -> bytes: | ||||
|         return b"".join( | ||||
|             self._pack("2L", *_limit_rational(frac, 2**32 - 1)) for frac in values | ||||
|         ) | ||||
|  | @ -828,7 +832,7 @@ class ImageFileDirectory_v2(_IFDv2Base): | |||
|         return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) | ||||
| 
 | ||||
|     @_register_writer(10) | ||||
|     def write_signed_rational(self, *values) -> bytes: | ||||
|     def write_signed_rational(self, *values: IFDRational) -> bytes: | ||||
|         return b"".join( | ||||
|             self._pack("2l", *_limit_signed_rational(frac, 2**31 - 1, -(2**31))) | ||||
|             for frac in values | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user