Skip to content

Commit cdecb3d

Browse files
authored
Merge pull request #7793 from radarhere/type_hints_test_image
Added remaining type hints to Tests/test_image_*.py
2 parents 5d6f22d + ea0240b commit cdecb3d

15 files changed

Lines changed: 124 additions & 73 deletions

Tests/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def fromstring(data: bytes) -> Image.Image:
244244
return Image.open(BytesIO(data))
245245

246246

247-
def tostring(im: Image.Image, string_format: str, **options: dict[str, Any]) -> bytes:
247+
def tostring(im: Image.Image, string_format: str, **options: Any) -> bytes:
248248
out = BytesIO()
249249
im.save(out, string_format, **options)
250250
return out.getvalue()

Tests/test_image_access.py

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import subprocess
55
import sys
66
import sysconfig
7+
from types import ModuleType
78

89
import pytest
910

@@ -23,6 +24,7 @@
2324
except ImportError:
2425
cffi = None
2526

27+
numpy: ModuleType | None
2628
try:
2729
import numpy
2830
except ImportError:
@@ -71,9 +73,10 @@ def test_sanity(self) -> None:
7173
pix1 = im1.load()
7274
pix2 = im2.load()
7375

74-
for x, y in ((0, "0"), ("0", 0)):
75-
with pytest.raises(TypeError):
76-
pix1[x, y]
76+
with pytest.raises(TypeError):
77+
pix1[0, "0"]
78+
with pytest.raises(TypeError):
79+
pix1["0", 0]
7780

7881
for y in range(im1.size[1]):
7982
for x in range(im1.size[0]):
@@ -123,12 +126,13 @@ def test_numpy(self) -> None:
123126
im = hopper()
124127
pix = im.load()
125128

129+
assert numpy is not None
126130
assert pix[numpy.int32(1), numpy.int32(2)] == (18, 20, 59)
127131

128132

129133
class TestImageGetPixel(AccessTest):
130134
@staticmethod
131-
def color(mode):
135+
def color(mode: str) -> int | tuple[int, ...]:
132136
bands = Image.getmodebands(mode)
133137
if bands == 1:
134138
return 1
@@ -138,12 +142,13 @@ def color(mode):
138142
return (16, 32, 49)
139143
return tuple(range(1, bands + 1))
140144

141-
def check(self, mode, expected_color=None) -> None:
145+
def check(self, mode: str, expected_color_int: int | None = None) -> None:
142146
if self._need_cffi_access and mode.startswith("BGR;"):
143147
pytest.skip("Support not added to deprecated module for BGR;* modes")
144148

145-
if not expected_color:
146-
expected_color = self.color(mode)
149+
expected_color = (
150+
self.color(mode) if expected_color_int is None else expected_color_int
151+
)
147152

148153
# check putpixel
149154
im = Image.new(mode, (1, 1), None)
@@ -222,7 +227,7 @@ def check(self, mode, expected_color=None) -> None:
222227
"YCbCr",
223228
),
224229
)
225-
def test_basic(self, mode) -> None:
230+
def test_basic(self, mode: str) -> None:
226231
self.check(mode)
227232

228233
def test_list(self) -> None:
@@ -231,14 +236,14 @@ def test_list(self) -> None:
231236

232237
@pytest.mark.parametrize("mode", ("I;16", "I;16B"))
233238
@pytest.mark.parametrize("expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1))
234-
def test_signedness(self, mode, expected_color) -> None:
239+
def test_signedness(self, mode: str, expected_color: int) -> None:
235240
# see https://github.com/python-pillow/Pillow/issues/452
236241
# pixelaccess is using signed int* instead of uint*
237242
self.check(mode, expected_color)
238243

239244
@pytest.mark.parametrize("mode", ("P", "PA"))
240245
@pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))
241-
def test_p_putpixel_rgb_rgba(self, mode, color) -> None:
246+
def test_p_putpixel_rgb_rgba(self, mode: str, color: tuple[int, ...]) -> None:
242247
im = Image.new(mode, (1, 1))
243248
im.putpixel((0, 0), color)
244249

@@ -262,7 +267,7 @@ class TestCffiGetPixel(TestImageGetPixel):
262267
class TestCffi(AccessTest):
263268
_need_cffi_access = True
264269

265-
def _test_get_access(self, im) -> None:
270+
def _test_get_access(self, im: Image.Image) -> None:
266271
"""Do we get the same thing as the old pixel access
267272
268273
Using private interfaces, forcing a capi access and
@@ -299,7 +304,7 @@ def test_get_vs_c(self) -> None:
299304
# im = Image.new('I;32B', (10, 10), 2**10)
300305
# self._test_get_access(im)
301306

302-
def _test_set_access(self, im, color) -> None:
307+
def _test_set_access(self, im: Image.Image, color: tuple[int, ...] | float) -> None:
303308
"""Are we writing the correct bits into the image?
304309
305310
Using private interfaces, forcing a capi access and
@@ -359,7 +364,7 @@ def test_reference_counting(self) -> None:
359364
assert px[i, 0] == 0
360365

361366
@pytest.mark.parametrize("mode", ("P", "PA"))
362-
def test_p_putpixel_rgb_rgba(self, mode) -> None:
367+
def test_p_putpixel_rgb_rgba(self, mode: str) -> None:
363368
for color in ((255, 0, 0), (255, 0, 0, 127 if mode == "PA" else 255)):
364369
im = Image.new(mode, (1, 1))
365370
with pytest.warns(DeprecationWarning):
@@ -377,7 +382,7 @@ class TestImagePutPixelError(AccessTest):
377382
INVALID_TYPES = ["foo", 1.0, None]
378383

379384
@pytest.mark.parametrize("mode", IMAGE_MODES1)
380-
def test_putpixel_type_error1(self, mode) -> None:
385+
def test_putpixel_type_error1(self, mode: str) -> None:
381386
im = hopper(mode)
382387
for v in self.INVALID_TYPES:
383388
with pytest.raises(TypeError, match="color must be int or tuple"):
@@ -400,14 +405,16 @@ def test_putpixel_type_error1(self, mode) -> None:
400405
),
401406
),
402407
)
403-
def test_putpixel_invalid_number_of_bands(self, mode, band_numbers, match) -> None:
408+
def test_putpixel_invalid_number_of_bands(
409+
self, mode: str, band_numbers: tuple[int, ...], match: str
410+
) -> None:
404411
im = hopper(mode)
405412
for band_number in band_numbers:
406413
with pytest.raises(TypeError, match=match):
407414
im.putpixel((0, 0), (0,) * band_number)
408415

409416
@pytest.mark.parametrize("mode", IMAGE_MODES2)
410-
def test_putpixel_type_error2(self, mode) -> None:
417+
def test_putpixel_type_error2(self, mode: str) -> None:
411418
im = hopper(mode)
412419
for v in self.INVALID_TYPES:
413420
with pytest.raises(
@@ -416,7 +423,7 @@ def test_putpixel_type_error2(self, mode) -> None:
416423
im.putpixel((0, 0), v)
417424

418425
@pytest.mark.parametrize("mode", IMAGE_MODES1 + IMAGE_MODES2)
419-
def test_putpixel_overflow_error(self, mode) -> None:
426+
def test_putpixel_overflow_error(self, mode: str) -> None:
420427
im = hopper(mode)
421428
with pytest.raises(OverflowError):
422429
im.putpixel((0, 0), 2**80)
@@ -428,7 +435,7 @@ class TestEmbeddable:
428435
def test_embeddable(self) -> None:
429436
import ctypes
430437

431-
from setuptools.command.build_ext import new_compiler
438+
from setuptools.command import build_ext
432439

433440
with open("embed_pil.c", "w", encoding="utf-8") as fh:
434441
fh.write(
@@ -457,7 +464,7 @@ def test_embeddable(self) -> None:
457464
% sys.prefix.replace("\\", "\\\\")
458465
)
459466

460-
compiler = new_compiler()
467+
compiler = getattr(build_ext, "new_compiler")()
461468
compiler.add_include_dir(sysconfig.get_config_var("INCLUDEPY"))
462469

463470
libdir = sysconfig.get_config_var("LIBDIR") or sysconfig.get_config_var(
@@ -471,7 +478,7 @@ def test_embeddable(self) -> None:
471478
env["PATH"] = sys.prefix + ";" + env["PATH"]
472479

473480
# do not display the Windows Error Reporting dialog
474-
ctypes.windll.kernel32.SetErrorMode(0x0002)
481+
getattr(ctypes, "windll").kernel32.SetErrorMode(0x0002)
475482

476483
process = subprocess.Popen(["embed_pil.exe"], env=env)
477484
process.communicate()

Tests/test_image_array.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from typing import Any
4+
35
import pytest
46
from packaging.version import parse as parse_version
57

@@ -13,7 +15,7 @@
1315

1416

1517
def test_toarray() -> None:
16-
def test(mode):
18+
def test(mode: str) -> tuple[tuple[int, ...], str, int]:
1719
ai = numpy.array(im.convert(mode))
1820
return ai.shape, ai.dtype.str, ai.nbytes
1921

@@ -50,14 +52,14 @@ def test_fromarray() -> None:
5052
class Wrapper:
5153
"""Class with API matching Image.fromarray"""
5254

53-
def __init__(self, img, arr_params) -> None:
55+
def __init__(self, img: Image.Image, arr_params: dict[str, Any]) -> None:
5456
self.img = img
5557
self.__array_interface__ = arr_params
5658

57-
def tobytes(self):
59+
def tobytes(self) -> bytes:
5860
return self.img.tobytes()
5961

60-
def test(mode):
62+
def test(mode: str) -> tuple[str, tuple[int, int], bool]:
6163
i = im.convert(mode)
6264
a = numpy.array(i)
6365
# Make wrapper instance for image, new array interface

Tests/test_image_draft.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
pytestmark = skip_unless_feature("jpg")
88

99

10-
def draft_roundtrip(in_mode, in_size, req_mode, req_size):
10+
def draft_roundtrip(
11+
in_mode: str,
12+
in_size: tuple[int, int],
13+
req_mode: str | None,
14+
req_size: tuple[int, int] | None,
15+
) -> Image.Image:
1116
im = Image.new(in_mode, in_size)
1217
data = tostring(im, "JPEG")
1318
im = fromstring(data)

Tests/test_image_entropy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
def test_entropy() -> None:
7-
def entropy(mode):
7+
def entropy(mode: str) -> float:
88
return hopper(mode).entropy()
99

1010
assert round(abs(entropy("1") - 0.9138803254693582), 7) == 0

Tests/test_image_filter.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
),
3737
)
3838
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
39-
def test_sanity(filter_to_apply, mode) -> None:
39+
def test_sanity(filter_to_apply: ImageFilter.Filter, mode: str) -> None:
4040
im = hopper(mode)
4141
if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter):
4242
out = im.filter(filter_to_apply)
@@ -45,15 +45,15 @@ def test_sanity(filter_to_apply, mode) -> None:
4545

4646

4747
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
48-
def test_sanity_error(mode) -> None:
48+
def test_sanity_error(mode: str) -> None:
4949
with pytest.raises(TypeError):
5050
im = hopper(mode)
5151
im.filter("hello")
5252

5353

5454
# crashes on small images
5555
@pytest.mark.parametrize("size", ((1, 1), (2, 2), (3, 3)))
56-
def test_crash(size) -> None:
56+
def test_crash(size: tuple[int, int]) -> None:
5757
im = Image.new("RGB", size)
5858
im.filter(ImageFilter.SMOOTH)
5959

@@ -67,7 +67,10 @@ def test_crash(size) -> None:
6767
("RGB", ((4, 0, 0), (0, 0, 0))),
6868
),
6969
)
70-
def test_modefilter(mode, expected) -> None:
70+
def test_modefilter(
71+
mode: str,
72+
expected: tuple[int, int] | tuple[tuple[int, int, int], tuple[int, int, int]],
73+
) -> None:
7174
im = Image.new(mode, (3, 3), None)
7275
im.putdata(list(range(9)))
7376
# image is:
@@ -90,7 +93,13 @@ def test_modefilter(mode, expected) -> None:
9093
("F", (0.0, 4.0, 8.0)),
9194
),
9295
)
93-
def test_rankfilter(mode, expected) -> None:
96+
def test_rankfilter(
97+
mode: str,
98+
expected: (
99+
tuple[float, float, float]
100+
| tuple[tuple[int, int, int], tuple[int, int, int], tuple[int, int, int]]
101+
),
102+
) -> None:
94103
im = Image.new(mode, (3, 3), None)
95104
im.putdata(list(range(9)))
96105
# image is:
@@ -106,7 +115,7 @@ def test_rankfilter(mode, expected) -> None:
106115
@pytest.mark.parametrize(
107116
"filter", (ImageFilter.MinFilter, ImageFilter.MedianFilter, ImageFilter.MaxFilter)
108117
)
109-
def test_rankfilter_error(filter) -> None:
118+
def test_rankfilter_error(filter: ImageFilter.RankFilter) -> None:
110119
with pytest.raises(ValueError):
111120
im = Image.new("P", (3, 3), None)
112121
im.putdata(list(range(9)))
@@ -137,7 +146,7 @@ def test_kernel_not_enough_coefficients() -> None:
137146

138147

139148
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
140-
def test_consistency_3x3(mode) -> None:
149+
def test_consistency_3x3(mode: str) -> None:
141150
with Image.open("Tests/images/hopper.bmp") as source:
142151
reference_name = "hopper_emboss"
143152
reference_name += "_I.png" if mode == "I" else ".bmp"
@@ -163,7 +172,7 @@ def test_consistency_3x3(mode) -> None:
163172

164173

165174
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
166-
def test_consistency_5x5(mode) -> None:
175+
def test_consistency_5x5(mode: str) -> None:
167176
with Image.open("Tests/images/hopper.bmp") as source:
168177
reference_name = "hopper_emboss_more"
169178
reference_name += "_I.png" if mode == "I" else ".bmp"
@@ -199,7 +208,7 @@ def test_consistency_5x5(mode) -> None:
199208
(2, -2),
200209
),
201210
)
202-
def test_invalid_box_blur_filter(radius) -> None:
211+
def test_invalid_box_blur_filter(radius: int | tuple[int, int]) -> None:
203212
with pytest.raises(ValueError):
204213
ImageFilter.BoxBlur(radius)
205214

Tests/test_image_getextrema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
def test_extrema() -> None:
9-
def extrema(mode):
9+
def extrema(mode: str) -> tuple[int, int] | tuple[tuple[int, int], ...]:
1010
return hopper(mode).getextrema()
1111

1212
assert extrema("1") == (0, 255)

Tests/test_image_getpalette.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
def test_palette() -> None:
9-
def palette(mode):
9+
def palette(mode: str) -> list[int] | None:
1010
p = hopper(mode).getpalette()
1111
if p:
1212
return p[:10]

0 commit comments

Comments
 (0)