mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	Merge pull request #7794 from radarhere/type_hints
Added type hints to additional tests
This commit is contained in:
		
						commit
						50e9a92c98
					
				| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from array import array
 | 
			
		||||
from types import ModuleType
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +9,7 @@ from PIL import Image, ImageFilter
 | 
			
		|||
 | 
			
		||||
from .helper import assert_image_equal
 | 
			
		||||
 | 
			
		||||
numpy: ModuleType | None
 | 
			
		||||
try:
 | 
			
		||||
    import numpy
 | 
			
		||||
except ImportError:
 | 
			
		||||
| 
						 | 
				
			
			@ -397,6 +399,7 @@ class TestColorLut3DFilter:
 | 
			
		|||
 | 
			
		||||
    @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
 | 
			
		||||
    def test_numpy_sources(self) -> None:
 | 
			
		||||
        assert numpy is not None
 | 
			
		||||
        table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16)
 | 
			
		||||
        with pytest.raises(ValueError, match="should have either channels"):
 | 
			
		||||
            lut = ImageFilter.Color3DLUT((5, 6, 7), table)
 | 
			
		||||
| 
						 | 
				
			
			@ -430,6 +433,7 @@ class TestColorLut3DFilter:
 | 
			
		|||
 | 
			
		||||
    @pytest.mark.skipif(numpy is None, reason="NumPy not installed")
 | 
			
		||||
    def test_numpy_formats(self) -> None:
 | 
			
		||||
        assert numpy is not None
 | 
			
		||||
        g = Image.linear_gradient("L")
 | 
			
		||||
        im = Image.merge(
 | 
			
		||||
            "RGB",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -187,6 +187,6 @@ class TestEnvVars:
 | 
			
		|||
            {"PILLOW_BLOCKS_MAX": "wat"},
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
    def test_warnings(self, var) -> None:
 | 
			
		||||
    def test_warnings(self, var: dict[str, str]) -> None:
 | 
			
		||||
        with pytest.warns(UserWarning):
 | 
			
		||||
            Image._apply_env_variables(var)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds"
 | 
			
		|||
        TEST_FILE_DX10_BC1_TYPELESS,
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_sanity_dxt1_bc1(image_path) -> None:
 | 
			
		||||
def test_sanity_dxt1_bc1(image_path: str) -> None:
 | 
			
		||||
    """Check DXT1 and BC1 images can be opened"""
 | 
			
		||||
    with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
 | 
			
		||||
        target = target.convert("RGBA")
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ def test_sanity_dxt5() -> None:
 | 
			
		|||
        TEST_FILE_BC4U,
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_sanity_ati1_bc4u(image_path) -> None:
 | 
			
		||||
def test_sanity_ati1_bc4u(image_path: str) -> None:
 | 
			
		||||
    """Check ATI1 and BC4U images can be opened"""
 | 
			
		||||
 | 
			
		||||
    with Image.open(image_path) as im:
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +117,7 @@ def test_sanity_ati1_bc4u(image_path) -> None:
 | 
			
		|||
        TEST_FILE_DX10_BC4_TYPELESS,
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_dx10_bc4(image_path) -> None:
 | 
			
		||||
def test_dx10_bc4(image_path: str) -> None:
 | 
			
		||||
    """Check DX10 BC4 images can be opened"""
 | 
			
		||||
 | 
			
		||||
    with Image.open(image_path) as im:
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +138,7 @@ def test_dx10_bc4(image_path) -> None:
 | 
			
		|||
        TEST_FILE_BC5U,
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_sanity_ati2_bc5u(image_path) -> None:
 | 
			
		||||
def test_sanity_ati2_bc5u(image_path: str) -> None:
 | 
			
		||||
    """Check ATI2 and BC5U images can be opened"""
 | 
			
		||||
 | 
			
		||||
    with Image.open(image_path) as im:
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +162,7 @@ def test_sanity_ati2_bc5u(image_path) -> None:
 | 
			
		|||
        (TEST_FILE_BC5S, TEST_FILE_BC5S),
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_dx10_bc5(image_path, expected_path) -> None:
 | 
			
		||||
def test_dx10_bc5(image_path: str, expected_path: str) -> None:
 | 
			
		||||
    """Check DX10 BC5 images can be opened"""
 | 
			
		||||
 | 
			
		||||
    with Image.open(image_path) as im:
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +176,7 @@ def test_dx10_bc5(image_path, expected_path) -> None:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize("image_path", (TEST_FILE_BC6H, TEST_FILE_BC6HS))
 | 
			
		||||
def test_dx10_bc6h(image_path) -> None:
 | 
			
		||||
def test_dx10_bc6h(image_path: str) -> None:
 | 
			
		||||
    """Check DX10 BC6H/BC6HS images can be opened"""
 | 
			
		||||
 | 
			
		||||
    with Image.open(image_path) as im:
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +257,7 @@ def test_dx10_r8g8b8a8_unorm_srgb() -> None:
 | 
			
		|||
        ("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA),
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
def test_uncompressed(mode, size, test_file) -> None:
 | 
			
		||||
def test_uncompressed(mode: str, size: tuple[int, int], test_file: str) -> None:
 | 
			
		||||
    """Check uncompressed images can be opened"""
 | 
			
		||||
 | 
			
		||||
    with Image.open(test_file) as im:
 | 
			
		||||
| 
						 | 
				
			
			@ -359,7 +359,7 @@ def test_unsupported_bitcount() -> None:
 | 
			
		|||
        "Tests/images/unimplemented_pfflags.dds",
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_not_implemented(test_file) -> None:
 | 
			
		||||
def test_not_implemented(test_file: str) -> None:
 | 
			
		||||
    with pytest.raises(NotImplementedError):
 | 
			
		||||
        with Image.open(test_file):
 | 
			
		||||
            pass
 | 
			
		||||
| 
						 | 
				
			
			@ -381,7 +381,7 @@ def test_save_unsupported_mode(tmp_path: Path) -> None:
 | 
			
		|||
        ("RGBA", "Tests/images/pil123rgba.png"),
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
def test_save(mode, test_file, tmp_path: Path) -> None:
 | 
			
		||||
def test_save(mode: str, test_file: str, tmp_path: Path) -> None:
 | 
			
		||||
    out = str(tmp_path / "temp.dds")
 | 
			
		||||
    with Image.open(test_file) as im:
 | 
			
		||||
        assert im.mode == mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ def test_seek() -> None:
 | 
			
		|||
    ],
 | 
			
		||||
)
 | 
			
		||||
@pytest.mark.timeout(timeout=3)
 | 
			
		||||
def test_timeouts(test_file) -> None:
 | 
			
		||||
def test_timeouts(test_file: str) -> None:
 | 
			
		||||
    with open(test_file, "rb") as f:
 | 
			
		||||
        with Image.open(f) as im:
 | 
			
		||||
            with pytest.raises(OSError):
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +160,7 @@ def test_timeouts(test_file) -> None:
 | 
			
		|||
        "Tests/images/crash-5762152299364352.fli",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
def test_crash(test_file) -> None:
 | 
			
		||||
def test_crash(test_file: str) -> None:
 | 
			
		||||
    with open(test_file, "rb") as f:
 | 
			
		||||
        with Image.open(f) as im:
 | 
			
		||||
            with pytest.raises(OSError):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import IO
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -55,15 +56,15 @@ def test_handler(tmp_path: Path) -> None:
 | 
			
		|||
        loaded = False
 | 
			
		||||
        saved = False
 | 
			
		||||
 | 
			
		||||
        def open(self, im) -> None:
 | 
			
		||||
        def open(self, im: Image.Image) -> None:
 | 
			
		||||
            self.opened = True
 | 
			
		||||
 | 
			
		||||
        def load(self, im):
 | 
			
		||||
        def load(self, im: Image.Image) -> Image.Image:
 | 
			
		||||
            self.loaded = True
 | 
			
		||||
            im.fp.close()
 | 
			
		||||
            return Image.new("RGB", (1, 1))
 | 
			
		||||
 | 
			
		||||
        def save(self, im, fp, filename) -> None:
 | 
			
		||||
        def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
 | 
			
		||||
            self.saved = True
 | 
			
		||||
 | 
			
		||||
    handler = TestHandler()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import IO
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,15 +57,15 @@ def test_handler(tmp_path: Path) -> None:
 | 
			
		|||
        loaded = False
 | 
			
		||||
        saved = False
 | 
			
		||||
 | 
			
		||||
        def open(self, im) -> None:
 | 
			
		||||
        def open(self, im: Image.Image) -> None:
 | 
			
		||||
            self.opened = True
 | 
			
		||||
 | 
			
		||||
        def load(self, im):
 | 
			
		||||
        def load(self, im: Image.Image) -> Image.Image:
 | 
			
		||||
            self.loaded = True
 | 
			
		||||
            im.fp.close()
 | 
			
		||||
            return Image.new("RGB", (1, 1))
 | 
			
		||||
 | 
			
		||||
        def save(self, im, fp, filename) -> None:
 | 
			
		||||
        def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
 | 
			
		||||
            self.saved = True
 | 
			
		||||
 | 
			
		||||
    handler = TestHandler()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import re
 | 
			
		|||
import warnings
 | 
			
		||||
from io import BytesIO
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from types import ModuleType
 | 
			
		||||
from typing import Any
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +34,7 @@ from .helper import (
 | 
			
		|||
    skip_unless_feature,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
ElementTree: ModuleType | None
 | 
			
		||||
try:
 | 
			
		||||
    from defusedxml import ElementTree
 | 
			
		||||
except ImportError:
 | 
			
		||||
| 
						 | 
				
			
			@ -440,25 +442,25 @@ class TestFileJpeg:
 | 
			
		|||
        for subsampling in (-1, 3):  # (default, invalid)
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling)
 | 
			
		||||
            assert getsampling(im) == (2, 2, 1, 1, 1, 1)
 | 
			
		||||
        for subsampling in (0, "4:4:4"):
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling)
 | 
			
		||||
        for subsampling1 in (0, "4:4:4"):
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling1)
 | 
			
		||||
            assert getsampling(im) == (1, 1, 1, 1, 1, 1)
 | 
			
		||||
        for subsampling in (1, "4:2:2"):
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling)
 | 
			
		||||
        for subsampling1 in (1, "4:2:2"):
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling1)
 | 
			
		||||
            assert getsampling(im) == (2, 1, 1, 1, 1, 1)
 | 
			
		||||
        for subsampling in (2, "4:2:0", "4:1:1"):
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling)
 | 
			
		||||
        for subsampling1 in (2, "4:2:0", "4:1:1"):
 | 
			
		||||
            im = self.roundtrip(hopper(), subsampling=subsampling1)
 | 
			
		||||
            assert getsampling(im) == (2, 2, 1, 1, 1, 1)
 | 
			
		||||
 | 
			
		||||
        # RGB colorspace
 | 
			
		||||
        for subsampling in (-1, 0, "4:4:4"):
 | 
			
		||||
        for subsampling1 in (-1, 0, "4:4:4"):
 | 
			
		||||
            # "4:4:4" doesn't really make sense for RGB, but the conversion
 | 
			
		||||
            # to an integer happens at a higher level
 | 
			
		||||
            im = self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
 | 
			
		||||
            im = self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling1)
 | 
			
		||||
            assert getsampling(im) == (1, 1, 1, 1, 1, 1)
 | 
			
		||||
        for subsampling in (1, "4:2:2", 2, "4:2:0", 3):
 | 
			
		||||
        for subsampling1 in (1, "4:2:2", 2, "4:2:0", 3):
 | 
			
		||||
            with pytest.raises(OSError):
 | 
			
		||||
                self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
 | 
			
		||||
                self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling1)
 | 
			
		||||
 | 
			
		||||
        with pytest.raises(TypeError):
 | 
			
		||||
            self.roundtrip(hopper(), subsampling="1:1:1")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ from PIL import Image
 | 
			
		|||
from .helper import assert_image_equal, hopper, magick_command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def helper_save_as_palm(tmp_path: Path, mode) -> None:
 | 
			
		||||
def helper_save_as_palm(tmp_path: Path, mode: str) -> None:
 | 
			
		||||
    # Arrange
 | 
			
		||||
    im = hopper(mode)
 | 
			
		||||
    outfile = str(tmp_path / ("temp_" + mode + ".palm"))
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ def helper_save_as_palm(tmp_path: Path, mode) -> None:
 | 
			
		|||
    assert os.path.getsize(outfile) > 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def open_with_magick(magick, tmp_path: Path, f):
 | 
			
		||||
def open_with_magick(magick: list[str], tmp_path: Path, f: str) -> Image.Image:
 | 
			
		||||
    outfile = str(tmp_path / "temp.png")
 | 
			
		||||
    rc = subprocess.call(
 | 
			
		||||
        magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ def open_with_magick(magick, tmp_path: Path, f):
 | 
			
		|||
    return Image.open(outfile)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def roundtrip(tmp_path: Path, mode) -> None:
 | 
			
		||||
def roundtrip(tmp_path: Path, mode: str) -> None:
 | 
			
		||||
    magick = magick_command()
 | 
			
		||||
    if not magick:
 | 
			
		||||
        return
 | 
			
		||||
| 
						 | 
				
			
			@ -66,6 +66,6 @@ def test_p_mode(tmp_path: Path) -> None:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize("mode", ("L", "RGB"))
 | 
			
		||||
def test_oserror(tmp_path: Path, mode) -> None:
 | 
			
		||||
def test_oserror(tmp_path: Path, mode: str) -> None:
 | 
			
		||||
    with pytest.raises(OSError):
 | 
			
		||||
        helper_save_as_palm(tmp_path, mode)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ TEST_TAR_FILE = "Tests/images/hopper.tar"
 | 
			
		|||
        ("jpg", "hopper.jpg", "JPEG"),
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_sanity(codec, test_path, format) -> None:
 | 
			
		||||
def test_sanity(codec: str, test_path: str, format: str) -> None:
 | 
			
		||||
    if features.check(codec):
 | 
			
		||||
        with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
 | 
			
		||||
            with Image.open(tar) as im:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ from __future__ import annotations
 | 
			
		|||
 | 
			
		||||
from io import BytesIO
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from types import ModuleType
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,7 @@ pytestmark = [
 | 
			
		|||
    skip_unless_feature("webp_mux"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
ElementTree: ModuleType | None
 | 
			
		||||
try:
 | 
			
		||||
    from defusedxml import ElementTree
 | 
			
		||||
except ImportError:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import sys
 | 
			
		|||
import tempfile
 | 
			
		||||
import warnings
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import IO
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,11 +62,11 @@ class TestImage:
 | 
			
		|||
            "HSV",
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
    def test_image_modes_success(self, mode) -> None:
 | 
			
		||||
    def test_image_modes_success(self, mode: str) -> None:
 | 
			
		||||
        Image.new(mode, (1, 1))
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("mode", ("", "bad", "very very long"))
 | 
			
		||||
    def test_image_modes_fail(self, mode) -> None:
 | 
			
		||||
    def test_image_modes_fail(self, mode: str) -> None:
 | 
			
		||||
        with pytest.raises(ValueError) as e:
 | 
			
		||||
            Image.new(mode, (1, 1))
 | 
			
		||||
        assert str(e.value) == "unrecognized image mode"
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +101,7 @@ class TestImage:
 | 
			
		|||
 | 
			
		||||
    def test_repr_pretty(self) -> None:
 | 
			
		||||
        class Pretty:
 | 
			
		||||
            def text(self, text) -> None:
 | 
			
		||||
            def text(self, text: str) -> None:
 | 
			
		||||
                self.pretty_output = text
 | 
			
		||||
 | 
			
		||||
        im = Image.new("L", (100, 100))
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +183,9 @@ class TestImage:
 | 
			
		|||
        temp_file = str(tmp_path / "temp.jpg")
 | 
			
		||||
 | 
			
		||||
        class FP:
 | 
			
		||||
            def write(self, b) -> None:
 | 
			
		||||
            name: str
 | 
			
		||||
 | 
			
		||||
            def write(self, b: bytes) -> None:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
        fp = FP()
 | 
			
		||||
| 
						 | 
				
			
			@ -536,7 +539,7 @@ class TestImage:
 | 
			
		|||
        "PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower"
 | 
			
		||||
    )
 | 
			
		||||
    @pytest.mark.parametrize("size", ((0, 100000000), (100000000, 0)))
 | 
			
		||||
    def test_empty_image(self, size) -> None:
 | 
			
		||||
    def test_empty_image(self, size: tuple[int, int]) -> None:
 | 
			
		||||
        Image.new("RGB", size)
 | 
			
		||||
 | 
			
		||||
    def test_storage_neg(self) -> None:
 | 
			
		||||
| 
						 | 
				
			
			@ -563,7 +566,7 @@ class TestImage:
 | 
			
		|||
            Image.linear_gradient(wrong_mode)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
 | 
			
		||||
    def test_linear_gradient(self, mode) -> None:
 | 
			
		||||
    def test_linear_gradient(self, mode: str) -> None:
 | 
			
		||||
        # Arrange
 | 
			
		||||
        target_file = "Tests/images/linear_gradient.png"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -588,7 +591,7 @@ class TestImage:
 | 
			
		|||
            Image.radial_gradient(wrong_mode)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
 | 
			
		||||
    def test_radial_gradient(self, mode) -> None:
 | 
			
		||||
    def test_radial_gradient(self, mode: str) -> None:
 | 
			
		||||
        # Arrange
 | 
			
		||||
        target_file = "Tests/images/radial_gradient.png"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -663,7 +666,11 @@ class TestImage:
 | 
			
		|||
        blank_p.palette = None
 | 
			
		||||
        blank_pa.palette = None
 | 
			
		||||
 | 
			
		||||
        def _make_new(base_image, image, palette_result=None) -> None:
 | 
			
		||||
        def _make_new(
 | 
			
		||||
            base_image: Image.Image,
 | 
			
		||||
            image: Image.Image,
 | 
			
		||||
            palette_result: ImagePalette.ImagePalette | None = None,
 | 
			
		||||
        ) -> None:
 | 
			
		||||
            new_image = base_image._new(image.im)
 | 
			
		||||
            assert new_image.mode == image.mode
 | 
			
		||||
            assert new_image.size == image.size
 | 
			
		||||
| 
						 | 
				
			
			@ -711,7 +718,7 @@ class TestImage:
 | 
			
		|||
    def test_load_on_nonexclusive_multiframe(self) -> None:
 | 
			
		||||
        with open("Tests/images/frozenpond.mpo", "rb") as fp:
 | 
			
		||||
 | 
			
		||||
            def act(fp) -> None:
 | 
			
		||||
            def act(fp: IO[bytes]) -> None:
 | 
			
		||||
                im = Image.open(fp)
 | 
			
		||||
                im.load()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -904,12 +911,12 @@ class TestImage:
 | 
			
		|||
                assert exif.get_ifd(0xA005)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
 | 
			
		||||
    def test_zero_tobytes(self, size) -> None:
 | 
			
		||||
    def test_zero_tobytes(self, size: tuple[int, int]) -> None:
 | 
			
		||||
        im = Image.new("RGB", size)
 | 
			
		||||
        assert im.tobytes() == b""
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
 | 
			
		||||
    def test_zero_frombytes(self, size) -> None:
 | 
			
		||||
    def test_zero_frombytes(self, size: tuple[int, int]) -> None:
 | 
			
		||||
        Image.frombytes("RGB", size, b"")
 | 
			
		||||
 | 
			
		||||
        im = Image.new("RGB", size)
 | 
			
		||||
| 
						 | 
				
			
			@ -994,7 +1001,7 @@ class TestImage:
 | 
			
		|||
            "01r_00.pcx",
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
    def test_overrun(self, path) -> None:
 | 
			
		||||
    def test_overrun(self, path: str) -> None:
 | 
			
		||||
        """For overrun completeness, test as:
 | 
			
		||||
        valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -1021,7 +1028,7 @@ class TestImage:
 | 
			
		|||
            pass
 | 
			
		||||
        assert not hasattr(im, "fp")
 | 
			
		||||
 | 
			
		||||
    def test_close_graceful(self, caplog) -> None:
 | 
			
		||||
    def test_close_graceful(self, caplog: pytest.LogCaptureFixture) -> None:
 | 
			
		||||
        with Image.open("Tests/images/hopper.jpg") as im:
 | 
			
		||||
            copy = im.copy()
 | 
			
		||||
            with caplog.at_level(logging.DEBUG):
 | 
			
		||||
| 
						 | 
				
			
			@ -1032,10 +1039,10 @@ class TestImage:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class MockEncoder:
 | 
			
		||||
    pass
 | 
			
		||||
    args: tuple[str, ...]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def mock_encode(*args):
 | 
			
		||||
def mock_encode(*args: str) -> MockEncoder:
 | 
			
		||||
    encoder = MockEncoder()
 | 
			
		||||
    encoder.args = args
 | 
			
		||||
    return encoder
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -208,7 +208,9 @@ def test_language() -> None:
 | 
			
		|||
    ),
 | 
			
		||||
    ids=("None", "ltr", "rtl2", "rtl", "ttb"),
 | 
			
		||||
)
 | 
			
		||||
def test_getlength(mode, text, direction, expected) -> None:
 | 
			
		||||
def test_getlength(
 | 
			
		||||
    mode: str, text: str, direction: str | None, expected: float
 | 
			
		||||
) -> None:
 | 
			
		||||
    ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
 | 
			
		||||
    im = Image.new(mode, (1, 1), 0)
 | 
			
		||||
    d = ImageDraw.Draw(im)
 | 
			
		||||
| 
						 | 
				
			
			@ -230,7 +232,7 @@ def test_getlength(mode, text, direction, expected) -> None:
 | 
			
		|||
    ("i" + ("\u030C" * 15) + "i", "i" + "\u032C" * 15 + "i", "\u035Cii", "i\u0305i"),
 | 
			
		||||
    ids=("caron-above", "caron-below", "double-breve", "overline"),
 | 
			
		||||
)
 | 
			
		||||
def test_getlength_combine(mode, direction, text) -> None:
 | 
			
		||||
def test_getlength_combine(mode: str, direction: str, text: str) -> None:
 | 
			
		||||
    if text == "i\u0305i" and direction == "ttb":
 | 
			
		||||
        pytest.skip("fails with this font")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +252,7 @@ def test_getlength_combine(mode, direction, text) -> None:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm"))
 | 
			
		||||
def test_anchor_ttb(anchor) -> None:
 | 
			
		||||
def test_anchor_ttb(anchor: str) -> None:
 | 
			
		||||
    text = "f"
 | 
			
		||||
    path = f"Tests/images/test_anchor_ttb_{text}_{anchor}.png"
 | 
			
		||||
    f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120)
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +308,9 @@ combine_tests = (
 | 
			
		|||
@pytest.mark.parametrize(
 | 
			
		||||
    "name, text, anchor, dir, epsilon", combine_tests, ids=[r[0] for r in combine_tests]
 | 
			
		||||
)
 | 
			
		||||
def test_combine(name, text, dir, anchor, epsilon) -> None:
 | 
			
		||||
def test_combine(
 | 
			
		||||
    name: str, text: str, dir: str | None, anchor: str | None, epsilon: float
 | 
			
		||||
) -> None:
 | 
			
		||||
    path = f"Tests/images/test_combine_{name}.png"
 | 
			
		||||
    f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 48)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -337,7 +341,7 @@ def test_combine(name, text, dir, anchor, epsilon) -> None:
 | 
			
		|||
        ("rm", "right"),  # pass with getsize
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
def test_combine_multiline(anchor, align) -> None:
 | 
			
		||||
def test_combine_multiline(anchor: str, align: str) -> None:
 | 
			
		||||
    # test that multiline text uses getlength, not getsize or getbbox
 | 
			
		||||
 | 
			
		||||
    path = f"Tests/images/test_combine_multiline_{anchor}_{align}.png"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ from PIL import Image, ImageMorph, _imagingmorph
 | 
			
		|||
from .helper import assert_image_equal_tofile, hopper
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def string_to_img(image_string):
 | 
			
		||||
def string_to_img(image_string: str) -> Image.Image:
 | 
			
		||||
    """Turn a string image representation into a binary image"""
 | 
			
		||||
    rows = [s for s in image_string.replace(" ", "").split("\n") if len(s)]
 | 
			
		||||
    height = len(rows)
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ A = string_to_img(
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def img_to_string(im):
 | 
			
		||||
def img_to_string(im: Image.Image) -> str:
 | 
			
		||||
    """Turn a (small) binary image into a string representation"""
 | 
			
		||||
    chars = ".1"
 | 
			
		||||
    width, height = im.size
 | 
			
		||||
| 
						 | 
				
			
			@ -48,11 +48,11 @@ def img_to_string(im):
 | 
			
		|||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def img_string_normalize(im):
 | 
			
		||||
def img_string_normalize(im: str) -> str:
 | 
			
		||||
    return img_to_string(string_to_img(im))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def assert_img_equal_img_string(a, b_string) -> None:
 | 
			
		||||
def assert_img_equal_img_string(a: Image.Image, b_string: str) -> None:
 | 
			
		||||
    assert img_to_string(a) == img_string_normalize(b_string)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ def test_str_to_img() -> None:
 | 
			
		|||
@pytest.mark.parametrize(
 | 
			
		||||
    "op", ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge")
 | 
			
		||||
)
 | 
			
		||||
def test_lut(op) -> None:
 | 
			
		||||
def test_lut(op: str) -> None:
 | 
			
		||||
    lb = ImageMorph.LutBuilder(op_name=op)
 | 
			
		||||
    assert lb.get_lut() is None
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ def test_getcolor_rgba_color_rgb_palette() -> None:
 | 
			
		|||
        (255, ImagePalette.ImagePalette("RGB", list(range(256)) * 3)),
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
def test_getcolor_not_special(index, palette) -> None:
 | 
			
		||||
def test_getcolor_not_special(index: int, palette: ImagePalette.ImagePalette) -> None:
 | 
			
		||||
    im = Image.new("P", (1, 1))
 | 
			
		||||
 | 
			
		||||
    # Do not use transparency index as a new color
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,9 @@ FONT_SIZE = 20
 | 
			
		|||
FONT_PATH = "Tests/fonts/DejaVuSans/DejaVuSans.ttf"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def helper_pickle_file(tmp_path: Path, pickle, protocol, test_file, mode) -> None:
 | 
			
		||||
def helper_pickle_file(
 | 
			
		||||
    tmp_path: Path, protocol: int, test_file: str, mode: str | None
 | 
			
		||||
) -> None:
 | 
			
		||||
    # Arrange
 | 
			
		||||
    with Image.open(test_file) as im:
 | 
			
		||||
        filename = str(tmp_path / "temp.pkl")
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +32,7 @@ def helper_pickle_file(tmp_path: Path, pickle, protocol, test_file, mode) -> Non
 | 
			
		|||
        assert im == loaded_im
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def helper_pickle_string(pickle, protocol, test_file, mode) -> None:
 | 
			
		||||
def helper_pickle_string(protocol: int, test_file: str, mode: str | None) -> None:
 | 
			
		||||
    with Image.open(test_file) as im:
 | 
			
		||||
        if mode:
 | 
			
		||||
            im = im.convert(mode)
 | 
			
		||||
| 
						 | 
				
			
			@ -64,10 +66,12 @@ def helper_pickle_string(pickle, protocol, test_file, mode) -> None:
 | 
			
		|||
    ],
 | 
			
		||||
)
 | 
			
		||||
@pytest.mark.parametrize("protocol", range(0, pickle.HIGHEST_PROTOCOL + 1))
 | 
			
		||||
def test_pickle_image(tmp_path: Path, test_file, test_mode, protocol) -> None:
 | 
			
		||||
def test_pickle_image(
 | 
			
		||||
    tmp_path: Path, test_file: str, test_mode: str | None, protocol: int
 | 
			
		||||
) -> None:
 | 
			
		||||
    # Act / Assert
 | 
			
		||||
    helper_pickle_string(pickle, protocol, test_file, test_mode)
 | 
			
		||||
    helper_pickle_file(tmp_path, pickle, protocol, test_file, test_mode)
 | 
			
		||||
    helper_pickle_string(protocol, test_file, test_mode)
 | 
			
		||||
    helper_pickle_file(tmp_path, protocol, test_file, test_mode)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_pickle_la_mode_with_palette(tmp_path: Path) -> None:
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +103,9 @@ def test_pickle_tell() -> None:
 | 
			
		|||
    assert unpickled_image.tell() == 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def helper_assert_pickled_font_images(font1, font2) -> None:
 | 
			
		||||
def helper_assert_pickled_font_images(
 | 
			
		||||
    font1: ImageFont.FreeTypeFont, font2: ImageFont.FreeTypeFont
 | 
			
		||||
) -> None:
 | 
			
		||||
    # Arrange
 | 
			
		||||
    im1 = Image.new(mode="RGBA", size=(300, 100))
 | 
			
		||||
    im2 = Image.new(mode="RGBA", size=(300, 100))
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +123,7 @@ def helper_assert_pickled_font_images(font1, font2) -> None:
 | 
			
		|||
 | 
			
		||||
@skip_unless_feature("freetype2")
 | 
			
		||||
@pytest.mark.parametrize("protocol", list(range(0, pickle.HIGHEST_PROTOCOL + 1)))
 | 
			
		||||
def test_pickle_font_string(protocol) -> None:
 | 
			
		||||
def test_pickle_font_string(protocol: int) -> None:
 | 
			
		||||
    # Arrange
 | 
			
		||||
    font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +137,7 @@ def test_pickle_font_string(protocol) -> None:
 | 
			
		|||
 | 
			
		||||
@skip_unless_feature("freetype2")
 | 
			
		||||
@pytest.mark.parametrize("protocol", list(range(0, pickle.HIGHEST_PROTOCOL + 1)))
 | 
			
		||||
def test_pickle_font_file(tmp_path: Path, protocol) -> None:
 | 
			
		||||
def test_pickle_font_file(tmp_path: Path, protocol: int) -> None:
 | 
			
		||||
    # Arrange
 | 
			
		||||
    font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
 | 
			
		||||
    filename = str(tmp_path / "temp.pkl")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ import pytest
 | 
			
		|||
from PIL import Image, PSDraw
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _create_document(ps) -> None:
 | 
			
		||||
def _create_document(ps: PSDraw.PSDraw) -> None:
 | 
			
		||||
    title = "hopper"
 | 
			
		||||
    box = (1 * 72, 2 * 72, 7 * 72, 10 * 72)  # in points
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ def test_draw_postscript(tmp_path: Path) -> None:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize("buffer", (True, False))
 | 
			
		||||
def test_stdout(buffer) -> None:
 | 
			
		||||
def test_stdout(buffer: bool) -> None:
 | 
			
		||||
    # Temporarily redirect stdout
 | 
			
		||||
    old_stdout = sys.stdout
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ from PIL import Image
 | 
			
		|||
        "Tests/images/crash-db8bfa78b19721225425530c5946217720d7df4e.sgi",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
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:
 | 
			
		||||
            with pytest.raises(OSError):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ from __future__ import annotations
 | 
			
		|||
 | 
			
		||||
import shutil
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from typing import Callable
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +18,12 @@ test_filenames = ("temp_';", 'temp_";', "temp_'\"|", "temp_'\"||", "temp_'\"&&")
 | 
			
		|||
 | 
			
		||||
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
 | 
			
		||||
class TestShellInjection:
 | 
			
		||||
    def assert_save_filename_check(self, tmp_path: Path, src_img, save_func) -> None:
 | 
			
		||||
    def assert_save_filename_check(
 | 
			
		||||
        self,
 | 
			
		||||
        tmp_path: Path,
 | 
			
		||||
        src_img: Image.Image,
 | 
			
		||||
        save_func: Callable[[Image.Image, int, str], None],
 | 
			
		||||
    ) -> None:
 | 
			
		||||
        for filename in test_filenames:
 | 
			
		||||
            dest_file = str(tmp_path / filename)
 | 
			
		||||
            save_func(src_img, 0, dest_file)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ from .helper import on_ci
 | 
			
		|||
@pytest.mark.filterwarnings("ignore:Possibly corrupt EXIF data")
 | 
			
		||||
@pytest.mark.filterwarnings("ignore:Metadata warning")
 | 
			
		||||
@pytest.mark.filterwarnings("ignore:Truncated File Read")
 | 
			
		||||
def test_tiff_crashes(test_file):
 | 
			
		||||
def test_tiff_crashes(test_file: str) -> None:
 | 
			
		||||
    try:
 | 
			
		||||
        with Image.open(test_file) as im:
 | 
			
		||||
            im.load()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,9 +53,9 @@ def test_nonetype() -> None:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def test_ifd_rational_save(tmp_path: Path) -> None:
 | 
			
		||||
    methods = (True, False)
 | 
			
		||||
    if not features.check("libtiff"):
 | 
			
		||||
        methods = (False,)
 | 
			
		||||
    methods = [True]
 | 
			
		||||
    if features.check("libtiff"):
 | 
			
		||||
        methods.append(False)
 | 
			
		||||
 | 
			
		||||
    for libtiff in methods:
 | 
			
		||||
        TiffImagePlugin.WRITE_LIBTIFF = libtiff
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user