Skip to content

Commit 726cdf5

Browse files
committed
Added type hints
1 parent 6dd4b3c commit 726cdf5

File tree

10 files changed

+223
-158
lines changed

10 files changed

+223
-158
lines changed

Tests/test_font_pcf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
from pathlib import Path
5+
from typing import AnyStr
56

67
import pytest
78

@@ -92,7 +93,7 @@ def test_textsize(request: pytest.FixtureRequest, tmp_path: Path) -> None:
9293

9394

9495
def _test_high_characters(
95-
request: pytest.FixtureRequest, tmp_path: Path, message: str | bytes
96+
request: pytest.FixtureRequest, tmp_path: Path, message: AnyStr
9697
) -> None:
9798
tempname = save_font(request, tmp_path)
9899
font = ImageFont.load(tempname)

Tests/test_imagefont.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,14 +717,14 @@ def test_variation_set_by_name(font: ImageFont.FreeTypeFont) -> None:
717717

718718
font = ImageFont.truetype("Tests/fonts/AdobeVFPrototype.ttf", 36)
719719
_check_text(font, "Tests/images/variation_adobe.png", 11)
720-
for name in ["Bold", b"Bold"]:
720+
for name in ("Bold", b"Bold"):
721721
font.set_variation_by_name(name)
722722
assert font.getname()[1] == "Bold"
723723
_check_text(font, "Tests/images/variation_adobe_name.png", 16)
724724

725725
font = ImageFont.truetype("Tests/fonts/TINY5x3GX.ttf", 36)
726726
_check_text(font, "Tests/images/variation_tiny.png", 40)
727-
for name in ["200", b"200"]:
727+
for name in ("200", b"200"):
728728
font.set_variation_by_name(name)
729729
assert font.getname()[1] == "200"
730730
_check_text(font, "Tests/images/variation_tiny_name.png", 40)

docs/reference/ImageFont.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,11 @@ Constants
9191
Set to 1,000,000, to protect against potential DOS attacks. Pillow will
9292
raise a :py:exc:`ValueError` if the number of characters is over this limit. The
9393
check can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.
94+
95+
Dictionaries
96+
------------
97+
98+
.. autoclass:: Axis
99+
:members:
100+
:undoc-members:
101+
:show-inheritance:

docs/reference/internal_modules.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,7 @@ on some Python versions.
7878

7979
An internal interface module previously known as :mod:`~PIL._imaging`,
8080
implemented in :file:`_imaging.c`.
81+
82+
.. py:class:: ImagingCore
83+
84+
A representation of the image data.

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,4 @@ exclude = [
159159
'^Tests/oss-fuzz/fuzz_font.py$',
160160
'^Tests/oss-fuzz/fuzz_pillow.py$',
161161
'^Tests/test_qt_image_qapplication.py$',
162-
'^Tests/test_font_pcf_charsets.py$',
163-
'^Tests/test_font_pcf.py$',
164162
]

src/PIL/Image.py

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ class Quantize(IntEnum):
218218
# Registries
219219

220220
if TYPE_CHECKING:
221+
from xml.etree.ElementTree import Element
222+
221223
from . import ImageFile, ImagePalette
222224
from ._typing import NumpyArray, StrOrBytesPath, TypeGuard
223225
ID: list[str] = []
@@ -241,9 +243,9 @@ class Quantize(IntEnum):
241243
_ENDIAN = "<" if sys.byteorder == "little" else ">"
242244

243245

244-
def _conv_type_shape(im):
246+
def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]:
245247
m = ImageMode.getmode(im.mode)
246-
shape = (im.height, im.width)
248+
shape: tuple[int, ...] = (im.height, im.width)
247249
extra = len(m.bands)
248250
if extra != 1:
249251
shape += (extra,)
@@ -470,10 +472,10 @@ def __init__(self, scale, offset) -> None:
470472
self.scale = scale
471473
self.offset = offset
472474

473-
def __neg__(self):
475+
def __neg__(self) -> _E:
474476
return _E(-self.scale, -self.offset)
475477

476-
def __add__(self, other):
478+
def __add__(self, other) -> _E:
477479
if isinstance(other, _E):
478480
return _E(self.scale + other.scale, self.offset + other.offset)
479481
return _E(self.scale, self.offset + other)
@@ -486,14 +488,14 @@ def __sub__(self, other):
486488
def __rsub__(self, other):
487489
return other + -self
488490

489-
def __mul__(self, other):
491+
def __mul__(self, other) -> _E:
490492
if isinstance(other, _E):
491493
return NotImplemented
492494
return _E(self.scale * other, self.offset * other)
493495

494496
__rmul__ = __mul__
495497

496-
def __truediv__(self, other):
498+
def __truediv__(self, other) -> _E:
497499
if isinstance(other, _E):
498500
return NotImplemented
499501
return _E(self.scale / other, self.offset / other)
@@ -718,9 +720,9 @@ def _repr_jpeg_(self) -> bytes | None:
718720
return self._repr_image("JPEG")
719721

720722
@property
721-
def __array_interface__(self):
723+
def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]:
722724
# numpy array interface support
723-
new = {"version": 3}
725+
new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3}
724726
try:
725727
if self.mode == "1":
726728
# Binary images need to be extended from bits to bytes
@@ -1418,7 +1420,7 @@ def getcolors(
14181420
return out
14191421
return self.im.getcolors(maxcolors)
14201422

1421-
def getdata(self, band: int | None = None):
1423+
def getdata(self, band: int | None = None) -> core.ImagingCore:
14221424
"""
14231425
Returns the contents of this image as a sequence object
14241426
containing pixel values. The sequence object is flattened, so
@@ -1467,8 +1469,8 @@ def getxmp(self) -> dict[str, Any]:
14671469
def get_name(tag: str) -> str:
14681470
return re.sub("^{[^}]+}", "", tag)
14691471

1470-
def get_value(element):
1471-
value = {get_name(k): v for k, v in element.attrib.items()}
1472+
def get_value(element: Element) -> str | dict[str, Any] | None:
1473+
value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()}
14721474
children = list(element)
14731475
if children:
14741476
for child in children:
@@ -1712,7 +1714,7 @@ def histogram(self, mask: Image | None = None, extrema=None) -> list[int]:
17121714
return self.im.histogram(extrema)
17131715
return self.im.histogram()
17141716

1715-
def entropy(self, mask=None, extrema=None):
1717+
def entropy(self, mask: Image | None = None, extrema=None):
17161718
"""
17171719
Calculates and returns the entropy for the image.
17181720
@@ -1996,7 +1998,7 @@ def putalpha(self, alpha: Image | int) -> None:
19961998

19971999
def putdata(
19982000
self,
1999-
data: Sequence[float] | Sequence[Sequence[int]] | NumpyArray,
2001+
data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray,
20002002
scale: float = 1.0,
20012003
offset: float = 0.0,
20022004
) -> None:
@@ -2184,7 +2186,12 @@ def remap_palette(
21842186

21852187
return m_im
21862188

2187-
def _get_safe_box(self, size, resample, box):
2189+
def _get_safe_box(
2190+
self,
2191+
size: tuple[int, int],
2192+
resample: Resampling,
2193+
box: tuple[float, float, float, float],
2194+
) -> tuple[int, int, int, int]:
21882195
"""Expands the box so it includes adjacent pixels
21892196
that may be used by resampling with the given resampling filter.
21902197
"""
@@ -2294,7 +2301,7 @@ def resize(
22942301
factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1
22952302
factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1
22962303
if factor_x > 1 or factor_y > 1:
2297-
reduce_box = self._get_safe_box(size, resample, box)
2304+
reduce_box = self._get_safe_box(size, cast(Resampling, resample), box)
22982305
factor = (factor_x, factor_y)
22992306
self = (
23002307
self.reduce(factor, box=reduce_box)
@@ -2430,7 +2437,7 @@ def rotate(
24302437
0.0,
24312438
]
24322439

2433-
def transform(x, y, matrix):
2440+
def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]:
24342441
(a, b, c, d, e, f) = matrix
24352442
return a * x + b * y + c, d * x + e * y + f
24362443

@@ -2445,9 +2452,9 @@ def transform(x, y, matrix):
24452452
xx = []
24462453
yy = []
24472454
for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
2448-
x, y = transform(x, y, matrix)
2449-
xx.append(x)
2450-
yy.append(y)
2455+
transformed_x, transformed_y = transform(x, y, matrix)
2456+
xx.append(transformed_x)
2457+
yy.append(transformed_y)
24512458
nw = math.ceil(max(xx)) - math.floor(min(xx))
24522459
nh = math.ceil(max(yy)) - math.floor(min(yy))
24532460

@@ -2705,7 +2712,7 @@ def thumbnail(
27052712
provided_size = tuple(map(math.floor, size))
27062713

27072714
def preserve_aspect_ratio() -> tuple[int, int] | None:
2708-
def round_aspect(number, key):
2715+
def round_aspect(number: float, key: Callable[[int], float]) -> int:
27092716
return max(min(math.floor(number), math.ceil(number), key=key), 1)
27102717

27112718
x, y = provided_size
@@ -2849,7 +2856,13 @@ def getdata(self):
28492856
return im
28502857

28512858
def __transformer(
2852-
self, box, image, method, data, resample=Resampling.NEAREST, fill=1
2859+
self,
2860+
box: tuple[int, int, int, int],
2861+
image: Image,
2862+
method,
2863+
data,
2864+
resample: int = Resampling.NEAREST,
2865+
fill: bool = True,
28532866
):
28542867
w = box[2] - box[0]
28552868
h = box[3] - box[1]
@@ -2899,11 +2912,12 @@ def __transformer(
28992912
Resampling.BICUBIC,
29002913
):
29012914
if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS):
2902-
msg = {
2915+
unusable: dict[int, str] = {
29032916
Resampling.BOX: "Image.Resampling.BOX",
29042917
Resampling.HAMMING: "Image.Resampling.HAMMING",
29052918
Resampling.LANCZOS: "Image.Resampling.LANCZOS",
2906-
}[resample] + f" ({resample}) cannot be used."
2919+
}
2920+
msg = unusable[resample] + f" ({resample}) cannot be used."
29072921
else:
29082922
msg = f"Unknown resampling filter ({resample})."
29092923

@@ -3843,7 +3857,7 @@ class Exif(_ExifBase):
38433857
print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99
38443858
"""
38453859

3846-
endian = None
3860+
endian: str | None = None
38473861
bigtiff = False
38483862
_loaded = False
38493863

@@ -3892,7 +3906,7 @@ def _get_head(self) -> bytes:
38923906
head += b"\x00\x00\x00\x00"
38933907
return head
38943908

3895-
def load(self, data):
3909+
def load(self, data: bytes) -> None:
38963910
# Extract EXIF information. This is highly experimental,
38973911
# and is likely to be replaced with something better in a future
38983912
# version.
@@ -3911,7 +3925,7 @@ def load(self, data):
39113925
self._info = None
39123926
return
39133927

3914-
self.fp = io.BytesIO(data)
3928+
self.fp: IO[bytes] = io.BytesIO(data)
39153929
self.head = self.fp.read(8)
39163930
# process dictionary
39173931
from . import TiffImagePlugin
@@ -3921,7 +3935,7 @@ def load(self, data):
39213935
self.fp.seek(self._info.next)
39223936
self._info.load(self.fp)
39233937

3924-
def load_from_fp(self, fp, offset=None):
3938+
def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None:
39253939
self._loaded_exif = None
39263940
self._data.clear()
39273941
self._hidden_data.clear()

0 commit comments

Comments
 (0)