mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 00:46:16 +03:00
Added type hints
This commit is contained in:
parent
5bd8fd1dc6
commit
cdc498e6f3
|
@ -15,7 +15,9 @@ except ImportError:
|
|||
|
||||
|
||||
class TestColorLut3DCoreAPI:
|
||||
def generate_identity_table(self, channels, size):
|
||||
def generate_identity_table(
|
||||
self, channels: int, size: int | tuple[int, int, int]
|
||||
) -> tuple[int, int, int, int, list[float]]:
|
||||
if isinstance(size, tuple):
|
||||
size_1d, size_2d, size_3d = size
|
||||
else:
|
||||
|
|
|
@ -84,7 +84,7 @@ simple_eps_file_with_long_binary_data = (
|
|||
("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252)))
|
||||
)
|
||||
@pytest.mark.parametrize("scale", (1, 2))
|
||||
def test_sanity(filename, size, scale) -> None:
|
||||
def test_sanity(filename: str, size: tuple[int, int], scale: int) -> None:
|
||||
expected_size = tuple(s * scale for s in size)
|
||||
with Image.open(filename) as image:
|
||||
image.load(scale=scale)
|
||||
|
@ -129,28 +129,28 @@ def test_binary_header_only() -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_missing_version_comment(prefix) -> None:
|
||||
def test_missing_version_comment(prefix: bytes) -> None:
|
||||
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_version))
|
||||
with pytest.raises(SyntaxError):
|
||||
EpsImagePlugin.EpsImageFile(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_missing_boundingbox_comment(prefix) -> None:
|
||||
def test_missing_boundingbox_comment(prefix: bytes) -> None:
|
||||
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_boundingbox))
|
||||
with pytest.raises(SyntaxError, match='EPS header missing "%%BoundingBox" comment'):
|
||||
EpsImagePlugin.EpsImageFile(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_invalid_boundingbox_comment(prefix) -> None:
|
||||
def test_invalid_boundingbox_comment(prefix: bytes) -> None:
|
||||
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox))
|
||||
with pytest.raises(OSError, match="cannot determine EPS bounding box"):
|
||||
EpsImagePlugin.EpsImageFile(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix) -> None:
|
||||
def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix: bytes) -> None:
|
||||
data = io.BytesIO(
|
||||
prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox_valid_imagedata)
|
||||
)
|
||||
|
@ -161,21 +161,21 @@ def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix) -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_ascii_comment_too_long(prefix) -> None:
|
||||
def test_ascii_comment_too_long(prefix: bytes) -> None:
|
||||
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_ascii_comment))
|
||||
with pytest.raises(SyntaxError, match="not an EPS file"):
|
||||
EpsImagePlugin.EpsImageFile(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_long_binary_data(prefix) -> None:
|
||||
def test_long_binary_data(prefix: bytes) -> None:
|
||||
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
|
||||
EpsImagePlugin.EpsImageFile(data)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
||||
@pytest.mark.parametrize("prefix", (b"", simple_binary_header))
|
||||
def test_load_long_binary_data(prefix) -> None:
|
||||
def test_load_long_binary_data(prefix: bytes) -> None:
|
||||
data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data))
|
||||
with Image.open(data) as img:
|
||||
img.load()
|
||||
|
@ -305,7 +305,7 @@ def test_render_scale2() -> None:
|
|||
|
||||
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
||||
@pytest.mark.parametrize("filename", (FILE1, FILE2, "Tests/images/illu10_preview.eps"))
|
||||
def test_resize(filename) -> None:
|
||||
def test_resize(filename: str) -> None:
|
||||
with Image.open(filename) as im:
|
||||
new_size = (100, 100)
|
||||
im = im.resize(new_size)
|
||||
|
@ -314,7 +314,7 @@ def test_resize(filename) -> None:
|
|||
|
||||
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
|
||||
@pytest.mark.parametrize("filename", (FILE1, FILE2))
|
||||
def test_thumbnail(filename) -> None:
|
||||
def test_thumbnail(filename: str) -> None:
|
||||
# Issue #619
|
||||
with Image.open(filename) as im:
|
||||
new_size = (100, 100)
|
||||
|
@ -335,7 +335,7 @@ def test_readline_psfile(tmp_path: Path) -> None:
|
|||
line_endings = ["\r\n", "\n", "\n\r", "\r"]
|
||||
strings = ["something", "else", "baz", "bif"]
|
||||
|
||||
def _test_readline(t, ending) -> None:
|
||||
def _test_readline(t: EpsImagePlugin.PSFile, ending: str) -> None:
|
||||
ending = "Failure with line ending: %s" % (
|
||||
"".join("%s" % ord(s) for s in ending)
|
||||
)
|
||||
|
@ -344,13 +344,13 @@ def test_readline_psfile(tmp_path: Path) -> None:
|
|||
assert t.readline().strip("\r\n") == "baz", ending
|
||||
assert t.readline().strip("\r\n") == "bif", ending
|
||||
|
||||
def _test_readline_io_psfile(test_string, ending) -> None:
|
||||
def _test_readline_io_psfile(test_string: str, ending: str) -> None:
|
||||
f = io.BytesIO(test_string.encode("latin-1"))
|
||||
with pytest.warns(DeprecationWarning):
|
||||
t = EpsImagePlugin.PSFile(f)
|
||||
_test_readline(t, ending)
|
||||
|
||||
def _test_readline_file_psfile(test_string, ending) -> None:
|
||||
def _test_readline_file_psfile(test_string: str, ending: str) -> None:
|
||||
f = str(tmp_path / "temp.txt")
|
||||
with open(f, "wb") as w:
|
||||
w.write(test_string.encode("latin-1"))
|
||||
|
@ -376,7 +376,7 @@ def test_psfile_deprecation() -> None:
|
|||
"line_ending",
|
||||
(b"\r\n", b"\n", b"\n\r", b"\r"),
|
||||
)
|
||||
def test_readline(prefix, line_ending) -> None:
|
||||
def test_readline(prefix: bytes, line_ending: bytes) -> None:
|
||||
simple_file = prefix + line_ending.join(simple_eps_file_with_comments)
|
||||
data = io.BytesIO(simple_file)
|
||||
test_file = EpsImagePlugin.EpsImageFile(data)
|
||||
|
@ -394,7 +394,7 @@ def test_readline(prefix, line_ending) -> None:
|
|||
"Tests/images/illuCS6_preview.eps",
|
||||
),
|
||||
)
|
||||
def test_open_eps(filename) -> None:
|
||||
def test_open_eps(filename: str) -> None:
|
||||
# https://github.com/python-pillow/Pillow/issues/1104
|
||||
with Image.open(filename) as img:
|
||||
assert img.mode == "RGB"
|
||||
|
@ -417,7 +417,7 @@ def test_emptyline() -> None:
|
|||
"test_file",
|
||||
["Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps"],
|
||||
)
|
||||
def test_timeout(test_file) -> None:
|
||||
def test_timeout(test_file: str) -> None:
|
||||
with open(test_file, "rb") as f:
|
||||
with pytest.raises(Image.UnidentifiedImageError):
|
||||
with Image.open(f):
|
||||
|
|
|
@ -5,6 +5,7 @@ import re
|
|||
import warnings
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -42,7 +43,7 @@ TEST_FILE = "Tests/images/hopper.jpg"
|
|||
|
||||
@skip_unless_feature("jpg")
|
||||
class TestFileJpeg:
|
||||
def roundtrip(self, im, **options):
|
||||
def roundtrip(self, im: Image.Image, **options: Any) -> Image.Image:
|
||||
out = BytesIO()
|
||||
im.save(out, "JPEG", **options)
|
||||
test_bytes = out.tell()
|
||||
|
@ -51,7 +52,7 @@ class TestFileJpeg:
|
|||
im.bytes = test_bytes # for testing only
|
||||
return im
|
||||
|
||||
def gen_random_image(self, size, mode: str = "RGB"):
|
||||
def gen_random_image(self, size: tuple[int, int], mode: str = "RGB") -> Image.Image:
|
||||
"""Generates a very hard to compress file
|
||||
:param size: tuple
|
||||
:param mode: optional image mode
|
||||
|
@ -71,7 +72,7 @@ class TestFileJpeg:
|
|||
assert im.get_format_mimetype() == "image/jpeg"
|
||||
|
||||
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
|
||||
def test_zero(self, size, tmp_path: Path) -> None:
|
||||
def test_zero(self, size: tuple[int, int], tmp_path: Path) -> None:
|
||||
f = str(tmp_path / "temp.jpg")
|
||||
im = Image.new("RGB", size)
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -108,13 +109,11 @@ class TestFileJpeg:
|
|||
assert "comment" not in reloaded.info
|
||||
|
||||
# Test that a comment argument overrides the default comment
|
||||
for comment in ("Test comment text", b"Text comment text"):
|
||||
for comment in ("Test comment text", b"Test comment text"):
|
||||
out = BytesIO()
|
||||
im.save(out, format="JPEG", comment=comment)
|
||||
with Image.open(out) as reloaded:
|
||||
if not isinstance(comment, bytes):
|
||||
comment = comment.encode()
|
||||
assert reloaded.info["comment"] == comment
|
||||
assert reloaded.info["comment"] == b"Test comment text"
|
||||
|
||||
def test_cmyk(self) -> None:
|
||||
# Test CMYK handling. Thanks to Tim and Charlie for test data,
|
||||
|
@ -145,7 +144,7 @@ class TestFileJpeg:
|
|||
assert k > 0.9
|
||||
|
||||
def test_rgb(self) -> None:
|
||||
def getchannels(im):
|
||||
def getchannels(im: Image.Image) -> tuple[int, int, int]:
|
||||
return tuple(v[0] for v in im.layer)
|
||||
|
||||
im = hopper()
|
||||
|
@ -161,8 +160,8 @@ class TestFileJpeg:
|
|||
"test_image_path",
|
||||
[TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
|
||||
)
|
||||
def test_dpi(self, test_image_path) -> None:
|
||||
def test(xdpi, ydpi=None):
|
||||
def test_dpi(self, test_image_path: str) -> None:
|
||||
def test(xdpi: int, ydpi: int | None = None):
|
||||
with Image.open(test_image_path) as im:
|
||||
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
|
||||
return im.info.get("dpi")
|
||||
|
@ -207,7 +206,7 @@ class TestFileJpeg:
|
|||
ImageFile.MAXBLOCK * 4 + 3, # large block
|
||||
),
|
||||
)
|
||||
def test_icc_big(self, n) -> None:
|
||||
def test_icc_big(self, n: int) -> None:
|
||||
# Make sure that the "extra" support handles large blocks
|
||||
# The ICC APP marker can store 65519 bytes per marker, so
|
||||
# using a 4-byte test code should allow us to detect out of
|
||||
|
@ -433,7 +432,7 @@ class TestFileJpeg:
|
|||
assert_image(im1, im2.mode, im2.size)
|
||||
|
||||
def test_subsampling(self) -> None:
|
||||
def getsampling(im):
|
||||
def getsampling(im: Image.Image):
|
||||
layer = im.layer
|
||||
return layer[0][1:3] + layer[1][1:3] + layer[2][1:3]
|
||||
|
||||
|
@ -530,7 +529,7 @@ class TestFileJpeg:
|
|||
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
|
||||
)
|
||||
def test_qtables(self, tmp_path: Path) -> None:
|
||||
def _n_qtables_helper(n, test_file) -> None:
|
||||
def _n_qtables_helper(n: int, test_file: str) -> None:
|
||||
with Image.open(test_file) as im:
|
||||
f = str(tmp_path / "temp.jpg")
|
||||
im.save(f, qtables=[[n] * 64] * n)
|
||||
|
@ -666,7 +665,7 @@ class TestFileJpeg:
|
|||
"blocks, rows, markers",
|
||||
((0, 0, 0), (1, 0, 15), (3, 0, 5), (8, 0, 1), (0, 1, 3), (0, 2, 1)),
|
||||
)
|
||||
def test_restart_markers(self, blocks, rows, markers) -> None:
|
||||
def test_restart_markers(self, blocks: int, rows: int, markers: int) -> None:
|
||||
im = Image.new("RGB", (32, 32)) # 16 MCUs
|
||||
out = BytesIO()
|
||||
im.save(
|
||||
|
@ -724,13 +723,13 @@ class TestFileJpeg:
|
|||
assert im.format == "JPEG"
|
||||
|
||||
@pytest.mark.parametrize("mode", ("1", "L", "RGB", "RGBX", "CMYK", "YCbCr"))
|
||||
def test_save_correct_modes(self, mode) -> None:
|
||||
def test_save_correct_modes(self, mode: str) -> None:
|
||||
out = BytesIO()
|
||||
img = Image.new(mode, (20, 20))
|
||||
img.save(out, "JPEG")
|
||||
|
||||
@pytest.mark.parametrize("mode", ("LA", "La", "RGBA", "RGBa", "P"))
|
||||
def test_save_wrong_modes(self, mode) -> None:
|
||||
def test_save_wrong_modes(self, mode: str) -> None:
|
||||
# ref https://github.com/python-pillow/Pillow/issues/2005
|
||||
out = BytesIO()
|
||||
img = Image.new(mode, (20, 20))
|
||||
|
@ -982,12 +981,12 @@ class TestFileJpeg:
|
|||
# Even though this decoder never says that it is finished
|
||||
# the image should still end when there is no new data
|
||||
class InfiniteMockPyDecoder(ImageFile.PyDecoder):
|
||||
def decode(self, buffer):
|
||||
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||
return 0, 0
|
||||
|
||||
decoder = InfiniteMockPyDecoder(None)
|
||||
|
||||
def closure(mode, *args):
|
||||
def closure(mode: str, *args) -> InfiniteMockPyDecoder:
|
||||
decoder.__init__(mode, *args)
|
||||
return decoder
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import os
|
|||
import re
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -36,7 +37,7 @@ test_card.load()
|
|||
# 'Not enough memory to handle tile data'
|
||||
|
||||
|
||||
def roundtrip(im, **options):
|
||||
def roundtrip(im: Image.Image, **options: Any) -> Image.Image:
|
||||
out = BytesIO()
|
||||
im.save(out, "JPEG2000", **options)
|
||||
test_bytes = out.tell()
|
||||
|
@ -138,7 +139,7 @@ def test_prog_res_rt() -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("num_resolutions", range(2, 6))
|
||||
def test_default_num_resolutions(num_resolutions) -> None:
|
||||
def test_default_num_resolutions(num_resolutions: int) -> None:
|
||||
d = 1 << (num_resolutions - 1)
|
||||
im = test_card.resize((d - 1, d - 1))
|
||||
with pytest.raises(OSError):
|
||||
|
@ -198,9 +199,9 @@ def test_layers_type(tmp_path: Path) -> None:
|
|||
for quality_layers in [[100, 50, 10], (100, 50, 10), None]:
|
||||
test_card.save(outfile, quality_layers=quality_layers)
|
||||
|
||||
for quality_layers in ["quality_layers", ("100", "50", "10")]:
|
||||
for quality_layers_str in ["quality_layers", ("100", "50", "10")]:
|
||||
with pytest.raises(ValueError):
|
||||
test_card.save(outfile, quality_layers=quality_layers)
|
||||
test_card.save(outfile, quality_layers=quality_layers_str)
|
||||
|
||||
|
||||
def test_layers() -> None:
|
||||
|
@ -233,7 +234,7 @@ def test_layers() -> None:
|
|||
("foo.jp2", {"no_jp2": False}, 4, b"jP"),
|
||||
),
|
||||
)
|
||||
def test_no_jp2(name, args, offset, data) -> None:
|
||||
def test_no_jp2(name: str, args: dict[str, bool], offset: int, data: bytes) -> None:
|
||||
out = BytesIO()
|
||||
if name:
|
||||
out.name = name
|
||||
|
@ -278,7 +279,7 @@ def test_sgnd(tmp_path: Path) -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
|
||||
def test_rgba(ext) -> None:
|
||||
def test_rgba(ext: str) -> None:
|
||||
# Arrange
|
||||
with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im:
|
||||
# Act
|
||||
|
@ -289,7 +290,7 @@ def test_rgba(ext) -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
|
||||
def test_16bit_monochrome_has_correct_mode(ext) -> None:
|
||||
def test_16bit_monochrome_has_correct_mode(ext: str) -> None:
|
||||
with Image.open("Tests/images/16bit.cropped" + ext) as im:
|
||||
im.load()
|
||||
assert im.mode == "I;16"
|
||||
|
@ -346,12 +347,12 @@ def test_parser_feed() -> None:
|
|||
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
|
||||
)
|
||||
@pytest.mark.parametrize("name", ("subsampling_1", "subsampling_2", "zoo1", "zoo2"))
|
||||
def test_subsampling_decode(name) -> None:
|
||||
def test_subsampling_decode(name: str) -> None:
|
||||
test = f"{EXTRA_DIR}/{name}.jp2"
|
||||
reference = f"{EXTRA_DIR}/{name}.ppm"
|
||||
|
||||
with Image.open(test) as im:
|
||||
epsilon = 3 # for YCbCr images
|
||||
epsilon = 3.0 # for YCbCr images
|
||||
with Image.open(reference) as im2:
|
||||
width, height = im2.size
|
||||
if name[-1] == "2":
|
||||
|
@ -400,7 +401,7 @@ def test_save_comment() -> None:
|
|||
"Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k",
|
||||
],
|
||||
)
|
||||
def test_crashes(test_file) -> None:
|
||||
def test_crashes(test_file: str) -> None:
|
||||
with open(test_file, "rb") as f:
|
||||
with Image.open(f) as im:
|
||||
# Valgrind should not complain here
|
||||
|
|
|
@ -27,7 +27,7 @@ from .helper import (
|
|||
|
||||
@skip_unless_feature("libtiff")
|
||||
class LibTiffTestCase:
|
||||
def _assert_noerr(self, tmp_path: Path, im) -> None:
|
||||
def _assert_noerr(self, tmp_path: Path, im: Image.Image) -> None:
|
||||
"""Helper tests that assert basic sanity about the g4 tiff reading"""
|
||||
# 1 bit
|
||||
assert im.mode == "1"
|
||||
|
@ -140,7 +140,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
|
||||
|
||||
@pytest.mark.parametrize("legacy_api", (False, True))
|
||||
def test_write_metadata(self, legacy_api, tmp_path: Path) -> None:
|
||||
def test_write_metadata(self, legacy_api: bool, tmp_path: Path) -> None:
|
||||
"""Test metadata writing through libtiff"""
|
||||
f = str(tmp_path / "temp.tiff")
|
||||
with Image.open("Tests/images/hopper_g4.tif") as img:
|
||||
|
@ -243,7 +243,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
def test_custom_metadata(self, tmp_path: Path) -> None:
|
||||
tc = namedtuple("test_case", "value,type,supported_by_default")
|
||||
tc = namedtuple("tc", "value,type,supported_by_default")
|
||||
custom = {
|
||||
37000 + k: v
|
||||
for k, v in enumerate(
|
||||
|
@ -284,7 +284,9 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
for libtiff in libtiffs:
|
||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||
|
||||
def check_tags(tiffinfo) -> None:
|
||||
def check_tags(
|
||||
tiffinfo: TiffImagePlugin.ImageFileDirectory_v2 | dict[int, str]
|
||||
) -> None:
|
||||
im = hopper()
|
||||
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
@ -502,7 +504,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert_image_equal_tofile(im, out)
|
||||
|
||||
@pytest.mark.parametrize("im", (hopper("P"), Image.new("P", (1, 1), "#000")))
|
||||
def test_palette_save(self, im, tmp_path: Path) -> None:
|
||||
def test_palette_save(self, im: Image.Image, tmp_path: Path) -> None:
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
||||
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||
|
@ -514,7 +516,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert len(reloaded.tag_v2[320]) == 768
|
||||
|
||||
@pytest.mark.parametrize("compression", ("tiff_ccitt", "group3", "group4"))
|
||||
def test_bw_compression_w_rgb(self, compression, tmp_path: Path) -> None:
|
||||
def test_bw_compression_w_rgb(self, compression: str, tmp_path: Path) -> None:
|
||||
im = hopper("RGB")
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
||||
|
@ -647,7 +649,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
# Generate test image
|
||||
pilim = hopper()
|
||||
|
||||
def save_bytesio(compression=None) -> None:
|
||||
def save_bytesio(compression: str | None = None) -> None:
|
||||
buffer_io = io.BytesIO()
|
||||
pilim.save(buffer_io, format="tiff", compression=compression)
|
||||
buffer_io.seek(0)
|
||||
|
@ -731,7 +733,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert icc == icc_libtiff
|
||||
|
||||
def test_write_icc(self, tmp_path: Path) -> None:
|
||||
def check_write(libtiff) -> None:
|
||||
def check_write(libtiff: bool) -> None:
|
||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||
|
||||
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||
|
@ -837,7 +839,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert reloaded.mode == "F"
|
||||
assert reloaded.getexif()[SAMPLEFORMAT] == 3
|
||||
|
||||
def test_lzma(self, capfd):
|
||||
def test_lzma(self, capfd: pytest.CaptureFixture[str]) -> None:
|
||||
try:
|
||||
with Image.open("Tests/images/hopper_lzma.tif") as im:
|
||||
assert im.mode == "RGB"
|
||||
|
@ -853,7 +855,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
sys.stderr.write(captured.err)
|
||||
raise
|
||||
|
||||
def test_webp(self, capfd):
|
||||
def test_webp(self, capfd: pytest.CaptureFixture[str]) -> None:
|
||||
try:
|
||||
with Image.open("Tests/images/hopper_webp.tif") as im:
|
||||
assert im.mode == "RGB"
|
||||
|
@ -971,7 +973,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
|
||||
|
||||
@pytest.mark.parametrize("compression", (None, "jpeg"))
|
||||
def test_block_tile_tags(self, compression, tmp_path: Path) -> None:
|
||||
def test_block_tile_tags(self, compression: str | None, tmp_path: Path) -> None:
|
||||
im = hopper()
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
||||
|
@ -1020,7 +1022,9 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
),
|
||||
],
|
||||
)
|
||||
def test_wrong_bits_per_sample(self, file_name, mode, size, tile) -> None:
|
||||
def test_wrong_bits_per_sample(
|
||||
self, file_name: str, mode: str, size: tuple[int, int], tile
|
||||
) -> None:
|
||||
with Image.open("Tests/images/" + file_name) as im:
|
||||
assert im.mode == mode
|
||||
assert im.size == size
|
||||
|
@ -1086,7 +1090,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
TiffImagePlugin.READ_LIBTIFF = False
|
||||
|
||||
@pytest.mark.parametrize("compression", ("tiff_adobe_deflate", "jpeg"))
|
||||
def test_save_multistrip(self, compression, tmp_path: Path) -> None:
|
||||
def test_save_multistrip(self, compression: str, tmp_path: Path) -> None:
|
||||
im = hopper("RGB").resize((256, 256))
|
||||
out = str(tmp_path / "temp.tif")
|
||||
im.save(out, compression=compression)
|
||||
|
@ -1096,14 +1100,14 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert len(im.tag_v2[STRIPOFFSETS]) > 1
|
||||
|
||||
@pytest.mark.parametrize("argument", (True, False))
|
||||
def test_save_single_strip(self, argument, tmp_path: Path) -> None:
|
||||
def test_save_single_strip(self, argument: bool, tmp_path: Path) -> None:
|
||||
im = hopper("RGB").resize((256, 256))
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
||||
if not argument:
|
||||
TiffImagePlugin.STRIP_SIZE = 2**18
|
||||
try:
|
||||
arguments = {"compression": "tiff_adobe_deflate"}
|
||||
arguments: dict[str, str | int] = {"compression": "tiff_adobe_deflate"}
|
||||
if argument:
|
||||
arguments["strip_size"] = 2**18
|
||||
im.save(out, **arguments)
|
||||
|
@ -1114,7 +1118,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
TiffImagePlugin.STRIP_SIZE = 65536
|
||||
|
||||
@pytest.mark.parametrize("compression", ("tiff_adobe_deflate", None))
|
||||
def test_save_zero(self, compression, tmp_path: Path) -> None:
|
||||
def test_save_zero(self, compression: str | None, tmp_path: Path) -> None:
|
||||
im = Image.new("RGB", (0, 0))
|
||||
out = str(tmp_path / "temp.tif")
|
||||
with pytest.raises(SystemError):
|
||||
|
@ -1134,7 +1138,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
("Tests/images/child_ifd_jpeg.tiff", (20,)),
|
||||
),
|
||||
)
|
||||
def test_get_child_images(self, path, sizes) -> None:
|
||||
def test_get_child_images(self, path: str, sizes: tuple[int, ...]) -> None:
|
||||
with Image.open(path) as im:
|
||||
ims = im.get_child_images()
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import warnings
|
|||
import zlib
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -36,7 +37,7 @@ TEST_PNG_FILE = "Tests/images/hopper.png"
|
|||
MAGIC = PngImagePlugin._MAGIC
|
||||
|
||||
|
||||
def chunk(cid, *data):
|
||||
def chunk(cid: bytes, *data: bytes) -> bytes:
|
||||
test_file = BytesIO()
|
||||
PngImagePlugin.putchunk(*(test_file, cid) + data)
|
||||
return test_file.getvalue()
|
||||
|
@ -52,11 +53,11 @@ HEAD = MAGIC + IHDR
|
|||
TAIL = IDAT + IEND
|
||||
|
||||
|
||||
def load(data):
|
||||
def load(data: bytes) -> Image.Image:
|
||||
return Image.open(BytesIO(data))
|
||||
|
||||
|
||||
def roundtrip(im, **options):
|
||||
def roundtrip(im: Image.Image, **options: Any) -> Image.Image:
|
||||
out = BytesIO()
|
||||
im.save(out, "PNG", **options)
|
||||
out.seek(0)
|
||||
|
@ -65,7 +66,7 @@ def roundtrip(im, **options):
|
|||
|
||||
@skip_unless_feature("zlib")
|
||||
class TestFilePng:
|
||||
def get_chunks(self, filename):
|
||||
def get_chunks(self, filename: str) -> list[bytes]:
|
||||
chunks = []
|
||||
with open(filename, "rb") as fp:
|
||||
fp.read(8)
|
||||
|
@ -436,7 +437,7 @@ class TestFilePng:
|
|||
def test_unicode_text(self) -> None:
|
||||
# Check preservation of non-ASCII characters
|
||||
|
||||
def rt_text(value) -> None:
|
||||
def rt_text(value: str) -> None:
|
||||
im = Image.new("RGB", (32, 32))
|
||||
info = PngImagePlugin.PngInfo()
|
||||
info.add_text("Text", value)
|
||||
|
@ -636,7 +637,7 @@ class TestFilePng:
|
|||
@pytest.mark.parametrize(
|
||||
"cid", (b"IHDR", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT")
|
||||
)
|
||||
def test_truncated_chunks(self, cid) -> None:
|
||||
def test_truncated_chunks(self, cid: bytes) -> None:
|
||||
fp = BytesIO()
|
||||
with PngImagePlugin.PngStream(fp) as png:
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -755,7 +756,7 @@ class TestFilePng:
|
|||
im.seek(1)
|
||||
|
||||
@pytest.mark.parametrize("buffer", (True, False))
|
||||
def test_save_stdout(self, buffer) -> None:
|
||||
def test_save_stdout(self, buffer: bool) -> None:
|
||||
old_stdout = sys.stdout
|
||||
|
||||
if buffer:
|
||||
|
|
|
@ -11,10 +11,9 @@ class TestImagingPaste:
|
|||
masks = {}
|
||||
size = 128
|
||||
|
||||
def assert_9points_image(self, im, expected) -> None:
|
||||
expected = [
|
||||
point[0] if im.mode == "L" else point[: len(im.mode)] for point in expected
|
||||
]
|
||||
def assert_9points_image(
|
||||
self, im: Image.Image, expected: list[tuple[int, int, int, int]]
|
||||
) -> None:
|
||||
px = im.load()
|
||||
actual = [
|
||||
px[0, 0],
|
||||
|
@ -27,9 +26,17 @@ class TestImagingPaste:
|
|||
px[self.size // 2, self.size - 1],
|
||||
px[self.size - 1, self.size - 1],
|
||||
]
|
||||
assert actual == expected
|
||||
assert actual == [
|
||||
point[0] if im.mode == "L" else point[: len(im.mode)] for point in expected
|
||||
]
|
||||
|
||||
def assert_9points_paste(self, im, im2, mask, expected) -> None:
|
||||
def assert_9points_paste(
|
||||
self,
|
||||
im: Image.Image,
|
||||
im2: Image.Image,
|
||||
mask: Image.Image,
|
||||
expected: list[tuple[int, int, int, int]],
|
||||
) -> None:
|
||||
im3 = im.copy()
|
||||
im3.paste(im2, (0, 0), mask)
|
||||
self.assert_9points_image(im3, expected)
|
||||
|
@ -106,7 +113,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_image_solid(self, mode) -> None:
|
||||
def test_image_solid(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "red")
|
||||
im2 = getattr(self, "gradient_" + mode)
|
||||
|
||||
|
@ -116,7 +123,7 @@ class TestImagingPaste:
|
|||
assert_image_equal(im, im2)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_image_mask_1(self, mode) -> None:
|
||||
def test_image_mask_1(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "white")
|
||||
im2 = getattr(self, "gradient_" + mode)
|
||||
|
||||
|
@ -138,7 +145,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_image_mask_L(self, mode) -> None:
|
||||
def test_image_mask_L(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "white")
|
||||
im2 = getattr(self, "gradient_" + mode)
|
||||
|
||||
|
@ -160,7 +167,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_image_mask_LA(self, mode) -> None:
|
||||
def test_image_mask_LA(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "white")
|
||||
im2 = getattr(self, "gradient_" + mode)
|
||||
|
||||
|
@ -182,7 +189,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_image_mask_RGBA(self, mode) -> None:
|
||||
def test_image_mask_RGBA(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "white")
|
||||
im2 = getattr(self, "gradient_" + mode)
|
||||
|
||||
|
@ -204,7 +211,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_image_mask_RGBa(self, mode) -> None:
|
||||
def test_image_mask_RGBa(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "white")
|
||||
im2 = getattr(self, "gradient_" + mode)
|
||||
|
||||
|
@ -226,7 +233,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_color_solid(self, mode) -> None:
|
||||
def test_color_solid(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), "black")
|
||||
|
||||
rect = (12, 23, 128 + 12, 128 + 23)
|
||||
|
@ -239,7 +246,7 @@ class TestImagingPaste:
|
|||
assert sum(head[:255]) == 0
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_color_mask_1(self, mode) -> None:
|
||||
def test_color_mask_1(self, mode: str) -> None:
|
||||
im = Image.new(mode, (200, 200), (50, 60, 70, 80)[: len(mode)])
|
||||
color = (10, 20, 30, 40)[: len(mode)]
|
||||
|
||||
|
@ -261,7 +268,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_color_mask_L(self, mode) -> None:
|
||||
def test_color_mask_L(self, mode: str) -> None:
|
||||
im = getattr(self, "gradient_" + mode).copy()
|
||||
color = "white"
|
||||
|
||||
|
@ -283,7 +290,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_color_mask_RGBA(self, mode) -> None:
|
||||
def test_color_mask_RGBA(self, mode: str) -> None:
|
||||
im = getattr(self, "gradient_" + mode).copy()
|
||||
color = "white"
|
||||
|
||||
|
@ -305,7 +312,7 @@ class TestImagingPaste:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
|
||||
def test_color_mask_RGBa(self, mode) -> None:
|
||||
def test_color_mask_RGBa(self, mode: str) -> None:
|
||||
im = getattr(self, "gradient_" + mode).copy()
|
||||
color = "white"
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ gradients_image.load()
|
|||
((1, 3), (10, 4)),
|
||||
),
|
||||
)
|
||||
def test_args_factor(size, expected) -> None:
|
||||
def test_args_factor(size: int | tuple[int, int], expected: tuple[int, int]) -> None:
|
||||
im = Image.new("L", (10, 10))
|
||||
assert expected == im.reduce(size).size
|
||||
|
||||
|
@ -56,7 +56,7 @@ def test_args_factor(size, expected) -> None:
|
|||
@pytest.mark.parametrize(
|
||||
"size, expected_error", ((0, ValueError), (2.0, TypeError), ((0, 10), ValueError))
|
||||
)
|
||||
def test_args_factor_error(size, expected_error) -> None:
|
||||
def test_args_factor_error(size: float | tuple[int, int], expected_error) -> None:
|
||||
im = Image.new("L", (10, 10))
|
||||
with pytest.raises(expected_error):
|
||||
im.reduce(size)
|
||||
|
@ -69,7 +69,7 @@ def test_args_factor_error(size, expected_error) -> None:
|
|||
((5, 5, 6, 6), (1, 1)),
|
||||
),
|
||||
)
|
||||
def test_args_box(size, expected) -> None:
|
||||
def test_args_box(size: tuple[int, int, int, int], expected: tuple[int, int]) -> None:
|
||||
im = Image.new("L", (10, 10))
|
||||
assert expected == im.reduce(2, size).size
|
||||
|
||||
|
@ -86,20 +86,20 @@ def test_args_box(size, expected) -> None:
|
|||
((5, 0, 5, 10), ValueError),
|
||||
),
|
||||
)
|
||||
def test_args_box_error(size, expected_error) -> None:
|
||||
def test_args_box_error(size: str | tuple[int, int, int, int], expected_error) -> None:
|
||||
im = Image.new("L", (10, 10))
|
||||
with pytest.raises(expected_error):
|
||||
im.reduce(2, size).size
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("P", "1", "I;16"))
|
||||
def test_unsupported_modes(mode) -> None:
|
||||
def test_unsupported_modes(mode: str) -> None:
|
||||
im = Image.new("P", (10, 10))
|
||||
with pytest.raises(ValueError):
|
||||
im.reduce(3)
|
||||
|
||||
|
||||
def get_image(mode):
|
||||
def get_image(mode: str) -> Image.Image:
|
||||
mode_info = ImageMode.getmode(mode)
|
||||
if mode_info.basetype == "L":
|
||||
bands = [gradients_image]
|
||||
|
@ -119,7 +119,7 @@ def get_image(mode):
|
|||
return im.crop((0, 0, im.width, im.height - 5))
|
||||
|
||||
|
||||
def compare_reduce_with_box(im, factor) -> None:
|
||||
def compare_reduce_with_box(im: Image.Image, factor: int | tuple[int, int]) -> None:
|
||||
box = (11, 13, 146, 164)
|
||||
reduced = im.reduce(factor, box=box)
|
||||
reference = im.crop(box).reduce(factor)
|
||||
|
@ -127,7 +127,10 @@ def compare_reduce_with_box(im, factor) -> None:
|
|||
|
||||
|
||||
def compare_reduce_with_reference(
|
||||
im, factor, average_diff: float = 0.4, max_diff: int = 1
|
||||
im: Image.Image,
|
||||
factor: int | tuple[int, int],
|
||||
average_diff: float = 0.4,
|
||||
max_diff: int = 1,
|
||||
) -> None:
|
||||
"""Image.reduce() should look very similar to Image.resize(BOX).
|
||||
|
||||
|
@ -173,7 +176,9 @@ def compare_reduce_with_reference(
|
|||
assert_compare_images(reduced, reference, average_diff, max_diff)
|
||||
|
||||
|
||||
def assert_compare_images(a, b, max_average_diff, max_diff: int = 255) -> None:
|
||||
def assert_compare_images(
|
||||
a: Image.Image, b: Image.Image, max_average_diff: float, max_diff: int = 255
|
||||
) -> None:
|
||||
assert a.mode == b.mode, f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
|
||||
assert a.size == b.size, f"got size {repr(a.size)}, expected {repr(b.size)}"
|
||||
|
||||
|
@ -201,20 +206,20 @@ def assert_compare_images(a, b, max_average_diff, max_diff: int = 255) -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_L(factor) -> None:
|
||||
def test_mode_L(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("L")
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_LA(factor) -> None:
|
||||
def test_mode_LA(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("LA")
|
||||
compare_reduce_with_reference(im, factor, 0.8, 5)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_LA_opaque(factor) -> None:
|
||||
def test_mode_LA_opaque(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("LA")
|
||||
# With opaque alpha, an error should be way smaller.
|
||||
im.putalpha(Image.new("L", im.size, 255))
|
||||
|
@ -223,27 +228,27 @@ def test_mode_LA_opaque(factor) -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_La(factor) -> None:
|
||||
def test_mode_La(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("La")
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_RGB(factor) -> None:
|
||||
def test_mode_RGB(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("RGB")
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_RGBA(factor) -> None:
|
||||
def test_mode_RGBA(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("RGBA")
|
||||
compare_reduce_with_reference(im, factor, 0.8, 5)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_RGBA_opaque(factor) -> None:
|
||||
def test_mode_RGBA_opaque(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("RGBA")
|
||||
# With opaque alpha, an error should be way smaller.
|
||||
im.putalpha(Image.new("L", im.size, 255))
|
||||
|
@ -252,21 +257,21 @@ def test_mode_RGBA_opaque(factor) -> None:
|
|||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_RGBa(factor) -> None:
|
||||
def test_mode_RGBa(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("RGBa")
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_I(factor) -> None:
|
||||
def test_mode_I(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("I")
|
||||
compare_reduce_with_reference(im, factor)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("factor", remarkable_factors)
|
||||
def test_mode_F(factor) -> None:
|
||||
def test_mode_F(factor: int | tuple[int, int]) -> None:
|
||||
im = get_image("F")
|
||||
compare_reduce_with_reference(im, factor, 0, 0)
|
||||
compare_reduce_with_box(im, factor)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
from typing import Generator
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -51,7 +52,7 @@ class TestImagingResampleVulnerability:
|
|||
|
||||
|
||||
class TestImagingCoreResampleAccuracy:
|
||||
def make_case(self, mode, size, color):
|
||||
def make_case(self, mode: str, size: tuple[int, int], color: int) -> Image.Image:
|
||||
"""Makes a sample image with two dark and two bright squares.
|
||||
For example:
|
||||
e0 e0 1f 1f
|
||||
|
@ -66,7 +67,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
|
||||
return Image.merge(mode, [case] * len(mode))
|
||||
|
||||
def make_sample(self, data, size):
|
||||
def make_sample(self, data: str, size: tuple[int, int]) -> Image.Image:
|
||||
"""Restores a sample image from given data string which contains
|
||||
hex-encoded pixels from the top left fourth of a sample.
|
||||
"""
|
||||
|
@ -83,7 +84,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
s_px[size[0] - x - 1, y] = 255 - val
|
||||
return sample
|
||||
|
||||
def check_case(self, case, sample) -> None:
|
||||
def check_case(self, case: Image.Image, sample: Image.Image) -> None:
|
||||
s_px = sample.load()
|
||||
c_px = case.load()
|
||||
for y in range(case.size[1]):
|
||||
|
@ -95,7 +96,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
)
|
||||
assert s_px[x, y] == c_px[x, y], message
|
||||
|
||||
def serialize_image(self, image):
|
||||
def serialize_image(self, image: Image.Image) -> str:
|
||||
s_px = image.load()
|
||||
return "\n".join(
|
||||
" ".join(f"{s_px[x, y]:02x}" for x in range(image.size[0]))
|
||||
|
@ -103,7 +104,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
)
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_reduce_box(self, mode) -> None:
|
||||
def test_reduce_box(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (8, 8), 0xE1)
|
||||
case = case.resize((4, 4), Image.Resampling.BOX)
|
||||
# fmt: off
|
||||
|
@ -114,7 +115,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_reduce_bilinear(self, mode) -> None:
|
||||
def test_reduce_bilinear(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (8, 8), 0xE1)
|
||||
case = case.resize((4, 4), Image.Resampling.BILINEAR)
|
||||
# fmt: off
|
||||
|
@ -125,7 +126,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_reduce_hamming(self, mode) -> None:
|
||||
def test_reduce_hamming(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (8, 8), 0xE1)
|
||||
case = case.resize((4, 4), Image.Resampling.HAMMING)
|
||||
# fmt: off
|
||||
|
@ -136,7 +137,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_reduce_bicubic(self, mode) -> None:
|
||||
def test_reduce_bicubic(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (12, 12), 0xE1)
|
||||
case = case.resize((6, 6), Image.Resampling.BICUBIC)
|
||||
# fmt: off
|
||||
|
@ -148,7 +149,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (6, 6)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_reduce_lanczos(self, mode) -> None:
|
||||
def test_reduce_lanczos(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (16, 16), 0xE1)
|
||||
case = case.resize((8, 8), Image.Resampling.LANCZOS)
|
||||
# fmt: off
|
||||
|
@ -161,7 +162,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (8, 8)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_enlarge_box(self, mode) -> None:
|
||||
def test_enlarge_box(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (2, 2), 0xE1)
|
||||
case = case.resize((4, 4), Image.Resampling.BOX)
|
||||
# fmt: off
|
||||
|
@ -172,7 +173,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_enlarge_bilinear(self, mode) -> None:
|
||||
def test_enlarge_bilinear(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (2, 2), 0xE1)
|
||||
case = case.resize((4, 4), Image.Resampling.BILINEAR)
|
||||
# fmt: off
|
||||
|
@ -183,7 +184,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_enlarge_hamming(self, mode) -> None:
|
||||
def test_enlarge_hamming(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (2, 2), 0xE1)
|
||||
case = case.resize((4, 4), Image.Resampling.HAMMING)
|
||||
# fmt: off
|
||||
|
@ -194,7 +195,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (4, 4)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_enlarge_bicubic(self, mode) -> None:
|
||||
def test_enlarge_bicubic(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (4, 4), 0xE1)
|
||||
case = case.resize((8, 8), Image.Resampling.BICUBIC)
|
||||
# fmt: off
|
||||
|
@ -207,7 +208,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
self.check_case(channel, self.make_sample(data, (8, 8)))
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
|
||||
def test_enlarge_lanczos(self, mode) -> None:
|
||||
def test_enlarge_lanczos(self, mode: str) -> None:
|
||||
case = self.make_case(mode, (6, 6), 0xE1)
|
||||
case = case.resize((12, 12), Image.Resampling.LANCZOS)
|
||||
data = (
|
||||
|
@ -230,7 +231,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
|
||||
|
||||
class TestCoreResampleConsistency:
|
||||
def make_case(self, mode, fill):
|
||||
def make_case(self, mode: str, fill: tuple[int, int, int] | float):
|
||||
im = Image.new(mode, (512, 9), fill)
|
||||
return im.resize((9, 512), Image.Resampling.LANCZOS), im.load()[0, 0]
|
||||
|
||||
|
@ -265,7 +266,7 @@ class TestCoreResampleConsistency:
|
|||
|
||||
|
||||
class TestCoreResampleAlphaCorrect:
|
||||
def make_levels_case(self, mode):
|
||||
def make_levels_case(self, mode: str) -> Image.Image:
|
||||
i = Image.new(mode, (256, 16))
|
||||
px = i.load()
|
||||
for y in range(i.size[1]):
|
||||
|
@ -275,7 +276,7 @@ class TestCoreResampleAlphaCorrect:
|
|||
px[x, y] = tuple(pix)
|
||||
return i
|
||||
|
||||
def run_levels_case(self, i) -> None:
|
||||
def run_levels_case(self, i: Image.Image) -> None:
|
||||
px = i.load()
|
||||
for y in range(i.size[1]):
|
||||
used_colors = {px[x, y][0] for x in range(i.size[0])}
|
||||
|
@ -302,7 +303,9 @@ class TestCoreResampleAlphaCorrect:
|
|||
self.run_levels_case(case.resize((512, 32), Image.Resampling.BICUBIC))
|
||||
self.run_levels_case(case.resize((512, 32), Image.Resampling.LANCZOS))
|
||||
|
||||
def make_dirty_case(self, mode, clean_pixel, dirty_pixel):
|
||||
def make_dirty_case(
|
||||
self, mode: str, clean_pixel: tuple[int, ...], dirty_pixel: tuple[int, ...]
|
||||
) -> Image.Image:
|
||||
i = Image.new(mode, (64, 64), dirty_pixel)
|
||||
px = i.load()
|
||||
xdiv4 = i.size[0] // 4
|
||||
|
@ -312,7 +315,7 @@ class TestCoreResampleAlphaCorrect:
|
|||
px[x + xdiv4, y + ydiv4] = clean_pixel
|
||||
return i
|
||||
|
||||
def run_dirty_case(self, i, clean_pixel) -> None:
|
||||
def run_dirty_case(self, i: Image.Image, clean_pixel: tuple[int, ...]) -> None:
|
||||
px = i.load()
|
||||
for y in range(i.size[1]):
|
||||
for x in range(i.size[0]):
|
||||
|
@ -432,7 +435,7 @@ class TestCoreResampleBox:
|
|||
Image.Resampling.LANCZOS,
|
||||
),
|
||||
)
|
||||
def test_wrong_arguments(self, resample) -> None:
|
||||
def test_wrong_arguments(self, resample: Image.Resampling) -> None:
|
||||
im = hopper()
|
||||
im.resize((32, 32), resample, (0, 0, im.width, im.height))
|
||||
im.resize((32, 32), resample, (20, 20, im.width, im.height))
|
||||
|
@ -459,8 +462,12 @@ class TestCoreResampleBox:
|
|||
with pytest.raises(ValueError, match="can't exceed"):
|
||||
im.resize((32, 32), resample, (0, 0, im.width, im.height + 1))
|
||||
|
||||
def resize_tiled(self, im, dst_size, xtiles, ytiles):
|
||||
def split_range(size, tiles):
|
||||
def resize_tiled(
|
||||
self, im: Image.Image, dst_size: tuple[int, int], xtiles: int, ytiles: int
|
||||
) -> Image.Image:
|
||||
def split_range(
|
||||
size: int, tiles: int
|
||||
) -> Generator[tuple[int, int], None, None]:
|
||||
scale = size / tiles
|
||||
for i in range(tiles):
|
||||
yield int(round(scale * i)), int(round(scale * (i + 1)))
|
||||
|
@ -518,7 +525,7 @@ class TestCoreResampleBox:
|
|||
@pytest.mark.parametrize(
|
||||
"resample", (Image.Resampling.NEAREST, Image.Resampling.BILINEAR)
|
||||
)
|
||||
def test_formats(self, mode, resample) -> None:
|
||||
def test_formats(self, mode: str, resample: Image.Resampling) -> None:
|
||||
im = hopper(mode)
|
||||
box = (20, 20, im.size[0] - 20, im.size[1] - 20)
|
||||
with_box = im.resize((32, 32), resample, box)
|
||||
|
@ -558,7 +565,7 @@ class TestCoreResampleBox:
|
|||
@pytest.mark.parametrize(
|
||||
"flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC)
|
||||
)
|
||||
def test_skip_horizontal(self, flt) -> None:
|
||||
def test_skip_horizontal(self, flt: Image.Resampling) -> None:
|
||||
# Can skip resize for one dimension
|
||||
im = hopper()
|
||||
|
||||
|
@ -581,7 +588,7 @@ class TestCoreResampleBox:
|
|||
@pytest.mark.parametrize(
|
||||
"flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC)
|
||||
)
|
||||
def test_skip_vertical(self, flt) -> None:
|
||||
def test_skip_vertical(self, flt: Image.Resampling) -> None:
|
||||
# Can skip resize for one dimension
|
||||
im = hopper()
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@ import pytest
|
|||
from PIL import Image, ImageMath
|
||||
|
||||
|
||||
def pixel(im):
|
||||
if hasattr(im, "im"):
|
||||
return f"{im.mode} {repr(im.getpixel((0, 0)))}"
|
||||
def pixel(im: Image.Image | int) -> str | int:
|
||||
if isinstance(im, int):
|
||||
return int(im) # hack to deal with booleans
|
||||
else:
|
||||
return f"{im.mode} {repr(im.getpixel((0, 0)))}"
|
||||
|
||||
|
||||
A = Image.new("L", (1, 1), 1)
|
||||
|
@ -60,7 +60,7 @@ def test_ops() -> None:
|
|||
"(lambda: (lambda: exec('pass'))())()",
|
||||
),
|
||||
)
|
||||
def test_prevent_exec(expression) -> None:
|
||||
def test_prevent_exec(expression: str) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
ImageMath.eval(expression)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user