Skip to content

Commit b7f3907

Browse files
authored
Merge pull request #7846 from radarhere/type_hints
Added type hints to additional tests
2 parents d53e66e + 6d78d42 commit b7f3907

27 files changed

Lines changed: 115 additions & 88 deletions

Tests/check_imaging_leaks.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ def _get_mem_usage() -> float:
2323

2424

2525
def _test_leak(
26-
min_iterations: int, max_iterations: int, fn: Callable[..., None], *args: Any
26+
min_iterations: int,
27+
max_iterations: int,
28+
fn: Callable[..., Image.Image | None],
29+
*args: Any,
2730
) -> None:
2831
mem_limit = None
2932
for i in range(max_iterations):

Tests/check_png_dos.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def test_ignore_dos_text() -> None:
1717
finally:
1818
ImageFile.LOAD_TRUNCATED_IMAGES = False
1919

20+
assert isinstance(im, PngImagePlugin.PngImageFile)
2021
for s in im.text.values():
2122
assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
2223

@@ -32,6 +33,7 @@ def test_dos_text() -> None:
3233
assert msg, "Decompressed Data Too Large"
3334
return
3435

36+
assert isinstance(im, PngImagePlugin.PngImageFile)
3537
for s in im.text.values():
3638
assert len(s) < 1024 * 1024, "Text chunk larger than 1M"
3739

@@ -57,6 +59,7 @@ def test_dos_total_memory() -> None:
5759
return
5860

5961
total_len = 0
62+
assert isinstance(im2, PngImagePlugin.PngImageFile)
6063
for txt in im2.text.values():
6164
total_len += len(txt)
6265
assert total_len < 64 * 1024 * 1024, "Total text chunks greater than 64M"

Tests/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ def is_mingw() -> bool:
351351

352352

353353
class CachedProperty:
354-
def __init__(self, func: Callable[[Any], None]) -> None:
354+
def __init__(self, func: Callable[[Any], Any]) -> None:
355355
self.func = func
356356

357357
def __get__(self, instance: Any, cls: type[Any] | None = None) -> Any:

Tests/test_file_container.py

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

3+
from typing import Literal
4+
35
import pytest
46

57
from PIL import ContainerIO, Image
@@ -22,14 +24,14 @@ def test_isatty() -> None:
2224

2325

2426
@pytest.mark.parametrize(
25-
"mode, expected_value",
27+
"mode, expected_position",
2628
(
2729
(0, 33),
2830
(1, 66),
2931
(2, 100),
3032
),
3133
)
32-
def test_seek_mode(mode: int, expected_value: int) -> None:
34+
def test_seek_mode(mode: Literal[0, 1, 2], expected_position: int) -> None:
3335
# Arrange
3436
with open(TEST_FILE, "rb") as fh:
3537
container = ContainerIO.ContainerIO(fh, 22, 100)
@@ -39,7 +41,7 @@ def test_seek_mode(mode: int, expected_value: int) -> None:
3941
container.seek(33, mode)
4042

4143
# Assert
42-
assert container.tell() == expected_value
44+
assert container.tell() == expected_position
4345

4446

4547
@pytest.mark.parametrize("bytesmode", (True, False))

Tests/test_file_jpeg.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from io import BytesIO
77
from pathlib import Path
88
from types import ModuleType
9-
from typing import Any
9+
from typing import Any, cast
1010

1111
import pytest
1212

@@ -45,14 +45,20 @@
4545

4646
@skip_unless_feature("jpg")
4747
class TestFileJpeg:
48-
def roundtrip(self, im: Image.Image, **options: Any) -> Image.Image:
48+
def roundtrip_with_bytes(
49+
self, im: Image.Image, **options: Any
50+
) -> tuple[JpegImagePlugin.JpegImageFile, int]:
4951
out = BytesIO()
5052
im.save(out, "JPEG", **options)
5153
test_bytes = out.tell()
5254
out.seek(0)
53-
im = Image.open(out)
54-
im.bytes = test_bytes # for testing only
55-
return im
55+
reloaded = cast(JpegImagePlugin.JpegImageFile, Image.open(out))
56+
return reloaded, test_bytes
57+
58+
def roundtrip(
59+
self, im: Image.Image, **options: Any
60+
) -> JpegImagePlugin.JpegImageFile:
61+
return self.roundtrip_with_bytes(im, **options)[0]
5662

5763
def gen_random_image(self, size: tuple[int, int], mode: str = "RGB") -> Image.Image:
5864
"""Generates a very hard to compress file
@@ -246,13 +252,13 @@ def test_large_icc_meta(self, tmp_path: Path) -> None:
246252
im.save(f, progressive=True, quality=94, exif=b" " * 43668)
247253

248254
def test_optimize(self) -> None:
249-
im1 = self.roundtrip(hopper())
250-
im2 = self.roundtrip(hopper(), optimize=0)
251-
im3 = self.roundtrip(hopper(), optimize=1)
255+
im1, im1_bytes = self.roundtrip_with_bytes(hopper())
256+
im2, im2_bytes = self.roundtrip_with_bytes(hopper(), optimize=0)
257+
im3, im3_bytes = self.roundtrip_with_bytes(hopper(), optimize=1)
252258
assert_image_equal(im1, im2)
253259
assert_image_equal(im1, im3)
254-
assert im1.bytes >= im2.bytes
255-
assert im1.bytes >= im3.bytes
260+
assert im1_bytes >= im2_bytes
261+
assert im1_bytes >= im3_bytes
256262

257263
def test_optimize_large_buffer(self, tmp_path: Path) -> None:
258264
# https://github.com/python-pillow/Pillow/issues/148
@@ -262,15 +268,15 @@ def test_optimize_large_buffer(self, tmp_path: Path) -> None:
262268
im.save(f, format="JPEG", optimize=True)
263269

264270
def test_progressive(self) -> None:
265-
im1 = self.roundtrip(hopper())
271+
im1, im1_bytes = self.roundtrip_with_bytes(hopper())
266272
im2 = self.roundtrip(hopper(), progressive=False)
267-
im3 = self.roundtrip(hopper(), progressive=True)
273+
im3, im3_bytes = self.roundtrip_with_bytes(hopper(), progressive=True)
268274
assert not im1.info.get("progressive")
269275
assert not im2.info.get("progressive")
270276
assert im3.info.get("progressive")
271277

272278
assert_image_equal(im1, im3)
273-
assert im1.bytes >= im3.bytes
279+
assert im1_bytes >= im3_bytes
274280

275281
def test_progressive_large_buffer(self, tmp_path: Path) -> None:
276282
f = str(tmp_path / "temp.jpg")
@@ -341,6 +347,7 @@ def test_empty_exif_gps(self) -> None:
341347
assert exif.get_ifd(0x8825) == {}
342348

343349
transposed = ImageOps.exif_transpose(im)
350+
assert transposed is not None
344351
exif = transposed.getexif()
345352
assert exif.get_ifd(0x8825) == {}
346353

@@ -419,14 +426,14 @@ def test_progressive_compat(self) -> None:
419426
assert im3.info.get("progression")
420427

421428
def test_quality(self) -> None:
422-
im1 = self.roundtrip(hopper())
423-
im2 = self.roundtrip(hopper(), quality=50)
429+
im1, im1_bytes = self.roundtrip_with_bytes(hopper())
430+
im2, im2_bytes = self.roundtrip_with_bytes(hopper(), quality=50)
424431
assert_image(im1, im2.mode, im2.size)
425-
assert im1.bytes >= im2.bytes
432+
assert im1_bytes >= im2_bytes
426433

427-
im3 = self.roundtrip(hopper(), quality=0)
434+
im3, im3_bytes = self.roundtrip_with_bytes(hopper(), quality=0)
428435
assert_image(im1, im3.mode, im3.size)
429-
assert im2.bytes > im3.bytes
436+
assert im2_bytes > im3_bytes
430437

431438
def test_smooth(self) -> None:
432439
im1 = self.roundtrip(hopper())

Tests/test_file_jpeg2k.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@
4040
def roundtrip(im: Image.Image, **options: Any) -> Image.Image:
4141
out = BytesIO()
4242
im.save(out, "JPEG2000", **options)
43-
test_bytes = out.tell()
4443
out.seek(0)
4544
with Image.open(out) as im:
46-
im.bytes = test_bytes # for testing only
4745
im.load()
4846
return im
4947

@@ -77,7 +75,9 @@ def test_invalid_file() -> None:
7775
def test_bytesio() -> None:
7876
with open("Tests/images/test-card-lossless.jp2", "rb") as f:
7977
data = BytesIO(f.read())
80-
assert_image_similar_tofile(test_card, data, 1.0e-3)
78+
with Image.open(data) as im:
79+
im.load()
80+
assert_image_similar(im, test_card, 1.0e-3)
8181

8282

8383
# These two test pre-written JPEG 2000 files that were not written with
@@ -340,6 +340,7 @@ def test_parser_feed() -> None:
340340
p.feed(data)
341341

342342
# Assert
343+
assert p.image is not None
343344
assert p.image.size == (640, 480)
344345

345346

Tests/test_file_libtiff.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
@skip_unless_feature("libtiff")
2929
class LibTiffTestCase:
30-
def _assert_noerr(self, tmp_path: Path, im: Image.Image) -> None:
30+
def _assert_noerr(self, tmp_path: Path, im: TiffImagePlugin.TiffImageFile) -> None:
3131
"""Helper tests that assert basic sanity about the g4 tiff reading"""
3232
# 1 bit
3333
assert im.mode == "1"
@@ -524,7 +524,8 @@ def test_bw_compression_w_rgb(self, compression: str, tmp_path: Path) -> None:
524524
im.save(out, compression=compression)
525525

526526
def test_fp_leak(self) -> None:
527-
im = Image.open("Tests/images/hopper_g4_500.tif")
527+
im: Image.Image | None = Image.open("Tests/images/hopper_g4_500.tif")
528+
assert im is not None
528529
fn = im.fp.fileno()
529530

530531
os.fstat(fn)
@@ -716,6 +717,7 @@ def test_fd_duplication(self, tmp_path: Path) -> None:
716717
f.write(src.read())
717718

718719
im = Image.open(tmpfile)
720+
assert isinstance(im, TiffImagePlugin.TiffImageFile)
719721
im.n_frames
720722
im.close()
721723
# Should not raise PermissionError.
@@ -1097,6 +1099,7 @@ def test_save_multistrip(self, compression: str, tmp_path: Path) -> None:
10971099

10981100
with Image.open(out) as im:
10991101
# Assert that there are multiple strips
1102+
assert isinstance(im, TiffImagePlugin.TiffImageFile)
11001103
assert len(im.tag_v2[STRIPOFFSETS]) > 1
11011104

11021105
@pytest.mark.parametrize("argument", (True, False))
@@ -1113,6 +1116,7 @@ def test_save_single_strip(self, argument: bool, tmp_path: Path) -> None:
11131116
im.save(out, **arguments)
11141117

11151118
with Image.open(out) as im:
1119+
assert isinstance(im, TiffImagePlugin.TiffImageFile)
11161120
assert len(im.tag_v2[STRIPOFFSETS]) == 1
11171121
finally:
11181122
TiffImagePlugin.STRIP_SIZE = 65536

Tests/test_file_mpo.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
import warnings
44
from io import BytesIO
5-
from typing import Any
5+
from typing import Any, cast
66

77
import pytest
88

9-
from PIL import Image
9+
from PIL import Image, MpoImagePlugin
1010

1111
from .helper import (
1212
assert_image_equal,
@@ -20,14 +20,11 @@
2020
pytestmark = skip_unless_feature("jpg")
2121

2222

23-
def roundtrip(im: Image.Image, **options: Any) -> Image.Image:
23+
def roundtrip(im: Image.Image, **options: Any) -> MpoImagePlugin.MpoImageFile:
2424
out = BytesIO()
2525
im.save(out, "MPO", **options)
26-
test_bytes = out.tell()
2726
out.seek(0)
28-
im = Image.open(out)
29-
im.bytes = test_bytes # for testing only
30-
return im
27+
return cast(MpoImagePlugin.MpoImageFile, Image.open(out))
3128

3229

3330
@pytest.mark.parametrize("test_file", test_files)

Tests/test_file_png.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from io import BytesIO
88
from pathlib import Path
99
from types import ModuleType
10-
from typing import Any
10+
from typing import Any, cast
1111

1212
import pytest
1313

@@ -59,11 +59,11 @@ def load(data: bytes) -> Image.Image:
5959
return Image.open(BytesIO(data))
6060

6161

62-
def roundtrip(im: Image.Image, **options: Any) -> Image.Image:
62+
def roundtrip(im: Image.Image, **options: Any) -> PngImagePlugin.PngImageFile:
6363
out = BytesIO()
6464
im.save(out, "PNG", **options)
6565
out.seek(0)
66-
return Image.open(out)
66+
return cast(PngImagePlugin.PngImageFile, Image.open(out))
6767

6868

6969
@skip_unless_feature("zlib")

Tests/test_file_spider.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from PIL import Image, ImageSequence, SpiderImagePlugin
1111

12-
from .helper import assert_image_equal_tofile, hopper, is_pypy
12+
from .helper import assert_image_equal, hopper, is_pypy
1313

1414
TEST_FILE = "Tests/images/hopper.spider"
1515

@@ -152,12 +152,13 @@ def test_nonstack_dos() -> None:
152152
assert i <= 1, "Non-stack DOS file test failed"
153153

154154

155-
# for issue #4093
155+
# for issue #4093s
156156
def test_odd_size() -> None:
157157
data = BytesIO()
158158
width = 100
159159
im = Image.new("F", (width, 64))
160160
im.save(data, format="SPIDER")
161161

162162
data.seek(0)
163-
assert_image_equal_tofile(im, data)
163+
with Image.open(data) as im2:
164+
assert_image_equal(im, im2)

0 commit comments

Comments
 (0)