mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 01:46:18 +03:00
Added type hints
This commit is contained in:
parent
497080f63b
commit
8afb7ddb4e
|
@ -5,6 +5,7 @@ ipython
|
||||||
numpy
|
numpy
|
||||||
packaging
|
packaging
|
||||||
pytest
|
pytest
|
||||||
|
sphinx
|
||||||
types-defusedxml
|
types-defusedxml
|
||||||
types-olefile
|
types-olefile
|
||||||
types-setuptools
|
types-setuptools
|
||||||
|
|
|
@ -14,6 +14,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
from PIL import Image, ImageFile
|
from PIL import Image, ImageFile
|
||||||
|
|
||||||
|
@ -94,26 +95,26 @@ DXT3_FOURCC = 0x33545844
|
||||||
DXT5_FOURCC = 0x35545844
|
DXT5_FOURCC = 0x35545844
|
||||||
|
|
||||||
|
|
||||||
def _decode565(bits):
|
def _decode565(bits: int) -> tuple[int, int, int]:
|
||||||
a = ((bits >> 11) & 0x1F) << 3
|
a = ((bits >> 11) & 0x1F) << 3
|
||||||
b = ((bits >> 5) & 0x3F) << 2
|
b = ((bits >> 5) & 0x3F) << 2
|
||||||
c = (bits & 0x1F) << 3
|
c = (bits & 0x1F) << 3
|
||||||
return a, b, c
|
return a, b, c
|
||||||
|
|
||||||
|
|
||||||
def _c2a(a, b):
|
def _c2a(a: int, b: int) -> int:
|
||||||
return (2 * a + b) // 3
|
return (2 * a + b) // 3
|
||||||
|
|
||||||
|
|
||||||
def _c2b(a, b):
|
def _c2b(a: int, b: int) -> int:
|
||||||
return (a + b) // 2
|
return (a + b) // 2
|
||||||
|
|
||||||
|
|
||||||
def _c3(a, b):
|
def _c3(a: int, b: int) -> int:
|
||||||
return (2 * b + a) // 3
|
return (2 * b + a) // 3
|
||||||
|
|
||||||
|
|
||||||
def _dxt1(data, width, height):
|
def _dxt1(data: IO[bytes], width: int, height: int) -> bytes:
|
||||||
# TODO implement this function as pixel format in decode.c
|
# TODO implement this function as pixel format in decode.c
|
||||||
ret = bytearray(4 * width * height)
|
ret = bytearray(4 * width * height)
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ def _dxt1(data, width, height):
|
||||||
return bytes(ret)
|
return bytes(ret)
|
||||||
|
|
||||||
|
|
||||||
def _dxtc_alpha(a0, a1, ac0, ac1, ai):
|
def _dxtc_alpha(a0: int, a1: int, ac0: int, ac1: int, ai: int) -> int:
|
||||||
if ai <= 12:
|
if ai <= 12:
|
||||||
ac = (ac0 >> ai) & 7
|
ac = (ac0 >> ai) & 7
|
||||||
elif ai == 15:
|
elif ai == 15:
|
||||||
|
@ -175,7 +176,7 @@ def _dxtc_alpha(a0, a1, ac0, ac1, ai):
|
||||||
return alpha
|
return alpha
|
||||||
|
|
||||||
|
|
||||||
def _dxt5(data, width, height):
|
def _dxt5(data: IO[bytes], width: int, height: int) -> bytes:
|
||||||
# TODO implement this function as pixel format in decode.c
|
# TODO implement this function as pixel format in decode.c
|
||||||
ret = bytearray(4 * width * height)
|
ret = bytearray(4 * width * height)
|
||||||
|
|
||||||
|
@ -211,7 +212,7 @@ class DdsImageFile(ImageFile.ImageFile):
|
||||||
format = "DDS"
|
format = "DDS"
|
||||||
format_description = "DirectDraw Surface"
|
format_description = "DirectDraw Surface"
|
||||||
|
|
||||||
def _open(self):
|
def _open(self) -> None:
|
||||||
if not _accept(self.fp.read(4)):
|
if not _accept(self.fp.read(4)):
|
||||||
msg = "not a DDS file"
|
msg = "not a DDS file"
|
||||||
raise SyntaxError(msg)
|
raise SyntaxError(msg)
|
||||||
|
@ -242,19 +243,20 @@ class DdsImageFile(ImageFile.ImageFile):
|
||||||
elif fourcc == b"DXT5":
|
elif fourcc == b"DXT5":
|
||||||
self.decoder = "DXT5"
|
self.decoder = "DXT5"
|
||||||
else:
|
else:
|
||||||
msg = f"Unimplemented pixel format {fourcc}"
|
msg = f"Unimplemented pixel format {repr(fourcc)}"
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
|
||||||
self.tile = [(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]
|
self.tile = [(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]
|
||||||
|
|
||||||
def load_seek(self, pos):
|
def load_seek(self, pos: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DXT1Decoder(ImageFile.PyDecoder):
|
class DXT1Decoder(ImageFile.PyDecoder):
|
||||||
_pulls_fd = True
|
_pulls_fd = True
|
||||||
|
|
||||||
def decode(self, buffer):
|
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||||
|
assert self.fd is not None
|
||||||
try:
|
try:
|
||||||
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
||||||
except struct.error as e:
|
except struct.error as e:
|
||||||
|
@ -266,7 +268,8 @@ class DXT1Decoder(ImageFile.PyDecoder):
|
||||||
class DXT5Decoder(ImageFile.PyDecoder):
|
class DXT5Decoder(ImageFile.PyDecoder):
|
||||||
_pulls_fd = True
|
_pulls_fd = True
|
||||||
|
|
||||||
def decode(self, buffer):
|
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||||
|
assert self.fd is not None
|
||||||
try:
|
try:
|
||||||
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
||||||
except struct.error as e:
|
except struct.error as e:
|
||||||
|
@ -279,7 +282,7 @@ Image.register_decoder("DXT1", DXT1Decoder)
|
||||||
Image.register_decoder("DXT5", DXT5Decoder)
|
Image.register_decoder("DXT5", DXT5Decoder)
|
||||||
|
|
||||||
|
|
||||||
def _accept(prefix):
|
def _accept(prefix: bytes) -> bool:
|
||||||
return prefix[:4] == b"DDS "
|
return prefix[:4] == b"DDS "
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -456,8 +456,11 @@ class IFDRational(Rational):
|
||||||
__int__ = _delegate("__int__")
|
__int__ = _delegate("__int__")
|
||||||
|
|
||||||
|
|
||||||
def _register_loader(idx: int, size: int):
|
_LoaderFunc = Callable[["ImageFileDirectory_v2", bytes, bool], Any]
|
||||||
def decorator(func):
|
|
||||||
|
|
||||||
|
def _register_loader(idx: int, size: int) -> Callable[[_LoaderFunc], _LoaderFunc]:
|
||||||
|
def decorator(func: _LoaderFunc) -> _LoaderFunc:
|
||||||
from .TiffTags import TYPES
|
from .TiffTags import TYPES
|
||||||
|
|
||||||
if func.__name__.startswith("load_"):
|
if func.__name__.startswith("load_"):
|
||||||
|
@ -482,12 +485,13 @@ def _register_basic(idx_fmt_name: tuple[int, str, str]) -> None:
|
||||||
idx, fmt, name = idx_fmt_name
|
idx, fmt, name = idx_fmt_name
|
||||||
TYPES[idx] = name
|
TYPES[idx] = name
|
||||||
size = struct.calcsize(f"={fmt}")
|
size = struct.calcsize(f"={fmt}")
|
||||||
_load_dispatch[idx] = ( # noqa: F821
|
|
||||||
size,
|
def basic_handler(
|
||||||
lambda self, data, legacy_api=True: (
|
self: ImageFileDirectory_v2, data: bytes, legacy_api: bool = True
|
||||||
self._unpack(f"{len(data) // size}{fmt}", data)
|
) -> tuple[Any, ...]:
|
||||||
),
|
return self._unpack(f"{len(data) // size}{fmt}", data)
|
||||||
)
|
|
||||||
|
_load_dispatch[idx] = size, basic_handler # noqa: F821
|
||||||
_write_dispatch[idx] = lambda self, *values: ( # noqa: F821
|
_write_dispatch[idx] = lambda self, *values: ( # noqa: F821
|
||||||
b"".join(self._pack(fmt, value) for value in values)
|
b"".join(self._pack(fmt, value) for value in values)
|
||||||
)
|
)
|
||||||
|
@ -560,7 +564,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_load_dispatch: dict[int, Callable[[ImageFileDirectory_v2, bytes, bool], Any]] = {}
|
_load_dispatch: dict[int, tuple[int, _LoaderFunc]] = {}
|
||||||
_write_dispatch: dict[int, Callable[..., Any]] = {}
|
_write_dispatch: dict[int, Callable[..., Any]] = {}
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -653,10 +657,10 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
def __contains__(self, tag: object) -> bool:
|
def __contains__(self, tag: object) -> bool:
|
||||||
return tag in self._tags_v2 or tag in self._tagdata
|
return tag in self._tags_v2 or tag in self._tagdata
|
||||||
|
|
||||||
def __setitem__(self, tag: int, value) -> None:
|
def __setitem__(self, tag: int, value: Any) -> None:
|
||||||
self._setitem(tag, value, self.legacy_api)
|
self._setitem(tag, value, self.legacy_api)
|
||||||
|
|
||||||
def _setitem(self, tag: int, value, legacy_api: bool) -> None:
|
def _setitem(self, tag: int, value: Any, legacy_api: bool) -> None:
|
||||||
basetypes = (Number, bytes, str)
|
basetypes = (Number, bytes, str)
|
||||||
|
|
||||||
info = TiffTags.lookup(tag, self.group)
|
info = TiffTags.lookup(tag, self.group)
|
||||||
|
@ -744,10 +748,10 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
def __iter__(self) -> Iterator[int]:
|
def __iter__(self) -> Iterator[int]:
|
||||||
return iter(set(self._tagdata) | set(self._tags_v2))
|
return iter(set(self._tagdata) | set(self._tags_v2))
|
||||||
|
|
||||||
def _unpack(self, fmt: str, data: bytes):
|
def _unpack(self, fmt: str, data: bytes) -> tuple[Any, ...]:
|
||||||
return struct.unpack(self._endian + fmt, data)
|
return struct.unpack(self._endian + fmt, data)
|
||||||
|
|
||||||
def _pack(self, fmt: str, *values) -> bytes:
|
def _pack(self, fmt: str, *values: Any) -> bytes:
|
||||||
return struct.pack(self._endian + fmt, *values)
|
return struct.pack(self._endian + fmt, *values)
|
||||||
|
|
||||||
list(
|
list(
|
||||||
|
@ -824,7 +828,9 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@_register_loader(10, 8)
|
@_register_loader(10, 8)
|
||||||
def load_signed_rational(self, data: bytes, legacy_api: bool = True):
|
def load_signed_rational(
|
||||||
|
self, data: bytes, legacy_api: bool = True
|
||||||
|
) -> tuple[tuple[int, int] | IFDRational, ...]:
|
||||||
vals = self._unpack(f"{len(data) // 4}l", data)
|
vals = self._unpack(f"{len(data) // 4}l", data)
|
||||||
|
|
||||||
def combine(a: int, b: int) -> tuple[int, int] | IFDRational:
|
def combine(a: int, b: int) -> tuple[int, int] | IFDRational:
|
||||||
|
@ -1088,7 +1094,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
||||||
def __iter__(self) -> Iterator[int]:
|
def __iter__(self) -> Iterator[int]:
|
||||||
return iter(set(self._tagdata) | set(self._tags_v1))
|
return iter(set(self._tagdata) | set(self._tags_v1))
|
||||||
|
|
||||||
def __setitem__(self, tag: int, value) -> None:
|
def __setitem__(self, tag: int, value: Any) -> None:
|
||||||
for legacy_api in (False, True):
|
for legacy_api in (False, True):
|
||||||
self._setitem(tag, value, legacy_api)
|
self._setitem(tag, value, legacy_api)
|
||||||
|
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -36,4 +36,4 @@ deps =
|
||||||
extras =
|
extras =
|
||||||
typing
|
typing
|
||||||
commands =
|
commands =
|
||||||
mypy src Tests {posargs}
|
mypy docs src winbuild Tests {posargs}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import re
|
||||||
import shutil
|
import shutil
|
||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def cmd_cd(path: str) -> str:
|
def cmd_cd(path: str) -> str:
|
||||||
|
@ -43,21 +44,19 @@ def cmd_nmake(
|
||||||
target: str = "",
|
target: str = "",
|
||||||
params: list[str] | None = None,
|
params: list[str] | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
params = "" if params is None else " ".join(params)
|
|
||||||
|
|
||||||
return " ".join(
|
return " ".join(
|
||||||
[
|
[
|
||||||
"{nmake}",
|
"{nmake}",
|
||||||
"-nologo",
|
"-nologo",
|
||||||
f'-f "{makefile}"' if makefile is not None else "",
|
f'-f "{makefile}"' if makefile is not None else "",
|
||||||
f"{params}",
|
f'{" ".join(params)}' if params is not None else "",
|
||||||
f'"{target}"',
|
f'"{target}"',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def cmds_cmake(
|
def cmds_cmake(
|
||||||
target: str | tuple[str, ...] | list[str], *params, build_dir: str = "."
|
target: str | tuple[str, ...] | list[str], *params: str, build_dir: str = "."
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
if not isinstance(target, str):
|
if not isinstance(target, str):
|
||||||
target = " ".join(target)
|
target = " ".join(target)
|
||||||
|
@ -129,7 +128,7 @@ V["ZLIB_DOTLESS"] = V["ZLIB"].replace(".", "")
|
||||||
|
|
||||||
|
|
||||||
# dependencies, listed in order of compilation
|
# dependencies, listed in order of compilation
|
||||||
DEPS = {
|
DEPS: dict[str, dict[str, Any]] = {
|
||||||
"libjpeg": {
|
"libjpeg": {
|
||||||
"url": f"{SF_PROJECTS}/libjpeg-turbo/files/{V['JPEGTURBO']}/"
|
"url": f"{SF_PROJECTS}/libjpeg-turbo/files/{V['JPEGTURBO']}/"
|
||||||
f"libjpeg-turbo-{V['JPEGTURBO']}.tar.gz/download",
|
f"libjpeg-turbo-{V['JPEGTURBO']}.tar.gz/download",
|
||||||
|
@ -538,7 +537,7 @@ def write_script(
|
||||||
print(" " + line)
|
print(" " + line)
|
||||||
|
|
||||||
|
|
||||||
def get_footer(dep: dict) -> list[str]:
|
def get_footer(dep: dict[str, Any]) -> list[str]:
|
||||||
lines = []
|
lines = []
|
||||||
for out in dep.get("headers", []):
|
for out in dep.get("headers", []):
|
||||||
lines.append(cmd_copy(out, "{inc_dir}"))
|
lines.append(cmd_copy(out, "{inc_dir}"))
|
||||||
|
@ -583,6 +582,7 @@ def build_dep(name: str, prefs: dict[str, str], verbose: bool) -> str:
|
||||||
license_text += f.read()
|
license_text += f.read()
|
||||||
if "license_pattern" in dep:
|
if "license_pattern" in dep:
|
||||||
match = re.search(dep["license_pattern"], license_text, re.DOTALL)
|
match = re.search(dep["license_pattern"], license_text, re.DOTALL)
|
||||||
|
assert match is not None
|
||||||
license_text = "\n".join(match.groups())
|
license_text = "\n".join(match.groups())
|
||||||
assert len(license_text) > 50
|
assert len(license_text) > 50
|
||||||
with open(os.path.join(license_dir, f"{directory}.txt"), "w") as f:
|
with open(os.path.join(license_dir, f"{directory}.txt"), "w") as f:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user