Skip to content

Commit 6782a07

Browse files
authored
Merge pull request #7784 from radarhere/type_hints
Added type hints to additional tests
2 parents 5bd8fd1 + 463c368 commit 6782a07

File tree

10 files changed

+160
-134
lines changed

10 files changed

+160
-134
lines changed

Tests/test_color_lut.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616

1717
class TestColorLut3DCoreAPI:
18-
def generate_identity_table(self, channels, size):
18+
def generate_identity_table(
19+
self, channels: int, size: int | tuple[int, int, int]
20+
) -> tuple[int, int, int, int, list[float]]:
1921
if isinstance(size, tuple):
2022
size_1d, size_2d, size_3d = size
2123
else:

Tests/test_file_eps.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252)))
8585
)
8686
@pytest.mark.parametrize("scale", (1, 2))
87-
def test_sanity(filename, size, scale) -> None:
87+
def test_sanity(filename: str, size: tuple[int, int], scale: int) -> None:
8888
expected_size = tuple(s * scale for s in size)
8989
with Image.open(filename) as image:
9090
image.load(scale=scale)
@@ -129,28 +129,28 @@ def test_binary_header_only() -> None:
129129

130130

131131
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
132-
def test_missing_version_comment(prefix) -> None:
132+
def test_missing_version_comment(prefix: bytes) -> None:
133133
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_version))
134134
with pytest.raises(SyntaxError):
135135
EpsImagePlugin.EpsImageFile(data)
136136

137137

138138
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
139-
def test_missing_boundingbox_comment(prefix) -> None:
139+
def test_missing_boundingbox_comment(prefix: bytes) -> None:
140140
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_boundingbox))
141141
with pytest.raises(SyntaxError, match='EPS header missing "%%BoundingBox" comment'):
142142
EpsImagePlugin.EpsImageFile(data)
143143

144144

145145
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
146-
def test_invalid_boundingbox_comment(prefix) -> None:
146+
def test_invalid_boundingbox_comment(prefix: bytes) -> None:
147147
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox))
148148
with pytest.raises(OSError, match="cannot determine EPS bounding box"):
149149
EpsImagePlugin.EpsImageFile(data)
150150

151151

152152
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
153-
def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix) -> None:
153+
def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix: bytes) -> None:
154154
data = io.BytesIO(
155155
prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox_valid_imagedata)
156156
)
@@ -161,21 +161,21 @@ def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix) -> None:
161161

162162

163163
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
164-
def test_ascii_comment_too_long(prefix) -> None:
164+
def test_ascii_comment_too_long(prefix: bytes) -> None:
165165
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_ascii_comment))
166166
with pytest.raises(SyntaxError, match="not an EPS file"):
167167
EpsImagePlugin.EpsImageFile(data)
168168

169169

170170
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
171-
def test_long_binary_data(prefix) -> None:
171+
def test_long_binary_data(prefix: bytes) -> None:
172172
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
173173
EpsImagePlugin.EpsImageFile(data)
174174

175175

176176
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
177177
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
178-
def test_load_long_binary_data(prefix) -> None:
178+
def test_load_long_binary_data(prefix: bytes) -> None:
179179
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
180180
with Image.open(data) as img:
181181
img.load()
@@ -305,7 +305,7 @@ def test_render_scale2() -> None:
305305

306306
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
307307
@pytest.mark.parametrize("filename", (FILE1, FILE2, "Tests/images/illu10_preview.eps"))
308-
def test_resize(filename) -> None:
308+
def test_resize(filename: str) -> None:
309309
with Image.open(filename) as im:
310310
new_size = (100, 100)
311311
im = im.resize(new_size)
@@ -314,7 +314,7 @@ def test_resize(filename) -> None:
314314

315315
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
316316
@pytest.mark.parametrize("filename", (FILE1, FILE2))
317-
def test_thumbnail(filename) -> None:
317+
def test_thumbnail(filename: str) -> None:
318318
# Issue #619
319319
with Image.open(filename) as im:
320320
new_size = (100, 100)
@@ -335,7 +335,7 @@ def test_readline_psfile(tmp_path: Path) -> None:
335335
line_endings = ["\r\n", "\n", "\n\r", "\r"]
336336
strings = ["something", "else", "baz", "bif"]
337337

338-
def _test_readline(t, ending) -> None:
338+
def _test_readline(t: EpsImagePlugin.PSFile, ending: str) -> None:
339339
ending = "Failure with line ending: %s" % (
340340
"".join("%s" % ord(s) for s in ending)
341341
)
@@ -344,13 +344,13 @@ def _test_readline(t, ending) -> None:
344344
assert t.readline().strip("\r\n") == "baz", ending
345345
assert t.readline().strip("\r\n") == "bif", ending
346346

347-
def _test_readline_io_psfile(test_string, ending) -> None:
347+
def _test_readline_io_psfile(test_string: str, ending: str) -> None:
348348
f = io.BytesIO(test_string.encode("latin-1"))
349349
with pytest.warns(DeprecationWarning):
350350
t = EpsImagePlugin.PSFile(f)
351351
_test_readline(t, ending)
352352

353-
def _test_readline_file_psfile(test_string, ending) -> None:
353+
def _test_readline_file_psfile(test_string: str, ending: str) -> None:
354354
f = str(tmp_path / "temp.txt")
355355
with open(f, "wb") as w:
356356
w.write(test_string.encode("latin-1"))
@@ -376,7 +376,7 @@ def test_psfile_deprecation() -> None:
376376
"line_ending",
377377
(b"\r\n", b"\n", b"\n\r", b"\r"),
378378
)
379-
def test_readline(prefix, line_ending) -> None:
379+
def test_readline(prefix: bytes, line_ending: bytes) -> None:
380380
simple_file = prefix + line_ending.join(simple_eps_file_with_comments)
381381
data = io.BytesIO(simple_file)
382382
test_file = EpsImagePlugin.EpsImageFile(data)
@@ -394,7 +394,7 @@ def test_readline(prefix, line_ending) -> None:
394394
"Tests/images/illuCS6_preview.eps",
395395
),
396396
)
397-
def test_open_eps(filename) -> None:
397+
def test_open_eps(filename: str) -> None:
398398
# https://github.com/python-pillow/Pillow/issues/1104
399399
with Image.open(filename) as img:
400400
assert img.mode == "RGB"
@@ -417,7 +417,7 @@ def test_emptyline() -> None:
417417
"test_file",
418418
["Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps"],
419419
)
420-
def test_timeout(test_file) -> None:
420+
def test_timeout(test_file: str) -> None:
421421
with open(test_file, "rb") as f:
422422
with pytest.raises(Image.UnidentifiedImageError):
423423
with Image.open(f):

Tests/test_file_jpeg.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import warnings
66
from io import BytesIO
77
from pathlib import Path
8+
from typing import Any
89

910
import pytest
1011

@@ -42,7 +43,7 @@
4243

4344
@skip_unless_feature("jpg")
4445
class TestFileJpeg:
45-
def roundtrip(self, im, **options):
46+
def roundtrip(self, im: Image.Image, **options: Any) -> Image.Image:
4647
out = BytesIO()
4748
im.save(out, "JPEG", **options)
4849
test_bytes = out.tell()
@@ -51,7 +52,7 @@ def roundtrip(self, im, **options):
5152
im.bytes = test_bytes # for testing only
5253
return im
5354

54-
def gen_random_image(self, size, mode: str = "RGB"):
55+
def gen_random_image(self, size: tuple[int, int], mode: str = "RGB") -> Image.Image:
5556
"""Generates a very hard to compress file
5657
:param size: tuple
5758
:param mode: optional image mode
@@ -71,7 +72,7 @@ def test_sanity(self) -> None:
7172
assert im.get_format_mimetype() == "image/jpeg"
7273

7374
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
74-
def test_zero(self, size, tmp_path: Path) -> None:
75+
def test_zero(self, size: tuple[int, int], tmp_path: Path) -> None:
7576
f = str(tmp_path / "temp.jpg")
7677
im = Image.new("RGB", size)
7778
with pytest.raises(ValueError):
@@ -108,13 +109,11 @@ def test_comment_write(self) -> None:
108109
assert "comment" not in reloaded.info
109110

110111
# Test that a comment argument overrides the default comment
111-
for comment in ("Test comment text", b"Text comment text"):
112+
for comment in ("Test comment text", b"Test comment text"):
112113
out = BytesIO()
113114
im.save(out, format="JPEG", comment=comment)
114115
with Image.open(out) as reloaded:
115-
if not isinstance(comment, bytes):
116-
comment = comment.encode()
117-
assert reloaded.info["comment"] == comment
116+
assert reloaded.info["comment"] == b"Test comment text"
118117

119118
def test_cmyk(self) -> None:
120119
# Test CMYK handling. Thanks to Tim and Charlie for test data,
@@ -145,7 +144,7 @@ def test_cmyk(self) -> None:
145144
assert k > 0.9
146145

147146
def test_rgb(self) -> None:
148-
def getchannels(im):
147+
def getchannels(im: Image.Image) -> tuple[int, int, int]:
149148
return tuple(v[0] for v in im.layer)
150149

151150
im = hopper()
@@ -161,8 +160,8 @@ def getchannels(im):
161160
"test_image_path",
162161
[TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
163162
)
164-
def test_dpi(self, test_image_path) -> None:
165-
def test(xdpi, ydpi=None):
163+
def test_dpi(self, test_image_path: str) -> None:
164+
def test(xdpi: int, ydpi: int | None = None):
166165
with Image.open(test_image_path) as im:
167166
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
168167
return im.info.get("dpi")
@@ -207,7 +206,7 @@ def test_icc(self, tmp_path: Path) -> None:
207206
ImageFile.MAXBLOCK * 4 + 3, # large block
208207
),
209208
)
210-
def test_icc_big(self, n) -> None:
209+
def test_icc_big(self, n: int) -> None:
211210
# Make sure that the "extra" support handles large blocks
212211
# The ICC APP marker can store 65519 bytes per marker, so
213212
# using a 4-byte test code should allow us to detect out of
@@ -433,7 +432,7 @@ def test_smooth(self) -> None:
433432
assert_image(im1, im2.mode, im2.size)
434433

435434
def test_subsampling(self) -> None:
436-
def getsampling(im):
435+
def getsampling(im: Image.Image):
437436
layer = im.layer
438437
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
439438

@@ -530,7 +529,7 @@ def test_truncated_jpeg_throws_oserror(self) -> None:
530529
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
531530
)
532531
def test_qtables(self, tmp_path: Path) -> None:
533-
def _n_qtables_helper(n, test_file) -> None:
532+
def _n_qtables_helper(n: int, test_file: str) -> None:
534533
with Image.open(test_file) as im:
535534
f = str(tmp_path / "temp.jpg")
536535
im.save(f, qtables=[[n] * 64] * n)
@@ -666,7 +665,7 @@ def test_save_low_quality_baseline_qtables(self) -> None:
666665
"blocks, rows, markers",
667666
((0, 0, 0), (1, 0, 15), (3, 0, 5), (8, 0, 1), (0, 1, 3), (0, 2, 1)),
668667
)
669-
def test_restart_markers(self, blocks, rows, markers) -> None:
668+
def test_restart_markers(self, blocks: int, rows: int, markers: int) -> None:
670669
im = Image.new("RGB", (32, 32)) # 16 MCUs
671670
out = BytesIO()
672671
im.save(
@@ -724,13 +723,13 @@ def test_bad_mpo_header(self) -> None:
724723
assert im.format == "JPEG"
725724

726725
@pytest.mark.parametrize("mode", ("1", "L", "RGB", "RGBX", "CMYK", "YCbCr"))
727-
def test_save_correct_modes(self, mode) -> None:
726+
def test_save_correct_modes(self, mode: str) -> None:
728727
out = BytesIO()
729728
img = Image.new(mode, (20, 20))
730729
img.save(out, "JPEG")
731730

732731
@pytest.mark.parametrize("mode", ("LA", "La", "RGBA", "RGBa", "P"))
733-
def test_save_wrong_modes(self, mode) -> None:
732+
def test_save_wrong_modes(self, mode: str) -> None:
734733
# ref https://github.com/python-pillow/Pillow/issues/2005
735734
out = BytesIO()
736735
img = Image.new(mode, (20, 20))
@@ -982,12 +981,12 @@ def test_eof(self) -> None:
982981
# Even though this decoder never says that it is finished
983982
# the image should still end when there is no new data
984983
class InfiniteMockPyDecoder(ImageFile.PyDecoder):
985-
def decode(self, buffer):
984+
def decode(self, buffer: bytes) -> tuple[int, int]:
986985
return 0, 0
987986

988987
decoder = InfiniteMockPyDecoder(None)
989988

990-
def closure(mode, *args):
989+
def closure(mode: str, *args) -> InfiniteMockPyDecoder:
991990
decoder.__init__(mode, *args)
992991
return decoder
993992

Tests/test_file_jpeg2k.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
from io import BytesIO
66
from pathlib import Path
7+
from typing import Any
78

89
import pytest
910

@@ -36,7 +37,7 @@
3637
# 'Not enough memory to handle tile data'
3738

3839

39-
def roundtrip(im, **options):
40+
def roundtrip(im: Image.Image, **options: Any) -> Image.Image:
4041
out = BytesIO()
4142
im.save(out, "JPEG2000", **options)
4243
test_bytes = out.tell()
@@ -138,7 +139,7 @@ def test_prog_res_rt() -> None:
138139

139140

140141
@pytest.mark.parametrize("num_resolutions", range(2, 6))
141-
def test_default_num_resolutions(num_resolutions) -> None:
142+
def test_default_num_resolutions(num_resolutions: int) -> None:
142143
d = 1 << (num_resolutions - 1)
143144
im = test_card.resize((d - 1, d - 1))
144145
with pytest.raises(OSError):
@@ -198,9 +199,9 @@ def test_layers_type(tmp_path: Path) -> None:
198199
for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
199200
test_card.save(outfile, quality_layers=quality_layers)
200201

201-
for quality_layers in ["quality_layers", ("100", "50", "10")]:
202+
for quality_layers_str in ["quality_layers", ("100", "50", "10")]:
202203
with pytest.raises(ValueError):
203-
test_card.save(outfile, quality_layers=quality_layers)
204+
test_card.save(outfile, quality_layers=quality_layers_str)
204205

205206

206207
def test_layers() -> None:
@@ -233,7 +234,7 @@ def test_layers() -> None:
233234
("foo.jp2", {"no_jp2": False}, 4, b"jP"),
234235
),
235236
)
236-
def test_no_jp2(name, args, offset, data) -> None:
237+
def test_no_jp2(name: str, args: dict[str, bool], offset: int, data: bytes) -> None:
237238
out = BytesIO()
238239
if name:
239240
out.name = name
@@ -278,7 +279,7 @@ def test_sgnd(tmp_path: Path) -> None:
278279

279280

280281
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
281-
def test_rgba(ext) -> None:
282+
def test_rgba(ext: str) -> None:
282283
# Arrange
283284
with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im:
284285
# Act
@@ -289,7 +290,7 @@ def test_rgba(ext) -> None:
289290

290291

291292
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
292-
def test_16bit_monochrome_has_correct_mode(ext) -> None:
293+
def test_16bit_monochrome_has_correct_mode(ext: str) -> None:
293294
with Image.open("Tests/images/16bit.cropped" + ext) as im:
294295
im.load()
295296
assert im.mode == "I;16"
@@ -346,12 +347,12 @@ def test_parser_feed() -> None:
346347
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
347348
)
348349
@pytest.mark.parametrize("name", ("subsampling_1", "subsampling_2", "zoo1", "zoo2"))
349-
def test_subsampling_decode(name) -> None:
350+
def test_subsampling_decode(name: str) -> None:
350351
test = f"{EXTRA_DIR}/{name}.jp2"
351352
reference = f"{EXTRA_DIR}/{name}.ppm"
352353

353354
with Image.open(test) as im:
354-
epsilon = 3 # for YCbCr images
355+
epsilon = 3.0 # for YCbCr images
355356
with Image.open(reference) as im2:
356357
width, height = im2.size
357358
if name[-1] == "2":
@@ -400,7 +401,7 @@ def test_save_comment() -> None:
400401
"Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k",
401402
],
402403
)
403-
def test_crashes(test_file) -> None:
404+
def test_crashes(test_file: str) -> None:
404405
with open(test_file, "rb") as f:
405406
with Image.open(f) as im:
406407
# Valgrind should not complain here

0 commit comments

Comments
 (0)