add type hints for Image.open and Image.init

This commit is contained in:
Nulano 2024-04-04 19:54:07 +02:00
parent e8ab564077
commit 8c14a394c1

View File

@ -41,7 +41,7 @@ import warnings
from collections.abc import Callable, MutableMapping from collections.abc import Callable, MutableMapping
from enum import IntEnum from enum import IntEnum
from types import ModuleType from types import ModuleType
from typing import IO, TYPE_CHECKING, Any from typing import IO, TYPE_CHECKING, Any, Literal, cast
# VERSION was removed in Pillow 6.0.0. # VERSION was removed in Pillow 6.0.0.
# PILLOW_VERSION was removed in Pillow 9.0.0. # PILLOW_VERSION was removed in Pillow 9.0.0.
@ -55,7 +55,7 @@ from . import (
_plugins, _plugins,
) )
from ._binary import i32le, o32be, o32le from ._binary import i32le, o32be, o32le
from ._typing import TypeGuard from ._typing import StrOrBytesPath, TypeGuard
from ._util import DeferredError, is_path from ._util import DeferredError, is_path
ElementTree: ModuleType | None ElementTree: ModuleType | None
@ -357,7 +357,7 @@ def preinit() -> None:
_initialized = 1 _initialized = 1
def init(): def init() -> bool:
""" """
Explicitly initializes the Python Imaging Library. This function Explicitly initializes the Python Imaging Library. This function
loads all available file format drivers. loads all available file format drivers.
@ -368,7 +368,7 @@ def init():
global _initialized global _initialized
if _initialized >= 2: if _initialized >= 2:
return 0 return False
parent_name = __name__.rpartition(".")[0] parent_name = __name__.rpartition(".")[0]
for plugin in _plugins: for plugin in _plugins:
@ -380,7 +380,8 @@ def init():
if OPEN or SAVE: if OPEN or SAVE:
_initialized = 2 _initialized = 2
return 1 return True
return False
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -3222,7 +3223,11 @@ def _decompression_bomb_check(size: tuple[int, int]) -> None:
) )
def open(fp, mode="r", formats=None) -> Image: def open(
fp: StrOrBytesPath | IO[bytes],
mode: Literal["r"] = "r",
formats: list[str] | tuple[str, ...] | None = None,
) -> ImageFile.ImageFile:
""" """
Opens and identifies the given image file. Opens and identifies the given image file.
@ -3253,10 +3258,10 @@ def open(fp, mode="r", formats=None) -> Image:
""" """
if mode != "r": if mode != "r":
msg = f"bad mode {repr(mode)}" msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
raise ValueError(msg) raise ValueError(msg)
elif isinstance(fp, io.StringIO): elif isinstance(fp, io.StringIO):
msg = ( msg = ( # type: ignore[unreachable]
"StringIO cannot be used to open an image. " "StringIO cannot be used to open an image. "
"Binary data must be used instead." "Binary data must be used instead."
) )
@ -3265,7 +3270,7 @@ def open(fp, mode="r", formats=None) -> Image:
if formats is None: if formats is None:
formats = ID formats = ID
elif not isinstance(formats, (list, tuple)): elif not isinstance(formats, (list, tuple)):
msg = "formats must be a list or tuple" msg = "formats must be a list or tuple" # type: ignore[unreachable]
raise TypeError(msg) raise TypeError(msg)
exclusive_fp = False exclusive_fp = False
@ -3276,6 +3281,8 @@ def open(fp, mode="r", formats=None) -> Image:
if filename: if filename:
fp = builtins.open(filename, "rb") fp = builtins.open(filename, "rb")
exclusive_fp = True exclusive_fp = True
else:
fp = cast(IO[bytes], fp)
try: try:
fp.seek(0) fp.seek(0)
@ -3287,9 +3294,14 @@ def open(fp, mode="r", formats=None) -> Image:
preinit() preinit()
accept_warnings = [] accept_warnings: list[str | bytes] = []
def _open_core(fp, filename, prefix, formats): def _open_core(
fp: IO[bytes],
filename: str | bytes,
prefix: bytes,
formats: list[str] | tuple[str, ...],
) -> ImageFile.ImageFile | None:
for i in formats: for i in formats:
i = i.upper() i = i.upper()
if i not in OPEN: if i not in OPEN:
@ -3298,7 +3310,7 @@ def open(fp, mode="r", formats=None) -> Image:
factory, accept = OPEN[i] factory, accept = OPEN[i]
result = not accept or accept(prefix) result = not accept or accept(prefix)
if type(result) in [str, bytes]: if type(result) in [str, bytes]:
accept_warnings.append(result) accept_warnings.append(result) # type: ignore[arg-type]
elif result: elif result:
fp.seek(0) fp.seek(0)
im = factory(fp, filename) im = factory(fp, filename)
@ -3318,7 +3330,7 @@ def open(fp, mode="r", formats=None) -> Image:
im = _open_core(fp, filename, prefix, formats) im = _open_core(fp, filename, prefix, formats)
if im is None and formats is ID: if im is None and formats is ID:
checked_formats = formats.copy() checked_formats = ID.copy()
if init(): if init():
im = _open_core( im = _open_core(
fp, fp,
@ -3334,7 +3346,7 @@ def open(fp, mode="r", formats=None) -> Image:
if exclusive_fp: if exclusive_fp:
fp.close() fp.close()
for message in accept_warnings: for message in accept_warnings:
warnings.warn(message) warnings.warn(message) # type: ignore[arg-type]
msg = "cannot identify image file %r" % (filename if filename else fp) msg = "cannot identify image file %r" % (filename if filename else fp)
raise UnidentifiedImageError(msg) raise UnidentifiedImageError(msg)