Added type hints

This commit is contained in:
Andrew Murray 2024-02-20 15:41:20 +11:00
parent 380bc1766b
commit e39765d755
19 changed files with 73 additions and 45 deletions

View File

@ -20,7 +20,7 @@ from PIL import _deprecate
),
],
)
def test_version(version, expected) -> None:
def test_version(version: int | None, expected: str) -> None:
with pytest.warns(DeprecationWarning, match=expected):
_deprecate.deprecate("Old thing", version, "new thing")
@ -46,7 +46,7 @@ def test_unknown_version() -> None:
),
],
)
def test_old_version(deprecated, plural, expected) -> None:
def test_old_version(deprecated: str, plural: bool, expected: str) -> None:
expected = r""
with pytest.raises(RuntimeError, match=expected):
_deprecate.deprecate(deprecated, 1, plural=plural)
@ -76,7 +76,7 @@ def test_replacement_and_action() -> None:
"Upgrade to new thing.",
],
)
def test_action(action) -> None:
def test_action(action: str) -> None:
expected = (
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
r"Upgrade to new thing\."

View File

@ -135,7 +135,7 @@ def test_different_bit_depths(tmp_path: Path) -> None:
@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA"))
def test_save_to_bytes_bmp(mode) -> None:
def test_save_to_bytes_bmp(mode: str) -> None:
output = io.BytesIO()
im = hopper(mode)
im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)])

View File

@ -98,7 +98,7 @@ def test_i() -> None:
assert ret == 97
def test_dump(monkeypatch) -> None:
def test_dump(monkeypatch: pytest.MonkeyPatch) -> None:
# Arrange
c = b"abc"
# Temporarily redirect stdout

View File

@ -52,7 +52,7 @@ def test_open_windows_v1() -> None:
assert isinstance(im, MspImagePlugin.MspImageFile)
def _assert_file_image_equal(source_path, target_path) -> None:
def _assert_file_image_equal(source_path: str, target_path: str) -> None:
with Image.open(source_path) as im:
assert_image_equal_tofile(im, target_path)

View File

@ -6,6 +6,7 @@ import warnings
import zlib
from io import BytesIO
from pathlib import Path
from types import ModuleType
from typing import Any
import pytest
@ -23,6 +24,7 @@ from .helper import (
skip_unless_feature,
)
ElementTree: ModuleType | None
try:
from defusedxml import ElementTree
except ImportError:

View File

@ -157,7 +157,7 @@ def test_combined_larger_than_size() -> None:
("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError),
],
)
def test_crashes(test_file, raises) -> None:
def test_crashes(test_file: str, raises) -> None:
with open(test_file, "rb") as f:
with pytest.raises(raises):
with Image.open(f):

View File

@ -22,8 +22,8 @@ _ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
@pytest.mark.parametrize("mode", _MODES)
def test_sanity(mode, tmp_path: Path) -> None:
def roundtrip(original_im) -> None:
def test_sanity(mode: str, tmp_path: Path) -> None:
def roundtrip(original_im: Image.Image) -> None:
out = str(tmp_path / "temp.tga")
original_im.save(out, rle=rle)

View File

@ -189,7 +189,9 @@ def test_iptc(tmp_path: Path) -> None:
@pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1")))
def test_writing_other_types_to_ascii(value, expected, tmp_path: Path) -> None:
def test_writing_other_types_to_ascii(
value: bytes | int, expected: str, tmp_path: Path
) -> None:
info = TiffImagePlugin.ImageFileDirectory_v2()
tag = TiffTags.TAGS_V2[271]
@ -206,7 +208,7 @@ def test_writing_other_types_to_ascii(value, expected, tmp_path: Path) -> None:
@pytest.mark.parametrize("value", (1, IFDRational(1)))
def test_writing_other_types_to_bytes(value, tmp_path: Path) -> None:
def test_writing_other_types_to_bytes(value: int | IFDRational, tmp_path: Path) -> None:
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()

View File

@ -237,7 +237,7 @@ def test_invalid_color_temperature() -> None:
@pytest.mark.parametrize("flag", ("my string", -1))
def test_invalid_flag(flag) -> None:
def test_invalid_flag(flag: str | int) -> None:
with hopper() as im:
with pytest.raises(
ImageCms.PyCMSError, match="flags must be an integer between 0 and "
@ -335,12 +335,26 @@ def test_extended_information() -> None:
o = ImageCms.getOpenProfile(SRGB)
p = o.profile
def assert_truncated_tuple_equal(tup1, tup2, digits: int = 10) -> None:
def assert_truncated_tuple_equal(
tup1: tuple[tuple[float, float, float], ...] | tuple[float],
tup2: (
tuple[tuple[tuple[float, float, float], ...], ...]
| tuple[tuple[float, float, float], ...]
| tuple[float]
),
digits: int = 10,
) -> None:
# Helper function to reduce precision of tuples of floats
# recursively and then check equality.
power = 10**digits
def truncate_tuple(tuple_or_float):
def truncate_tuple(
tuple_or_float: (
tuple[tuple[tuple[float, float, float], ...], ...]
| tuple[tuple[float, float, float], ...]
| tuple[float, ...]
)
) -> tuple[tuple[float, ...], ...]:
return tuple(
(
truncate_tuple(val)
@ -504,8 +518,10 @@ def test_profile_typesafety() -> None:
ImageCms.ImageCmsProfile(1).tobytes()
def assert_aux_channel_preserved(mode, transform_in_place, preserved_channel) -> None:
def create_test_image():
def assert_aux_channel_preserved(
mode: str, transform_in_place: bool, preserved_channel: str
) -> None:
def create_test_image() -> Image.Image:
# set up test image with something interesting in the tested aux channel.
# fmt: off
nine_grid_deltas = [
@ -633,7 +649,7 @@ def test_auxiliary_channels_isolated() -> None:
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
def test_rgb_lab(mode) -> None:
def test_rgb_lab(mode: str) -> None:
im = Image.new(mode, (1, 1))
converted_im = im.convert("LAB")
assert converted_im.getpixel((0, 0)) == (0, 128, 128)

View File

@ -7,7 +7,7 @@ import shutil
import sys
from io import BytesIO
from pathlib import Path
from typing import BinaryIO
from typing import Any, BinaryIO
import pytest
from packaging.version import parse as parse_version
@ -44,7 +44,7 @@ def test_sanity() -> None:
pytest.param(ImageFont.Layout.RAQM, marks=skip_unless_feature("raqm")),
],
)
def layout_engine(request):
def layout_engine(request: pytest.FixtureRequest) -> ImageFont.Layout:
return request.param
@ -535,21 +535,23 @@ def test_unicode_extended(layout_engine: ImageFont.Layout) -> None:
(("linux", "/usr/local/share/fonts"), ("darwin", "/System/Library/Fonts")),
)
@pytest.mark.skipif(is_win32(), reason="requires Unix or macOS")
def test_find_font(monkeypatch, platform, font_directory) -> None:
def test_find_font(
monkeypatch: pytest.MonkeyPatch, platform: str, font_directory: str
) -> None:
def _test_fake_loading_font(path_to_fake: str, fontname: str) -> None:
# Make a copy of FreeTypeFont so we can patch the original
free_type_font = copy.deepcopy(ImageFont.FreeTypeFont)
with monkeypatch.context() as m:
m.setattr(ImageFont, "_FreeTypeFont", free_type_font, raising=False)
def loadable_font(filepath, size, index, encoding, *args, **kwargs):
def loadable_font(
filepath: str, size: int, index: int, encoding: str, *args: Any
):
if filepath == path_to_fake:
return ImageFont._FreeTypeFont(
FONT_PATH, size, index, encoding, *args, **kwargs
FONT_PATH, size, index, encoding, *args
)
return ImageFont._FreeTypeFont(
filepath, size, index, encoding, *args, **kwargs
)
return ImageFont._FreeTypeFont(filepath, size, index, encoding, *args)
m.setattr(ImageFont, "FreeTypeFont", loadable_font)
font = ImageFont.truetype(fontname)
@ -563,7 +565,7 @@ def test_find_font(monkeypatch, platform, font_directory) -> None:
if platform == "linux":
monkeypatch.setenv("XDG_DATA_DIRS", "/usr/share/:/usr/local/share/")
def fake_walker(path):
def fake_walker(path: str) -> list[tuple[str, list[str], list[str]]]:
if path == font_directory:
return [
(
@ -1101,7 +1103,7 @@ def test_oom(test_file: str) -> None:
font.getmask("Test Text")
def test_raqm_missing_warning(monkeypatch) -> None:
def test_raqm_missing_warning(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(ImageFont.core, "HAVE_RAQM", False)
with pytest.warns(UserWarning) as record:
font = ImageFont.truetype(

View File

@ -84,6 +84,7 @@ $bmp = New-Object Drawing.Bitmap 200, 200
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_file(self) -> None:
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
assert p.stdin is not None
p.stdin.write(rb'Set-Clipboard -Path "Tests\images\hopper.gif"')
p.communicate()
@ -94,6 +95,7 @@ $bmp = New-Object Drawing.Bitmap 200, 200
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_png(self) -> None:
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
assert p.stdin is not None
p.stdin.write(
rb"""$bytes = [System.IO.File]::ReadAllBytes("Tests\images\hopper.png")
$ms = new-object System.IO.MemoryStream(, $bytes)
@ -113,7 +115,7 @@ $ms = new-object System.IO.MemoryStream(, $bytes)
reason="Linux with wl-clipboard only",
)
@pytest.mark.parametrize("ext", ("gif", "png", "ico"))
def test_grabclipboard_wl_clipboard(self, ext) -> None:
def test_grabclipboard_wl_clipboard(self, ext: str) -> None:
image_path = "Tests/images/hopper." + ext
with open(image_path, "rb") as fp:
subprocess.call(["wl-copy"], stdin=fp)
@ -128,6 +130,6 @@ $ms = new-object System.IO.MemoryStream(, $bytes)
reason="Linux with wl-clipboard only",
)
@pytest.mark.parametrize("arg", ("text", "--clear"))
def test_grabclipboard_wl_clipboard_errors(self, arg):
def test_grabclipboard_wl_clipboard_errors(self, arg: str) -> None:
subprocess.call(["wl-copy", arg])
assert ImageGrab.grabclipboard() is None

View File

@ -58,7 +58,9 @@ def test_path() -> None:
ImagePath.Path((0, 1)),
),
)
def test_path_constructors(coords) -> None:
def test_path_constructors(
coords: Sequence[float] | array.array[float] | ImagePath.Path,
) -> None:
# Arrange / Act
p = ImagePath.Path(coords)
@ -206,9 +208,9 @@ class Evil:
def __init__(self) -> None:
self.corrupt = Image.core.path(0x4000000000000000)
def __getitem__(self, i):
def __getitem__(self, i: int) -> bytes:
x = self.corrupt[i]
return struct.pack("dd", x[0], x[1])
def __setitem__(self, i, x) -> None:
def __setitem__(self, i: int, x: bytes) -> None:
self.corrupt[i] = struct.unpack("dd", x)

View File

@ -28,7 +28,7 @@ def test_rgb() -> None:
assert qRgb(0, 0, 0) == qRgba(0, 0, 0, 255)
def checkrgb(r, g, b) -> None:
def checkrgb(r: int, g: int, b: int) -> None:
val = ImageQt.rgb(r, g, b)
val = val % 2**24 # drop the alpha
assert val >> 16 == r

View File

@ -1,5 +1,7 @@
from __future__ import annotations
from typing import Any
import pytest
from PIL import Image, ImageShow
@ -24,9 +26,9 @@ def test_register() -> None:
"order",
[-1, 0],
)
def test_viewer_show(order) -> None:
def test_viewer_show(order: int) -> None:
class TestViewer(ImageShow.Viewer):
def show_image(self, image, **options) -> bool:
def show_image(self, image: Image.Image, **options: Any) -> bool:
self.methodCalled = True
return True
@ -48,7 +50,7 @@ def test_viewer_show(order) -> None:
reason="Only run on CIs; hangs on Windows CIs",
)
@pytest.mark.parametrize("mode", ("1", "I;16", "LA", "RGB", "RGBA"))
def test_show(mode) -> None:
def test_show(mode: str) -> None:
im = hopper(mode)
assert ImageShow.show(im)
@ -73,7 +75,7 @@ def test_viewer() -> None:
@pytest.mark.parametrize("viewer", ImageShow._viewers)
def test_viewers(viewer) -> None:
def test_viewers(viewer: ImageShow.Viewer) -> None:
try:
viewer.get_command("test.jpg")
except NotImplementedError:

View File

@ -70,7 +70,7 @@ if is_win32():
]
CreateDIBSection.restype = ctypes.wintypes.HBITMAP
def serialize_dib(bi, pixels):
def serialize_dib(bi, pixels) -> bytearray:
bf = BITMAPFILEHEADER()
bf.bfType = 0x4D42
bf.bfOffBits = ctypes.sizeof(bf) + bi.biSize

View File

@ -14,7 +14,7 @@ TEST_IMAGE_SIZE = (10, 10)
def test_numpy_to_image() -> None:
def to_image(dtype, bands: int = 1, boolean: int = 0):
def to_image(dtype, bands: int = 1, boolean: int = 0) -> Image.Image:
if bands == 1:
if boolean:
data = [0, 255] * 50
@ -99,7 +99,7 @@ def test_1d_array() -> None:
assert_image(Image.fromarray(a), "L", (1, 5))
def _test_img_equals_nparray(img, np) -> None:
def _test_img_equals_nparray(img: Image.Image, np) -> None:
assert len(np.shape) >= 2
np_size = np.shape[1], np.shape[0]
assert img.size == np_size
@ -157,7 +157,7 @@ def test_save_tiff_uint16() -> None:
("HSV", numpy.uint8),
),
)
def test_to_array(mode, dtype) -> None:
def test_to_array(mode: str, dtype) -> None:
img = hopper(mode)
# Resize to non-square

View File

@ -4,7 +4,7 @@ from pathlib import Path
import pytest
from PIL import ImageQt
from PIL import Image, ImageQt
from .helper import assert_image_equal_tofile, assert_image_similar, hopper
@ -37,7 +37,7 @@ if ImageQt.qt_is_installed:
lbl.setPixmap(pixmap1.copy())
def roundtrip(expected) -> None:
def roundtrip(expected: Image.Image) -> None:
result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected))
# Qt saves all pixmaps as rgb
assert_image_similar(result, expected.convert("RGB"), 1)

View File

@ -17,7 +17,7 @@ if ImageQt.qt_is_installed:
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "L", "P", "1"))
def test_sanity(mode, tmp_path: Path) -> None:
def test_sanity(mode: str, tmp_path: Path) -> None:
src = hopper(mode)
data = ImageQt.toqimage(src)

View File

@ -10,7 +10,7 @@ from PIL import _util
@pytest.mark.parametrize(
"test_path", ["filename.ext", Path("filename.ext"), PurePath("filename.ext")]
)
def test_is_path(test_path) -> None:
def test_is_path(test_path: str | Path | PurePath) -> None:
# Act
it_is = _util.is_path(test_path)