mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 09:26:16 +03:00
Added type hints
This commit is contained in:
parent
cdecb3da91
commit
4ce06aac3b
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from array import array
|
from array import array
|
||||||
|
from types import ModuleType
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ from PIL import Image, ImageFilter
|
||||||
|
|
||||||
from .helper import assert_image_equal
|
from .helper import assert_image_equal
|
||||||
|
|
||||||
|
numpy: ModuleType | None
|
||||||
try:
|
try:
|
||||||
import numpy
|
import numpy
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -397,6 +399,7 @@ class TestColorLut3DFilter:
|
||||||
|
|
||||||
@pytest.mark.skipif(numpy is None, reason="NumPy not installed")
|
@pytest.mark.skipif(numpy is None, reason="NumPy not installed")
|
||||||
def test_numpy_sources(self) -> None:
|
def test_numpy_sources(self) -> None:
|
||||||
|
assert numpy is not None
|
||||||
table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16)
|
table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16)
|
||||||
with pytest.raises(ValueError, match="should have either channels"):
|
with pytest.raises(ValueError, match="should have either channels"):
|
||||||
lut = ImageFilter.Color3DLUT((5, 6, 7), table)
|
lut = ImageFilter.Color3DLUT((5, 6, 7), table)
|
||||||
|
@ -430,6 +433,7 @@ class TestColorLut3DFilter:
|
||||||
|
|
||||||
@pytest.mark.skipif(numpy is None, reason="NumPy not installed")
|
@pytest.mark.skipif(numpy is None, reason="NumPy not installed")
|
||||||
def test_numpy_formats(self) -> None:
|
def test_numpy_formats(self) -> None:
|
||||||
|
assert numpy is not None
|
||||||
g = Image.linear_gradient("L")
|
g = Image.linear_gradient("L")
|
||||||
im = Image.merge(
|
im = Image.merge(
|
||||||
"RGB",
|
"RGB",
|
||||||
|
|
|
@ -187,6 +187,6 @@ class TestEnvVars:
|
||||||
{"PILLOW_BLOCKS_MAX": "wat"},
|
{"PILLOW_BLOCKS_MAX": "wat"},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_warnings(self, var) -> None:
|
def test_warnings(self, var: dict[str, str]) -> None:
|
||||||
with pytest.warns(UserWarning):
|
with pytest.warns(UserWarning):
|
||||||
Image._apply_env_variables(var)
|
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,
|
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"""
|
"""Check DXT1 and BC1 images can be opened"""
|
||||||
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
|
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
|
||||||
target = target.convert("RGBA")
|
target = target.convert("RGBA")
|
||||||
|
@ -96,7 +96,7 @@ def test_sanity_dxt5() -> None:
|
||||||
TEST_FILE_BC4U,
|
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"""
|
"""Check ATI1 and BC4U images can be opened"""
|
||||||
|
|
||||||
with Image.open(image_path) as im:
|
with Image.open(image_path) as im:
|
||||||
|
@ -117,7 +117,7 @@ def test_sanity_ati1_bc4u(image_path) -> None:
|
||||||
TEST_FILE_DX10_BC4_TYPELESS,
|
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"""
|
"""Check DX10 BC4 images can be opened"""
|
||||||
|
|
||||||
with Image.open(image_path) as im:
|
with Image.open(image_path) as im:
|
||||||
|
@ -138,7 +138,7 @@ def test_dx10_bc4(image_path) -> None:
|
||||||
TEST_FILE_BC5U,
|
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"""
|
"""Check ATI2 and BC5U images can be opened"""
|
||||||
|
|
||||||
with Image.open(image_path) as im:
|
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),
|
(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"""
|
"""Check DX10 BC5 images can be opened"""
|
||||||
|
|
||||||
with Image.open(image_path) as im:
|
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))
|
@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"""
|
"""Check DX10 BC6H/BC6HS images can be opened"""
|
||||||
|
|
||||||
with Image.open(image_path) as im:
|
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),
|
("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"""
|
"""Check uncompressed images can be opened"""
|
||||||
|
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
|
@ -359,7 +359,7 @@ def test_unsupported_bitcount() -> None:
|
||||||
"Tests/images/unimplemented_pfflags.dds",
|
"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 pytest.raises(NotImplementedError):
|
||||||
with Image.open(test_file):
|
with Image.open(test_file):
|
||||||
pass
|
pass
|
||||||
|
@ -381,7 +381,7 @@ def test_save_unsupported_mode(tmp_path: Path) -> None:
|
||||||
("RGBA", "Tests/images/pil123rgba.png"),
|
("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")
|
out = str(tmp_path / "temp.dds")
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
assert im.mode == mode
|
assert im.mode == mode
|
||||||
|
|
|
@ -147,7 +147,7 @@ def test_seek() -> None:
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.timeout(timeout=3)
|
@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 open(test_file, "rb") as f:
|
||||||
with Image.open(f) as im:
|
with Image.open(f) as im:
|
||||||
with pytest.raises(OSError):
|
with pytest.raises(OSError):
|
||||||
|
@ -160,7 +160,7 @@ def test_timeouts(test_file) -> None:
|
||||||
"Tests/images/crash-5762152299364352.fli",
|
"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 open(test_file, "rb") as f:
|
||||||
with Image.open(f) as im:
|
with Image.open(f) as im:
|
||||||
with pytest.raises(OSError):
|
with pytest.raises(OSError):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -55,15 +56,15 @@ def test_handler(tmp_path: Path) -> None:
|
||||||
loaded = False
|
loaded = False
|
||||||
saved = False
|
saved = False
|
||||||
|
|
||||||
def open(self, im) -> None:
|
def open(self, im: Image.Image) -> None:
|
||||||
self.opened = True
|
self.opened = True
|
||||||
|
|
||||||
def load(self, im):
|
def load(self, im: Image.Image) -> Image.Image:
|
||||||
self.loaded = True
|
self.loaded = True
|
||||||
im.fp.close()
|
im.fp.close()
|
||||||
return Image.new("RGB", (1, 1))
|
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
|
self.saved = True
|
||||||
|
|
||||||
handler = TestHandler()
|
handler = TestHandler()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -56,15 +57,15 @@ def test_handler(tmp_path: Path) -> None:
|
||||||
loaded = False
|
loaded = False
|
||||||
saved = False
|
saved = False
|
||||||
|
|
||||||
def open(self, im) -> None:
|
def open(self, im: Image.Image) -> None:
|
||||||
self.opened = True
|
self.opened = True
|
||||||
|
|
||||||
def load(self, im):
|
def load(self, im: Image.Image) -> Image.Image:
|
||||||
self.loaded = True
|
self.loaded = True
|
||||||
im.fp.close()
|
im.fp.close()
|
||||||
return Image.new("RGB", (1, 1))
|
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
|
self.saved = True
|
||||||
|
|
||||||
handler = TestHandler()
|
handler = TestHandler()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import re
|
||||||
import warnings
|
import warnings
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from types import ModuleType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -33,6 +34,7 @@ from .helper import (
|
||||||
skip_unless_feature,
|
skip_unless_feature,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ElementTree: ModuleType | None
|
||||||
try:
|
try:
|
||||||
from defusedxml import ElementTree
|
from defusedxml import ElementTree
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -440,25 +442,25 @@ class TestFileJpeg:
|
||||||
for subsampling in (-1, 3): # (default, invalid)
|
for subsampling in (-1, 3): # (default, invalid)
|
||||||
im = self.roundtrip(hopper(), subsampling=subsampling)
|
im = self.roundtrip(hopper(), subsampling=subsampling)
|
||||||
assert getsampling(im) == (2, 2, 1, 1, 1, 1)
|
assert getsampling(im) == (2, 2, 1, 1, 1, 1)
|
||||||
for subsampling in (0, "4:4:4"):
|
for subsampling1 in (0, "4:4:4"):
|
||||||
im = self.roundtrip(hopper(), subsampling=subsampling)
|
im = self.roundtrip(hopper(), subsampling=subsampling1)
|
||||||
assert getsampling(im) == (1, 1, 1, 1, 1, 1)
|
assert getsampling(im) == (1, 1, 1, 1, 1, 1)
|
||||||
for subsampling in (1, "4:2:2"):
|
for subsampling1 in (1, "4:2:2"):
|
||||||
im = self.roundtrip(hopper(), subsampling=subsampling)
|
im = self.roundtrip(hopper(), subsampling=subsampling1)
|
||||||
assert getsampling(im) == (2, 1, 1, 1, 1, 1)
|
assert getsampling(im) == (2, 1, 1, 1, 1, 1)
|
||||||
for subsampling in (2, "4:2:0", "4:1:1"):
|
for subsampling1 in (2, "4:2:0", "4:1:1"):
|
||||||
im = self.roundtrip(hopper(), subsampling=subsampling)
|
im = self.roundtrip(hopper(), subsampling=subsampling1)
|
||||||
assert getsampling(im) == (2, 2, 1, 1, 1, 1)
|
assert getsampling(im) == (2, 2, 1, 1, 1, 1)
|
||||||
|
|
||||||
# RGB colorspace
|
# 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
|
# "4:4:4" doesn't really make sense for RGB, but the conversion
|
||||||
# to an integer happens at a higher level
|
# 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)
|
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):
|
with pytest.raises(OSError):
|
||||||
self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling)
|
self.roundtrip(hopper(), keep_rgb=True, subsampling=subsampling1)
|
||||||
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
self.roundtrip(hopper(), subsampling="1:1:1")
|
self.roundtrip(hopper(), subsampling="1:1:1")
|
||||||
|
|
|
@ -11,7 +11,7 @@ from PIL import Image
|
||||||
from .helper import assert_image_equal, hopper, magick_command
|
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
|
# Arrange
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
outfile = str(tmp_path / ("temp_" + mode + ".palm"))
|
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
|
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")
|
outfile = str(tmp_path / "temp.png")
|
||||||
rc = subprocess.call(
|
rc = subprocess.call(
|
||||||
magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
|
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)
|
return Image.open(outfile)
|
||||||
|
|
||||||
|
|
||||||
def roundtrip(tmp_path: Path, mode) -> None:
|
def roundtrip(tmp_path: Path, mode: str) -> None:
|
||||||
magick = magick_command()
|
magick = magick_command()
|
||||||
if not magick:
|
if not magick:
|
||||||
return
|
return
|
||||||
|
@ -66,6 +66,6 @@ def test_p_mode(tmp_path: Path) -> None:
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("mode", ("L", "RGB"))
|
@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):
|
with pytest.raises(OSError):
|
||||||
helper_save_as_palm(tmp_path, mode)
|
helper_save_as_palm(tmp_path, mode)
|
||||||
|
|
|
@ -19,7 +19,7 @@ TEST_TAR_FILE = "Tests/images/hopper.tar"
|
||||||
("jpg", "hopper.jpg", "JPEG"),
|
("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):
|
if features.check(codec):
|
||||||
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
|
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
|
||||||
with Image.open(tar) as im:
|
with Image.open(tar) as im:
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from types import ModuleType
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ pytestmark = [
|
||||||
skip_unless_feature("webp_mux"),
|
skip_unless_feature("webp_mux"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
ElementTree: ModuleType | None
|
||||||
try:
|
try:
|
||||||
from defusedxml import ElementTree
|
from defusedxml import ElementTree
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
|
@ -8,6 +8,7 @@ import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -61,11 +62,11 @@ class TestImage:
|
||||||
"HSV",
|
"HSV",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_image_modes_success(self, mode) -> None:
|
def test_image_modes_success(self, mode: str) -> None:
|
||||||
Image.new(mode, (1, 1))
|
Image.new(mode, (1, 1))
|
||||||
|
|
||||||
@pytest.mark.parametrize("mode", ("", "bad", "very very long"))
|
@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:
|
with pytest.raises(ValueError) as e:
|
||||||
Image.new(mode, (1, 1))
|
Image.new(mode, (1, 1))
|
||||||
assert str(e.value) == "unrecognized image mode"
|
assert str(e.value) == "unrecognized image mode"
|
||||||
|
@ -100,7 +101,7 @@ class TestImage:
|
||||||
|
|
||||||
def test_repr_pretty(self) -> None:
|
def test_repr_pretty(self) -> None:
|
||||||
class Pretty:
|
class Pretty:
|
||||||
def text(self, text) -> None:
|
def text(self, text: str) -> None:
|
||||||
self.pretty_output = text
|
self.pretty_output = text
|
||||||
|
|
||||||
im = Image.new("L", (100, 100))
|
im = Image.new("L", (100, 100))
|
||||||
|
@ -184,7 +185,9 @@ class TestImage:
|
||||||
temp_file = str(tmp_path / "temp.jpg")
|
temp_file = str(tmp_path / "temp.jpg")
|
||||||
|
|
||||||
class FP:
|
class FP:
|
||||||
def write(self, b) -> None:
|
name: str
|
||||||
|
|
||||||
|
def write(self, b: bytes) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
fp = FP()
|
fp = FP()
|
||||||
|
@ -538,7 +541,7 @@ class TestImage:
|
||||||
"PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower"
|
"PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower"
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize("size", ((0, 100000000), (100000000, 0)))
|
@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)
|
Image.new("RGB", size)
|
||||||
|
|
||||||
def test_storage_neg(self) -> None:
|
def test_storage_neg(self) -> None:
|
||||||
|
@ -565,7 +568,7 @@ class TestImage:
|
||||||
Image.linear_gradient(wrong_mode)
|
Image.linear_gradient(wrong_mode)
|
||||||
|
|
||||||
@pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
|
@pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
|
||||||
def test_linear_gradient(self, mode) -> None:
|
def test_linear_gradient(self, mode: str) -> None:
|
||||||
# Arrange
|
# Arrange
|
||||||
target_file = "Tests/images/linear_gradient.png"
|
target_file = "Tests/images/linear_gradient.png"
|
||||||
|
|
||||||
|
@ -590,7 +593,7 @@ class TestImage:
|
||||||
Image.radial_gradient(wrong_mode)
|
Image.radial_gradient(wrong_mode)
|
||||||
|
|
||||||
@pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
|
@pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
|
||||||
def test_radial_gradient(self, mode) -> None:
|
def test_radial_gradient(self, mode: str) -> None:
|
||||||
# Arrange
|
# Arrange
|
||||||
target_file = "Tests/images/radial_gradient.png"
|
target_file = "Tests/images/radial_gradient.png"
|
||||||
|
|
||||||
|
@ -665,7 +668,11 @@ class TestImage:
|
||||||
blank_p.palette = None
|
blank_p.palette = None
|
||||||
blank_pa.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)
|
new_image = base_image._new(image.im)
|
||||||
assert new_image.mode == image.mode
|
assert new_image.mode == image.mode
|
||||||
assert new_image.size == image.size
|
assert new_image.size == image.size
|
||||||
|
@ -713,7 +720,7 @@ class TestImage:
|
||||||
def test_load_on_nonexclusive_multiframe(self) -> None:
|
def test_load_on_nonexclusive_multiframe(self) -> None:
|
||||||
with open("Tests/images/frozenpond.mpo", "rb") as fp:
|
with open("Tests/images/frozenpond.mpo", "rb") as fp:
|
||||||
|
|
||||||
def act(fp) -> None:
|
def act(fp: IO[bytes]) -> None:
|
||||||
im = Image.open(fp)
|
im = Image.open(fp)
|
||||||
im.load()
|
im.load()
|
||||||
|
|
||||||
|
@ -906,12 +913,12 @@ class TestImage:
|
||||||
assert exif.get_ifd(0xA005)
|
assert exif.get_ifd(0xA005)
|
||||||
|
|
||||||
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
|
@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)
|
im = Image.new("RGB", size)
|
||||||
assert im.tobytes() == b""
|
assert im.tobytes() == b""
|
||||||
|
|
||||||
@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
|
@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"")
|
Image.frombytes("RGB", size, b"")
|
||||||
|
|
||||||
im = Image.new("RGB", size)
|
im = Image.new("RGB", size)
|
||||||
|
@ -996,7 +1003,7 @@ class TestImage:
|
||||||
"01r_00.pcx",
|
"01r_00.pcx",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_overrun(self, path) -> None:
|
def test_overrun(self, path: str) -> None:
|
||||||
"""For overrun completeness, test as:
|
"""For overrun completeness, test as:
|
||||||
valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c
|
valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c
|
||||||
"""
|
"""
|
||||||
|
@ -1023,7 +1030,7 @@ class TestImage:
|
||||||
pass
|
pass
|
||||||
assert not hasattr(im, "fp")
|
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:
|
with Image.open("Tests/images/hopper.jpg") as im:
|
||||||
copy = im.copy()
|
copy = im.copy()
|
||||||
with caplog.at_level(logging.DEBUG):
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
@ -1034,10 +1041,10 @@ class TestImage:
|
||||||
|
|
||||||
|
|
||||||
class MockEncoder:
|
class MockEncoder:
|
||||||
pass
|
args: tuple[str, ...]
|
||||||
|
|
||||||
|
|
||||||
def mock_encode(*args):
|
def mock_encode(*args: str) -> MockEncoder:
|
||||||
encoder = MockEncoder()
|
encoder = MockEncoder()
|
||||||
encoder.args = args
|
encoder.args = args
|
||||||
return encoder
|
return encoder
|
||||||
|
|
|
@ -208,7 +208,9 @@ def test_language() -> None:
|
||||||
),
|
),
|
||||||
ids=("None", "ltr", "rtl2", "rtl", "ttb"),
|
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)
|
ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
im = Image.new(mode, (1, 1), 0)
|
im = Image.new(mode, (1, 1), 0)
|
||||||
d = ImageDraw.Draw(im)
|
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"),
|
("i" + ("\u030C" * 15) + "i", "i" + "\u032C" * 15 + "i", "\u035Cii", "i\u0305i"),
|
||||||
ids=("caron-above", "caron-below", "double-breve", "overline"),
|
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":
|
if text == "i\u0305i" and direction == "ttb":
|
||||||
pytest.skip("fails with this font")
|
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"))
|
@pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm"))
|
||||||
def test_anchor_ttb(anchor) -> None:
|
def test_anchor_ttb(anchor: str) -> None:
|
||||||
text = "f"
|
text = "f"
|
||||||
path = f"Tests/images/test_anchor_ttb_{text}_{anchor}.png"
|
path = f"Tests/images/test_anchor_ttb_{text}_{anchor}.png"
|
||||||
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120)
|
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120)
|
||||||
|
@ -306,7 +308,9 @@ combine_tests = (
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"name, text, anchor, dir, epsilon", combine_tests, ids=[r[0] for r in combine_tests]
|
"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"
|
path = f"Tests/images/test_combine_{name}.png"
|
||||||
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 48)
|
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
|
("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
|
# test that multiline text uses getlength, not getsize or getbbox
|
||||||
|
|
||||||
path = f"Tests/images/test_combine_multiline_{anchor}_{align}.png"
|
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
|
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"""
|
"""Turn a string image representation into a binary image"""
|
||||||
rows = [s for s in image_string.replace(" ", "").split("\n") if len(s)]
|
rows = [s for s in image_string.replace(" ", "").split("\n") if len(s)]
|
||||||
height = len(rows)
|
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"""
|
"""Turn a (small) binary image into a string representation"""
|
||||||
chars = ".1"
|
chars = ".1"
|
||||||
width, height = im.size
|
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))
|
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)
|
assert img_to_string(a) == img_string_normalize(b_string)
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ def test_str_to_img() -> None:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"op", ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge")
|
"op", ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge")
|
||||||
)
|
)
|
||||||
def test_lut(op) -> None:
|
def test_lut(op: str) -> None:
|
||||||
lb = ImageMorph.LutBuilder(op_name=op)
|
lb = ImageMorph.LutBuilder(op_name=op)
|
||||||
assert lb.get_lut() is None
|
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)),
|
(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))
|
im = Image.new("P", (1, 1))
|
||||||
|
|
||||||
# Do not use transparency index as a new color
|
# Do not use transparency index as a new color
|
||||||
|
|
|
@ -13,7 +13,9 @@ FONT_SIZE = 20
|
||||||
FONT_PATH = "Tests/fonts/DejaVuSans/DejaVuSans.ttf"
|
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
|
# Arrange
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
filename = str(tmp_path / "temp.pkl")
|
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
|
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:
|
with Image.open(test_file) as im:
|
||||||
if mode:
|
if mode:
|
||||||
im = im.convert(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))
|
@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
|
# Act / Assert
|
||||||
helper_pickle_string(pickle, protocol, test_file, test_mode)
|
helper_pickle_string(protocol, test_file, test_mode)
|
||||||
helper_pickle_file(tmp_path, pickle, 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:
|
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
|
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
|
# Arrange
|
||||||
im1 = Image.new(mode="RGBA", size=(300, 100))
|
im1 = Image.new(mode="RGBA", size=(300, 100))
|
||||||
im2 = 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")
|
@skip_unless_feature("freetype2")
|
||||||
@pytest.mark.parametrize("protocol", list(range(0, pickle.HIGHEST_PROTOCOL + 1)))
|
@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
|
# Arrange
|
||||||
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
|
|
||||||
|
@ -131,7 +137,7 @@ def test_pickle_font_string(protocol) -> None:
|
||||||
|
|
||||||
@skip_unless_feature("freetype2")
|
@skip_unless_feature("freetype2")
|
||||||
@pytest.mark.parametrize("protocol", list(range(0, pickle.HIGHEST_PROTOCOL + 1)))
|
@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
|
# Arrange
|
||||||
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||||||
filename = str(tmp_path / "temp.pkl")
|
filename = str(tmp_path / "temp.pkl")
|
||||||
|
|
|
@ -10,7 +10,7 @@ import pytest
|
||||||
from PIL import Image, PSDraw
|
from PIL import Image, PSDraw
|
||||||
|
|
||||||
|
|
||||||
def _create_document(ps) -> None:
|
def _create_document(ps: PSDraw.PSDraw) -> None:
|
||||||
title = "hopper"
|
title = "hopper"
|
||||||
box = (1 * 72, 2 * 72, 7 * 72, 10 * 72) # in points
|
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))
|
@pytest.mark.parametrize("buffer", (True, False))
|
||||||
def test_stdout(buffer) -> None:
|
def test_stdout(buffer: bool) -> None:
|
||||||
# Temporarily redirect stdout
|
# Temporarily redirect stdout
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ from PIL import Image
|
||||||
"Tests/images/crash-db8bfa78b19721225425530c5946217720d7df4e.sgi",
|
"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 open(test_file, "rb") as f:
|
||||||
with Image.open(f) as im:
|
with Image.open(f) as im:
|
||||||
with pytest.raises(OSError):
|
with pytest.raises(OSError):
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -17,7 +18,12 @@ test_filenames = ("temp_';", 'temp_";', "temp_'\"|", "temp_'\"||", "temp_'\"&&")
|
||||||
|
|
||||||
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
|
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
|
||||||
class TestShellInjection:
|
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:
|
for filename in test_filenames:
|
||||||
dest_file = str(tmp_path / filename)
|
dest_file = str(tmp_path / filename)
|
||||||
save_func(src_img, 0, dest_file)
|
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:Possibly corrupt EXIF data")
|
||||||
@pytest.mark.filterwarnings("ignore:Metadata warning")
|
@pytest.mark.filterwarnings("ignore:Metadata warning")
|
||||||
@pytest.mark.filterwarnings("ignore:Truncated File Read")
|
@pytest.mark.filterwarnings("ignore:Truncated File Read")
|
||||||
def test_tiff_crashes(test_file):
|
def test_tiff_crashes(test_file: str) -> None:
|
||||||
try:
|
try:
|
||||||
with Image.open(test_file) as im:
|
with Image.open(test_file) as im:
|
||||||
im.load()
|
im.load()
|
||||||
|
|
|
@ -53,9 +53,9 @@ def test_nonetype() -> None:
|
||||||
|
|
||||||
|
|
||||||
def test_ifd_rational_save(tmp_path: Path) -> None:
|
def test_ifd_rational_save(tmp_path: Path) -> None:
|
||||||
methods = (True, False)
|
methods = [True]
|
||||||
if not features.check("libtiff"):
|
if features.check("libtiff"):
|
||||||
methods = (False,)
|
methods.append(False)
|
||||||
|
|
||||||
for libtiff in methods:
|
for libtiff in methods:
|
||||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||||
|
|
Loading…
Reference in New Issue
Block a user