From 1d63cffdadbf649442804dae288992cdd854a849 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 19 Jan 2024 21:50:27 +1100 Subject: [PATCH] Added type hints --- Tests/check_fli_overflow.py | 2 +- Tests/check_imaging_leaks.py | 15 ++++++++++----- Tests/check_j2k_leaks.py | 4 ++-- Tests/check_j2k_overflow.py | 3 ++- Tests/check_jpeg_leaks.py | 6 +++--- Tests/check_large_memory.py | 12 ++++++++---- Tests/check_large_memory_numpy.py | 7 ++++--- Tests/check_libtiff_segfault.py | 2 +- Tests/check_png_dos.py | 8 ++++---- Tests/check_wheel.py | 6 +++--- Tests/helper.py | 4 ++-- 11 files changed, 40 insertions(+), 29 deletions(-) diff --git a/Tests/check_fli_overflow.py b/Tests/check_fli_overflow.py index 0fabcb5d35f..109f8fb5498 100644 --- a/Tests/check_fli_overflow.py +++ b/Tests/check_fli_overflow.py @@ -4,7 +4,7 @@ TEST_FILE = "Tests/images/fli_overflow.fli" -def test_fli_overflow(): +def test_fli_overflow() -> None: # this should not crash with a malloc error or access violation with Image.open(TEST_FILE) as im: im.load() diff --git a/Tests/check_imaging_leaks.py b/Tests/check_imaging_leaks.py index 8c17c051d4b..b0c4f620b93 100755 --- a/Tests/check_imaging_leaks.py +++ b/Tests/check_imaging_leaks.py @@ -2,6 +2,8 @@ from __future__ import annotations import pytest +from typing import Any, Callable + from PIL import Image from .helper import is_win32 @@ -12,31 +14,34 @@ pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS") -def _get_mem_usage(): +def _get_mem_usage() -> float: from resource import RUSAGE_SELF, getpagesize, getrusage mem = getrusage(RUSAGE_SELF).ru_maxrss return mem * getpagesize() / 1024 / 1024 -def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs): +def _test_leak( + min_iterations: int, max_iterations: int, fn: Callable[..., None], *args: Any +) -> None: mem_limit = None for i in range(max_iterations): - fn(*args, **kwargs) + fn(*args) mem = _get_mem_usage() if i < min_iterations: mem_limit = mem + 1 continue msg = f"memory usage limit exceeded after {i + 1} iterations" + assert mem_limit is not None assert mem <= mem_limit, msg -def test_leak_putdata(): +def test_leak_putdata() -> None: im = Image.new("RGB", (25, 25)) _test_leak(min_iterations, max_iterations, im.putdata, im.getdata()) -def test_leak_getlist(): +def test_leak_getlist() -> None: im = Image.new("P", (25, 25)) _test_leak( min_iterations, diff --git a/Tests/check_j2k_leaks.py b/Tests/check_j2k_leaks.py index 83a12e2c29f..0d0d3a57c2d 100644 --- a/Tests/check_j2k_leaks.py +++ b/Tests/check_j2k_leaks.py @@ -19,7 +19,7 @@ ] -def test_leak_load(): +def test_leak_load() -> None: from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit setrlimit(RLIMIT_STACK, (stack_size, stack_size)) @@ -29,7 +29,7 @@ def test_leak_load(): im.load() -def test_leak_save(): +def test_leak_save() -> None: from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit setrlimit(RLIMIT_STACK, (stack_size, stack_size)) diff --git a/Tests/check_j2k_overflow.py b/Tests/check_j2k_overflow.py index 982f6ea74d2..ba14964b55f 100644 --- a/Tests/check_j2k_overflow.py +++ b/Tests/check_j2k_overflow.py @@ -1,10 +1,11 @@ from __future__ import annotations +from pathlib import PosixPath import pytest from PIL import Image -def test_j2k_overflow(tmp_path): +def test_j2k_overflow(tmp_path: PosixPath) -> None: im = Image.new("RGBA", (1024, 131584)) target = str(tmp_path / "temp.jpc") with pytest.raises(OSError): diff --git a/Tests/check_jpeg_leaks.py b/Tests/check_jpeg_leaks.py index 3cd37c7af7b..e91709a9604 100644 --- a/Tests/check_jpeg_leaks.py +++ b/Tests/check_jpeg_leaks.py @@ -110,14 +110,14 @@ [standard_l_qtable, standard_chrominance_qtable], ), ) -def test_qtables_leak(qtables): +def test_qtables_leak(qtables: tuple[tuple[int, ...]] | list[tuple[int, ...]]) -> None: im = hopper("RGB") for _ in range(iterations): test_output = BytesIO() im.save(test_output, "JPEG", qtables=qtables) -def test_exif_leak(): +def test_exif_leak() -> None: """ pre patch: @@ -180,7 +180,7 @@ def test_exif_leak(): im.save(test_output, "JPEG", exif=exif) -def test_base_save(): +def test_base_save() -> None: """ base case: MB diff --git a/Tests/check_large_memory.py b/Tests/check_large_memory.py index 9b83798d5e7..4d67270765c 100644 --- a/Tests/check_large_memory.py +++ b/Tests/check_large_memory.py @@ -1,5 +1,7 @@ from __future__ import annotations +from pathlib import PosixPath import sys +from types import ModuleType import pytest @@ -15,6 +17,7 @@ # 2.7 and 3.2. +numpy: ModuleType | None try: import numpy except ImportError: @@ -27,23 +30,24 @@ pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system") -def _write_png(tmp_path, xdim, ydim): +def _write_png(tmp_path: PosixPath, xdim: int, ydim: int) -> None: f = str(tmp_path / "temp.png") im = Image.new("L", (xdim, ydim), 0) im.save(f) -def test_large(tmp_path): +def test_large(tmp_path: PosixPath) -> None: """succeeded prepatch""" _write_png(tmp_path, XDIM, YDIM) -def test_2gpx(tmp_path): +def test_2gpx(tmp_path: PosixPath) -> None: """failed prepatch""" _write_png(tmp_path, XDIM, XDIM) @pytest.mark.skipif(numpy is None, reason="Numpy is not installed") -def test_size_greater_than_int(): +def test_size_greater_than_int() -> None: + assert numpy is not None arr = numpy.ndarray(shape=(16394, 16394)) Image.fromarray(arr) diff --git a/Tests/check_large_memory_numpy.py b/Tests/check_large_memory_numpy.py index 0ff3de8dcc7..d1cbad887aa 100644 --- a/Tests/check_large_memory_numpy.py +++ b/Tests/check_large_memory_numpy.py @@ -1,4 +1,5 @@ from __future__ import annotations +from pathlib import PosixPath import sys import pytest @@ -23,7 +24,7 @@ pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system") -def _write_png(tmp_path, xdim, ydim): +def _write_png(tmp_path: PosixPath, xdim: int, ydim: int) -> None: dtype = np.uint8 a = np.zeros((xdim, ydim), dtype=dtype) f = str(tmp_path / "temp.png") @@ -31,11 +32,11 @@ def _write_png(tmp_path, xdim, ydim): im.save(f) -def test_large(tmp_path): +def test_large(tmp_path: PosixPath) -> None: """succeeded prepatch""" _write_png(tmp_path, XDIM, YDIM) -def test_2gpx(tmp_path): +def test_2gpx(tmp_path: PosixPath) -> None: """failed prepatch""" _write_png(tmp_path, XDIM, XDIM) diff --git a/Tests/check_libtiff_segfault.py b/Tests/check_libtiff_segfault.py index ee1d7d11f0c..f1c77efc16b 100644 --- a/Tests/check_libtiff_segfault.py +++ b/Tests/check_libtiff_segfault.py @@ -6,7 +6,7 @@ TEST_FILE = "Tests/images/libtiff_segfault.tif" -def test_libtiff_segfault(): +def test_libtiff_segfault() -> None: """This test should not segfault. It will on Pillow <= 3.1.0 and libtiff >= 4.0.0 """ diff --git a/Tests/check_png_dos.py b/Tests/check_png_dos.py index 292fe4b7f09..a3d50fa57e5 100644 --- a/Tests/check_png_dos.py +++ b/Tests/check_png_dos.py @@ -7,7 +7,7 @@ TEST_FILE = "Tests/images/png_decompression_dos.png" -def test_ignore_dos_text(): +def test_ignore_dos_text() -> None: ImageFile.LOAD_TRUNCATED_IMAGES = True try: @@ -23,7 +23,7 @@ def test_ignore_dos_text(): assert len(s) < 1024 * 1024, "Text chunk larger than 1M" -def test_dos_text(): +def test_dos_text() -> None: try: im = Image.open(TEST_FILE) im.load() @@ -35,7 +35,7 @@ def test_dos_text(): assert len(s) < 1024 * 1024, "Text chunk larger than 1M" -def test_dos_total_memory(): +def test_dos_total_memory() -> None: im = Image.new("L", (1, 1)) compressed_data = zlib.compress(b"a" * 1024 * 1023) @@ -52,7 +52,7 @@ def test_dos_total_memory(): try: im2 = Image.open(b) except ValueError as msg: - assert "Too much memory" in msg + assert "Too much memory" in str(msg) return total_len = 0 diff --git a/Tests/check_wheel.py b/Tests/check_wheel.py index afe4cc3eeaa..969e596b45a 100644 --- a/Tests/check_wheel.py +++ b/Tests/check_wheel.py @@ -4,7 +4,7 @@ from PIL import features -def test_wheel_modules(): +def test_wheel_modules() -> None: expected_modules = {"pil", "tkinter", "freetype2", "littlecms2", "webp"} # tkinter is not available in cibuildwheel installed CPython on Windows @@ -18,13 +18,13 @@ def test_wheel_modules(): assert set(features.get_supported_modules()) == expected_modules -def test_wheel_codecs(): +def test_wheel_codecs() -> None: expected_codecs = {"jpg", "jpg_2000", "zlib", "libtiff"} assert set(features.get_supported_codecs()) == expected_codecs -def test_wheel_features(): +def test_wheel_features() -> None: expected_features = { "webp_anim", "webp_mux", diff --git a/Tests/helper.py b/Tests/helper.py index 88c1f02a803..34839422e2f 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -238,7 +238,7 @@ def tostring(im, string_format, **options): return out.getvalue() -def hopper(mode=None, cache={}): +def hopper(mode: str | None = None, cache: dict[str, Image.Image] = {}) -> Image.Image: if mode is None: # Always return fresh not-yet-loaded version of image. # Operations on not-yet-loaded images is separate class of errors @@ -323,7 +323,7 @@ def is_ppc64le(): return platform.machine() == "ppc64le" -def is_win32(): +def is_win32() -> bool: return sys.platform.startswith("win32")