Merge remote-tracking branch 'radarhere/type-annotations' into type-annotations

This commit is contained in:
Andrew Murray 2024-06-06 12:11:53 +10:00
commit f3ec2770e6
6 changed files with 75 additions and 58 deletions

View File

@ -506,7 +506,7 @@ def _getscaleoffset(expr):
class SupportsGetData(Protocol):
def getdata(
self,
) -> tuple[Transform, Sequence[Any]]: ...
) -> tuple[Transform, Sequence[int]]: ...
class Image:
@ -1295,7 +1295,7 @@ class Image:
return im.crop((x0, y0, x1, y1))
def draft(
self, mode: str, size: tuple[int, int]
self, mode: str | None, size: tuple[int, int]
) -> tuple[str, tuple[int, int, float, float]] | None:
"""
Configures the image file loader so it returns a version of the
@ -1719,7 +1719,7 @@ class Image:
def paste(
self,
im: Image | str | int | tuple[int, ...],
im: Image | str | float | tuple[int, ...],
box: tuple[int, int, int, int] | tuple[int, int] | None = None,
mask: Image | None = None,
) -> None:
@ -1750,7 +1750,7 @@ class Image:
See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
combine images with respect to their alpha channels.
:param im: Source image or pixel value (integer or tuple).
:param im: Source image or pixel value (integer, float or tuple).
:param box: An optional 4-tuple giving the region to paste into.
If a 2-tuple is used instead, it's treated as the upper left
corner. If omitted or None, the source is pasted into the
@ -2228,13 +2228,9 @@ class Image:
msg = "reducing_gap must be 1.0 or greater"
raise ValueError(msg)
size = cast("tuple[int, int]", tuple(size))
self.load()
if box is None:
box = (0, 0) + self.size
else:
box = cast("tuple[float, float, float, float]", tuple(box))
if self.size == size and box == (0, 0) + self.size:
return self.copy()
@ -2291,8 +2287,6 @@ class Image:
if box is None:
box = (0, 0) + self.size
else:
box = cast("tuple[int, int, int, int]", tuple(box))
if factor == (1, 1) and box == (0, 0) + self.size:
return self.copy()
@ -2692,7 +2686,9 @@ class Image:
return
size = preserved_size
res = self.draft(None, (size[0] * reducing_gap, size[1] * reducing_gap)) # type: ignore[arg-type]
res = self.draft(
None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
)
if res is not None:
box = res[1]
if box is None:
@ -2799,7 +2795,7 @@ class Image:
im.info = self.info.copy()
if method == Transform.MESH:
# list of quads
for box, quad in cast("Sequence[tuple[float, float]]", data):
for box, quad in data:
im.__transformer(
box, self, Transform.QUAD, quad, resample, fillcolor is None
)
@ -2957,7 +2953,7 @@ class ImageTransformHandler:
self,
size: tuple[int, int],
image: Image,
**options: dict[str, str | int | tuple[int, ...] | list[int]] | int,
**options: str | int | tuple[int, ...] | list[int],
) -> Image:
pass

View File

@ -456,14 +456,12 @@ class ImageDraw:
self.draw.draw_rectangle(right, ink, 1)
def _multiline_check(self, text: AnyStr) -> bool:
split_character = cast(AnyStr, "\n" if isinstance(text, str) else b"\n")
split_character = "\n" if isinstance(text, str) else b"\n"
return split_character in text
def _multiline_split(self, text: AnyStr) -> list[AnyStr]:
split_character = cast(AnyStr, "\n" if isinstance(text, str) else b"\n")
return text.split(split_character)
return text.split("\n" if isinstance(text, str) else b"\n")
def _multiline_spacing(self, font, spacing, stroke_width):
return (
@ -477,7 +475,12 @@ class ImageDraw:
xy: tuple[float, float],
text: str,
fill=None,
font: ImageFont.FreeTypeFont | ImageFont.ImageFont | None = None,
font: (
ImageFont.ImageFont
| ImageFont.FreeTypeFont
| ImageFont.TransposedFont
| None
) = None,
anchor=None,
spacing=4,
align="left",
@ -597,9 +600,14 @@ class ImageDraw:
def multiline_text(
self,
xy: tuple[float, float],
text,
text: str,
fill=None,
font=None,
font: (
ImageFont.ImageFont
| ImageFont.FreeTypeFont
| ImageFont.TransposedFont
| None
) = None,
anchor=None,
spacing=4,
align="left",
@ -684,7 +692,12 @@ class ImageDraw:
def textlength(
self,
text: str,
font: ImageFont.FreeTypeFont | ImageFont.ImageFont | None = None,
font: (
ImageFont.ImageFont
| ImageFont.FreeTypeFont
| ImageFont.TransposedFont
| None
) = None,
direction=None,
features=None,
language=None,

View File

@ -33,11 +33,11 @@ import sys
import warnings
from enum import IntEnum
from io import BytesIO
from typing import TYPE_CHECKING, BinaryIO
from typing import IO, TYPE_CHECKING, Any, BinaryIO
from . import Image
from ._typing import StrOrBytesPath
from ._util import is_directory, is_path
from ._util import is_path
if TYPE_CHECKING:
from . import ImageFile
@ -61,7 +61,7 @@ except ImportError as ex:
core = DeferredError.new(ex)
def _string_length_check(text: str) -> None:
def _string_length_check(text: str | bytes | bytearray) -> None:
if MAX_STRING_LENGTH is not None and len(text) > MAX_STRING_LENGTH:
msg = "too many characters in string"
raise ValueError(msg)
@ -113,7 +113,7 @@ class ImageFont:
self._load_pilfont_data(fp, image)
image.close()
def _load_pilfont_data(self, file, image):
def _load_pilfont_data(self, file: IO[bytes], image: Image.Image) -> None:
# read PILfont header
if file.readline() != b"PILfont\n":
msg = "Not a PILfont file"
@ -161,7 +161,7 @@ class ImageFont:
return self.font.getmask(text, mode)
def getbbox(
self, text: str, *args: object, **kwargs: object
self, text: str | bytes | bytearray, *args: Any, **kwargs: Any
) -> tuple[int, int, int, int]:
"""
Returns bounding box (in pixels) of given text.
@ -180,7 +180,9 @@ class ImageFont:
width, height = self.font.getsize(text)
return 0, 0, width, height
def getlength(self, text: str, *args: object, **kwargs: object) -> int:
def getlength(
self, text: str | bytes | bytearray, *args: Any, **kwargs: Any
) -> int:
"""
Returns length (in pixels) of given text.
This is the amount by which following text should be offset.
@ -357,13 +359,13 @@ class FreeTypeFont:
def getbbox(
self,
text: str,
mode="",
direction=None,
features=None,
language=None,
stroke_width=0,
anchor=None,
) -> tuple[int, int, int, int]:
mode: str = "",
direction: str | None = None,
features: str | None = None,
language: str | None = None,
stroke_width: float = 0,
anchor: str | None = None,
) -> tuple[float, float, float, float]:
"""
Returns bounding box (in pixels) of given text relative to given anchor
when rendered in font with provided direction, features, and language.
@ -513,7 +515,7 @@ class FreeTypeFont:
def getmask2(
self,
text,
text: str,
mode="",
direction=None,
features=None,
@ -641,7 +643,7 @@ class FreeTypeFont:
layout_engine=layout_engine or self.layout_engine,
)
def get_variation_names(self):
def get_variation_names(self) -> list[bytes]:
"""
:returns: A list of the named styles in a variation font.
:exception OSError: If the font is not a variation font.
@ -683,10 +685,11 @@ class FreeTypeFont:
msg = "FreeType 2.9.1 or greater is required"
raise NotImplementedError(msg) from e
for axis in axes:
axis["name"] = axis["name"].replace(b"\x00", b"")
if axis["name"]:
axis["name"] = axis["name"].replace(b"\x00", b"")
return axes
def set_variation_by_axes(self, axes):
def set_variation_by_axes(self, axes: list[float]) -> None:
"""
:param axes: A list of values for each axis.
:exception OSError: If the font is not a variation font.
@ -731,7 +734,7 @@ class TransposedFont:
return 0, 0, height, width
return 0, 0, width, height
def getlength(self, text, *args, **kwargs):
def getlength(self, text: str, *args, **kwargs) -> float:
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270):
msg = "text length is undefined for text rotated by 90 or 270 degrees"
raise ValueError(msg)
@ -878,15 +881,13 @@ def load_path(filename: str | bytes) -> ImageFont:
:return: A font object.
:exception OSError: If the file could not be read.
"""
if not isinstance(filename, str):
filename = filename.decode("utf-8")
for directory in sys.path:
if is_directory(directory):
assert isinstance(directory, str)
if not isinstance(filename, str):
filename = filename.decode("utf-8")
try:
return load(os.path.join(directory, filename))
except OSError:
pass
try:
return load(os.path.join(directory, filename))
except OSError:
pass
msg = "cannot find font file"
raise OSError(msg)

View File

@ -425,7 +425,7 @@ class JpegImageFile(ImageFile.ImageFile):
return s
def draft(
self, mode: str, size: tuple[int, int]
self, mode: str | None, size: tuple[int, int]
) -> tuple[str, tuple[int, int, float, float]] | None:
if len(self.tile) != 1:
return None

View File

@ -1,7 +1,5 @@
from typing import Any
from typing_extensions import Buffer
class ImagingCore:
def __getattr__(self, name: str) -> Any: ...
@ -14,5 +12,5 @@ class ImagingDraw:
class PixelAccess:
def __getattr__(self, name: str) -> Any: ...
def font(image, glyphdata: Buffer) -> ImagingFont: ...
def font(image, glyphdata: bytes) -> ImagingFont: ...
def __getattr__(name: str) -> Any: ...

View File

@ -1,5 +1,7 @@
from typing import Any, TypedDict
from . import _imaging
class _Axis(TypedDict):
minimum: int | None
default: int | None
@ -37,21 +39,28 @@ class Font:
x_start=...,
y_start=...,
/,
) -> tuple[Any, tuple[int, int]]: ...
) -> tuple[_imaging.ImagingCore, tuple[int, int]]: ...
def getsize(
self, string: str, mode=..., dir=..., features=..., lang=..., anchor=..., /
self,
string: str | bytes | bytearray,
mode=...,
dir=...,
features=...,
lang=...,
anchor=...,
/,
) -> tuple[tuple[int, int], tuple[int, int]]: ...
def getlength(
self, string: str, mode=..., dir=..., features=..., lang=..., /
) -> int: ...
def getvarnames(self) -> list[str]: ...
def getvaraxes(self) -> list[_Axis]: ...
) -> float: ...
def getvarnames(self) -> list[bytes]: ...
def getvaraxes(self) -> list[_Axis] | None: ...
def setvarname(self, instance_index: int, /) -> None: ...
def setvaraxes(self, axes: list[float], /) -> None: ...
def getfont(
filename: str | bytes | bytearray,
size,
filename: str | bytes,
size: float,
index=...,
encoding=...,
font_bytes=...,